Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/site/content/zh/latest/tasks/mock.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,11 @@ items:
proxies:
- path: /api/v1/{part}
target: http://atest.localhost:8080
echo: true
```

当 echo 的值为 true 时,会把收到的请求以及响应打印出来,方便观察数据。

当我们发起如下的请求时,实际请求的地址为 `http://atest.localhost:8080/api/v1/projects`

```shell
Expand Down
1 change: 1 addition & 0 deletions docs/site/content/zh/latest/tasks/mock/simple.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ proxies:
target: http://atest.localhost:8080
- path: /open-apis/bot/v2/hook/{token}
target: https://open.feishu.cn/
echo: true
requestAmend:
bodyPatch: |
[{
Expand Down
16 changes: 16 additions & 0 deletions pkg/mock/in_memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,16 @@
fmt.Println("after patch:", string(requestBody))
}

if proxy.Echo {
fmt.Println("Original request header:")
for k, v := range req.Header {
fmt.Println(k, ":", v)

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

Sensitive data returned by HTTP request headers
flows to a logging call.

Copilot Autofix

AI about 2 months ago

To fix the problem, we should prevent logging sensitive HTTP headers. The best practice is to either omit logging headers entirely, or to redact/obfuscate sensitive header values before logging them. When logging headers, we should maintain a denylist of sensitive header names (e.g., Authorization, Cookie, Set-Cookie, Proxy-Authorization) and mask their values if they're present.
Specifically, in pkg/mock/in_memory.go, within the loop starting at line 183, we should update the logging so that before printing each header, we check if it is sensitive; if so, print its value as <redacted>, else print its actual value. This can be done by a simple helper function that matches header names case-insensitively.
Minimal changes are needed and no functionality should be lost (other than leaking secrets). We'll define the sensitive headers list in this code region and use it for redaction.

Suggested changeset 1
pkg/mock/in_memory.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/pkg/mock/in_memory.go b/pkg/mock/in_memory.go
--- a/pkg/mock/in_memory.go
+++ b/pkg/mock/in_memory.go
@@ -181,7 +181,11 @@
 		if proxy.Echo {
 			fmt.Println("Original request header:")
 			for k, v := range req.Header {
-				fmt.Println(k, ":", v)
+				if isSensitiveHeader(k) {
+					fmt.Println(k, ":", "<redacted>")
+				} else {
+					fmt.Println(k, ":", v)
+				}
 			}
 			fmt.Println("Original request path:", req.URL)
 			fmt.Println("Original request payload:")
@@ -226,6 +230,27 @@
 	})
 }
 
+// isSensitiveHeader returns true if the HTTP header name is considered sensitive.
+func isSensitiveHeader(headerName string) bool {
+	// List of common sensitive headers
+	sensitive := []string{
+		"Authorization",
+		"Cookie",
+		"Set-Cookie",
+		"Proxy-Authorization",
+		"X-Api-Key",
+		"X-Auth-Token",
+		"X-Csrf-Token",
+	}
+	normalized := strings.ToLower(headerName)
+	for _, h := range sensitive {
+		if normalized == strings.ToLower(h) {
+			return true
+		}
+	}
+	return false
+}
+
 func (s *inMemoryServer) tcpProxy(proxy *Proxy) {
 	fmt.Println("start to proxy", proxy.Port)
 	lisener, err := net.Listen("tcp", fmt.Sprintf(":%d", proxy.Port))
EOF
@@ -181,7 +181,11 @@
if proxy.Echo {
fmt.Println("Original request header:")
for k, v := range req.Header {
fmt.Println(k, ":", v)
if isSensitiveHeader(k) {
fmt.Println(k, ":", "<redacted>")
} else {
fmt.Println(k, ":", v)
}
}
fmt.Println("Original request path:", req.URL)
fmt.Println("Original request payload:")
@@ -226,6 +230,27 @@
})
}

// isSensitiveHeader returns true if the HTTP header name is considered sensitive.
func isSensitiveHeader(headerName string) bool {
// List of common sensitive headers
sensitive := []string{
"Authorization",
"Cookie",
"Set-Cookie",
"Proxy-Authorization",
"X-Api-Key",
"X-Auth-Token",
"X-Csrf-Token",
}
normalized := strings.ToLower(headerName)
for _, h := range sensitive {
if normalized == strings.ToLower(h) {
return true
}
}
return false
}

func (s *inMemoryServer) tcpProxy(proxy *Proxy) {
fmt.Println("start to proxy", proxy.Port)
lisener, err := net.Listen("tcp", fmt.Sprintf(":%d", proxy.Port))
Copilot is powered by AI and may make mistakes. Always verify output.
}
fmt.Println("Original request path:", req.URL)
fmt.Println("Original request payload:")
fmt.Println(string(requestBody))

Check notice

Code scanning / SonarCloud

Logging should not be vulnerable to injection attacks Low

Change this code to not log user-controlled data. See more on SonarQube Cloud
}

targetReq, err := http.NewRequestWithContext(req.Context(), req.Method, api, bytes.NewBuffer(requestBody))
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
Expand Down Expand Up @@ -206,6 +216,12 @@
for k, v := range resp.Header {
w.Header().Add(k, v[0])
}

if proxy.Echo {
fmt.Println("Original response payload:")
fmt.Println(string(data))
}

w.Write(data)
})
}
Expand Down
75 changes: 38 additions & 37 deletions pkg/mock/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,65 +16,66 @@ limitations under the License.
package mock

type Object struct {
Name string `yaml:"name" json:"name"`
InitCount *int `yaml:"initCount" json:"initCount"`
Sample string `yaml:"sample" json:"sample"`
Name string `yaml:"name" json:"name"`
InitCount *int `yaml:"initCount" json:"initCount"`
Sample string `yaml:"sample" json:"sample"`
}

type Item struct {
Name string `yaml:"name" json:"name"`
Request Request `yaml:"request" json:"request"`
Response Response `yaml:"response" json:"response"`
Param map[string]interface{}
Name string `yaml:"name" json:"name"`
Request Request `yaml:"request" json:"request"`
Response Response `yaml:"response" json:"response"`
Param map[string]interface{}
}

type Request struct {
Protocol string `yaml:"protocol" json:"protocol"`
Path string `yaml:"path" json:"path"`
Method string `yaml:"method" json:"method"`
Header map[string]string `yaml:"header" json:"header"`
Body string `yaml:"body" json:"body"`
Protocol string `yaml:"protocol" json:"protocol"`
Path string `yaml:"path" json:"path"`
Method string `yaml:"method" json:"method"`
Header map[string]string `yaml:"header" json:"header"`
Body string `yaml:"body" json:"body"`
}

type RequestWithAuth struct {
Request `yaml:",inline"`
BearerAPI string `yaml:"bearerAPI" json:"bearerAPI"`
Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
Request `yaml:",inline"`
BearerAPI string `yaml:"bearerAPI" json:"bearerAPI"`
Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
}

type Response struct {
Encoder string `yaml:"encoder" json:"encoder"`
Body string `yaml:"body" json:"body"`
BodyFromFile string `yaml:"bodyFromFile" json:"bodyFromFile"`
Header map[string]string `yaml:"header" json:"header"`
StatusCode int `yaml:"statusCode" json:"statusCode"`
BodyData []byte
Encoder string `yaml:"encoder" json:"encoder"`
Body string `yaml:"body" json:"body"`
BodyFromFile string `yaml:"bodyFromFile" json:"bodyFromFile"`
Header map[string]string `yaml:"header" json:"header"`
StatusCode int `yaml:"statusCode" json:"statusCode"`
BodyData []byte
}

type Webhook struct {
Name string `yaml:"name" json:"name"`
Timer string `yaml:"timer" json:"timer"`
Param map[string]string `yaml:"param" json:"param"`
Request RequestWithAuth `yaml:"request" json:"request"`
Name string `yaml:"name" json:"name"`
Timer string `yaml:"timer" json:"timer"`
Param map[string]string `yaml:"param" json:"param"`
Request RequestWithAuth `yaml:"request" json:"request"`
}

type Proxy struct {
Prefix string `yaml:"prefix" json:"prefix"`
Port int `yaml:"port" json:"port"`
Path string `yaml:"path" json:"path"`
Target string `yaml:"target" json:"target"`
RequestAmend RequestAmend `yaml:"requestAmend" json:"requestAmend"`
Protocol string `yaml:"protocol" json:"protocol"`
Prefix string `yaml:"prefix" json:"prefix"`
Port int `yaml:"port" json:"port"`
Path string `yaml:"path" json:"path"`
Target string `yaml:"target" json:"target"`
RequestAmend RequestAmend `yaml:"requestAmend" json:"requestAmend"`
Protocol string `yaml:"protocol" json:"protocol"`
Echo bool `yaml:"echo" json:"echo"`
}

type RequestAmend struct {
BodyPatch string `yaml:"bodyPatch" json:"bodyPatch"`
BodyPatch string `yaml:"bodyPatch" json:"bodyPatch"`
}

type Server struct {
Objects []Object `yaml:"objects" json:"objects"`
Items []Item `yaml:"items" json:"items"`
Proxies []Proxy `yaml:"proxies" json:"proxies"`
Webhooks []Webhook `yaml:"webhooks" json:"webhooks"`
Objects []Object `yaml:"objects" json:"objects"`
Items []Item `yaml:"items" json:"items"`
Proxies []Proxy `yaml:"proxies" json:"proxies"`
Webhooks []Webhook `yaml:"webhooks" json:"webhooks"`
}
Loading