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

ipfans's Blog · · 2230 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

今天正好看到一篇关于敏感信息过滤的文章,这算做一个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接口类型的影响,请根据使用情况酌情使用。


有疑问加站长微信联系(非本文作者)

本文来自:ipfans's Blog

感谢作者:ipfans's Blog

查看原文:关于Golang过滤敏感信息的正确姿势

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

2230 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传