GoでパスワードなどをPrintfで出力させたくない
RailsのLoggerだとリクエストパラメータにパスワードなどが含まれていると、FILTERED
といった感じで生の情報が出力されない。
Goでも、例えば、以下のような構造体Userを fmt.Printf("%#v", u)
で出力したときに Password
が隠れて欲しい。
type User struct { Name string Password string }
ノーガード
特に何もしないと、そのまま出力される。
type User struct { Name string Password string } func main() { u := &User{ Name: "namae", Password: "pass", } fmt.Printf("%+v", u) // &{Name:namae Password:pass} }
https://play.golang.org/p/HZuuaXwS4O
そりゃそうだ。
Password を Stringer にしてみる
fmtで出力されるとき、StringerだとStringが呼ばれるはず。
type Password string func (p Password) String() string { return "FILTERED" } type User struct { Name string Password Password } func main() { u := &User{ Name: "namae", Password: Password("pass"), } fmt.Printf("%+v", u) // &{Name:namae Password:FILTERED} }
https://play.golang.org/p/hmNsB0yrbk
お、できた!?
"%#v" には勝てない
%+v だと出力されないんだけど、%#vだと出力されてしまう…
type Password string func (p Password) String() string { return "FILTERED" } type User struct { Name string Password Password } func main() { u := &User{ Name: "namae", Password: Password("pass"), } fmt.Printf("%#v", u) // &main.User{Name:"namae", Password:"pass"} }
https://play.golang.org/p/1BT9E4dM17
ポインタ型にしてみる
ポインタ型にしたらどうだろう。
type Password string func (p Password) String() string { return "FILTERED" } type User struct { Name string Password *Password } func main() { p := Password("pass") u := &User{ Name: "namae", Password: &p, } fmt.Printf("%#v", u) // &main.User{Name:"namae", Password:(*main.Password)(0x1040a120)} }
https://play.golang.org/p/_pcSzrx64p
アドレスが出力されるので、とりあえずパスワードはわからない状態になった。
まとめ
- とりあえずStringerにする
- 構造体のフィールドとしてはポインタ型にしておく
で良いんだろうか?
もっと良い方法ないだろうか。