有条件地打印包含敏感数据的调试信息

huangapple go评论79阅读模式
英文:

Conditionally print debug info containing sensitive data

问题

我正在运行一个作为k8s作业的Go程序。

该应用程序向elasticsearch集群发送API请求以创建用户,因此它将包含敏感数据(用户的密码)。

    requestDump, err := httputil.DumpRequest(req, true)
    responseDump, err := httputil.DumpResponse(resp, true)
	esapiClient.log.Printf("在创建用户时收到响应代码 %d:%s\n", resp.StatusCode, user.Username)
	if resp.StatusCode != http.StatusOK {
		esapiClient.log.Printf("错误:在创建用户%s时收到响应代码:%d\n", user.Username, resp.StatusCode)
		esapiClient.log.Println("请求\n", string(requestDump))
		esapiClient.log.Println("响应\n", string(responseDump))
		return ErrResponseCode
	}

当事情出错时,我希望能够转储请求和响应(尤其是在400情况下),以检查出错的原因(主要是潜在的格式错误的请求)。

有没有推荐的方法来实现这一点?日志级别是唯一的解决方法吗?

英文:

I am running a Go program as a k8s job.

The application sends an API request to an elasticsearch cluster to create users, therefore it will contain sensitive data (user's password).

    requestDump, err := httputil.DumpRequest(req, true)
    responseDump, err := httputil.DumpResponse(resp, true)
	esapiClient.log.Printf("got response code %d when creating user: %s\n", resp.StatusCode, user.Username)
	if resp.StatusCode != http.StatusOK {
		esapiClient.log.Printf("error: got response code: %d when creating user %s\n", resp.StatusCode, user.Username)
		esapiClient.log.Println("Request\n", string(requestDump))
		esapiClient.log.Println("Response\n", string(responseDump))
		return ErrResponseCode
	}

When things go south, I want to be able to dump the request and the responses (especially in 400 cases) to check what went wrong (mainly with potentially malformed requests).

What is the recommended way of of doing this? Are log levels the only way around this?

答案1

得分: 3

日志级别不是一个解决方案。你的目标应该是在日志转储中完全避免包含个人身份信息(PII),包括在调试模式下启动服务时。

根据你的日志记录方式,只需在结构体上实现相关接口,并省略或隐藏包含PII的字段。对于需要在调试目的下保留一些关于原始值的线索的字段,你可以只隐藏部分信息。

例如,如果你使用fmt格式化或类似的方式记录日志,可以实现Stringer接口:

type User struct {
	Name     string
	Password string
}

func (u User) String() string {
	return fmt.Sprintf("{%s %s}", u.Name, "*****")
}


func main() {
	u := User{"pkaramol", "secret"}
	fmt.Println(u) // {pkaramol *****}
	
}

如果你以JSON格式记录日志,可以实现MarshalJSON方法进行隐藏,或使用结构体标签json:"-"进行省略:

func (u User) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]interface{}{
        "name": u.Name,
        "password": "*****",
    })
}

func main() {
	u := User{"pkaramol", "secret"}
    b, _ := json.Marshal(u)
	fmt.Println(string(b)) // {"name":"pkaramol","password":"*****"}
}
英文:

Log levels is a non-solution. Your goal should be not having PII (personally identifiable information) end up in your log dumps altogether, including when you start the service in debug mode.

Depending on how you do the logging, just implement the relevant interfaces on your structs and omit or redact fields that contain PII. In case of fields where you need to have some clue about the original value for debugging purposes, you can redact only a part of it.

For example, if you log with fmt verbs or similar, you can implement the Stringer interface:

type User struct {
	Name     string
	Password string
}

func (u User) String() string {
	return fmt.Sprintf("{%s %s}", u.Name, "*****")
}


func main() {
	u := User{"pkaramol", "secret"}
	fmt.Println(u) // {pkaramol *****}
	
}

If you log in JSON, implement MarshalJSON to redact, or use the struct tag json:"-" to omit:

func (u User) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]interface{}{
        "name": u.Name,
        "password": "*****",
    })
}

func main() {
	u := User{"pkaramol", "secret"}
    b, _ := json.Marshal()
	fmt.Println(string(b)) // {"name":"pkaramol","password":"*****"}
}

huangapple
  • 本文由 发表于 2021年9月4日 03:15:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/69049675.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定