关于Golang过滤敏感信息的正确姿势

今天正好看到一篇关于敏感信息过滤的文章,这算做一个interface实际应用的一些举例和应用。

例子中介绍了一种比较常见的使用场景:使用JSON保存数据时的对诸如用户密码等信息进行保护时候应该做的事情。作者以使用JSON格式保存用户账户和密码为例,讲解了使用json.Unmarshaler接口类型过滤敏感信息。

比如,对于保存敏感数据的结构体:

1
2
3
4
5
6
7
8
9
10
11
type Credentials struct {
Email string `json:”email”`
Password string `json:”password”`
}

func (co Credentials) MarshalJSON() ([]byte, error) {
type credentials Credentials
cn := credentials(co)
cn.Password = "[REDACTED]"
return json.Marshal((*credentials)(&cn))
}

通过定义MarshalJSON方法满足json.Unmarshaler接口类型的要求,这样,当使用json.Unmarshal等方法时,就可以规避掉在日志或者JSON接口之类的方法中输出敏感信息Password

文中提及了json.Unmarshaler接口一个方法,但这种方法并不是完全能够解决所有的类型的敏感信息过滤问题。比如在使用调试过程中,开发人员常常使用的fmt/log包,则不能用这种方法解决。

要解决这个问题,则需要使用另外一个值得注意的接口类型,那么就是fmt.Stringer接口类型。该接口类型通常用于如log/fmt之类的包的输出中。

实际上,我个人认为非常合适的方法是,我们可以特定某个特殊类型Sensitivity,对于敏感信息统一采用这个类型予以保护。这样也方便我们后续添加新的保护方式。

看一下这个敏感信息如何过滤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Sensitivity string

func (s Sensitivity) String() string {
return "[SENSITIVE DATA]"
}

...

request := CreateUserRequest{
Credentials: Credentials{
Email: "bilbro@theshire.net",
Password: "theonering",
},
}
fmt.Println("request:", request)

输出结果为:

1
request: {{bilbro@theshire.net [SENSITIVE DATA]}}

同样的,我们结合第一个方法中的json.Unmarshaler一起使用时,那么就是一个比较完整的敏感信息过滤方案了。

1
2
3
4
5
6
7
8
9
type Sensitivity string

func (s Sensitivity) String() string {
return "[SENSITIVE DATA]"
}

func (s Sensitivity) MarshalJSON() ([]byte, error) {
return []byte(`"[SENSITIVE DATA]"`), nil
}

这种方式也能很好的兼容各种数据库ORM库,保证我们的功能可以正常应用在数据模型等场景上:

1
2
3
4
5
6
7
8
9
10
11
12
sess, _ := mgo.Dial("")
sess.DB("test").C("data").Insert(&request.Credentials)
var c Credentials
sess.DB("test").C("data").Find(bson.M{}).One(&c)
fmt.Println(c.Password == "theonering")
...
db, _ := gorm.Open("mysql", "root:pwd@/ytest?charset=utf8&parseTime=True&loc=Local")
...
db.Create(&request.Credentials)
var c Credentials
db.First(&c)
fmt.Println(c.Password == "theonering")

类似的还有一个涉及编码方法encoding.TextMarshaler,基本与fmt.Stringer类似,因此也不需要额外的赘述了。

注意:如果你使用了如fmt.Sprintf之类的格式化请求,也会受到fmt.Stringer接口类型的影响,请根据使用情况酌情使用。