0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

goaでPayloadの文字列がログに出ないようにする

Posted at

iOS/Androidアプリで使うAPIをgoaで作っていて、Payloadの中身をログに出したくない、という案件が出てきたので色々調べた。

参考になった情報

作ったやつ

やったこと

参考URLの2つを組み合わせた。

  1. stringのエイリアスSecretStringを定義する
  2. fmt.Stringer, fmt.GoStringerインターフェースを実装する
  3. json.Marshalerインターフェースを実装する
  4. stringに戻すための関数を定義する

※最後のやつは必須ではない。単にstring(foo)で戻せるが、「生の文字列を使っているのがどこか?」を簡単に把握できるようにするためには必要かなと。

最小限のコードは以下の通り。

type SecretString string

func (ss SecretString) String() string {
	return "[FILTERED]"
}

func (ss SecretString) GoString() string {
	return ss.String()
}

func (ss SecretString) MarshalJSON() ([]byte, error) {
	return json.Marshal(ss.String())
}

func (ss SecretString) RawString() string {
	return string(ss)
}

GitHubに置いたコードは、もう少し色気を出して色々書いている。
secret_string.go

使い方

基本的には、stringで定義するところをsecretstr.SecretStringに置き換えるだけで使える。READMEのサンプルコードを参照。
これにより、
fmt.Println(パスワードをメンバに含む構造体)
のようなデバッグコードが仮に残っていたとしても、ログに生のパスワードが出力されることはなくなる。

ただ、goagenで自動生成されるコードについては一工夫必要。

goagenで自動生成されるPayloadでの使い方

例えば以下のようにリクエストを投げた場合。

curl -X POST http://localhost:8080/auth/login -d '{"id":"raw_id","password":"raw_password"}' -H "Content-Type: application/json"

Before

通常の定義だと、型はただのstringなので、当然ログにID/PWが出る。

design/design.go
Payload(func() {
	Param("id", String, "Login ID")
	Param("password", String, "Login password")
})
2019/05/05 21:30:13 [INFO] started req_id=tBkbeBBZ60-1 POST=/auth/login from=::1 ctrl=LoginController action=login
2019/05/05 21:30:13 [INFO] headers req_id=tBkbeBBZ60-1 Accept=*/* Content-Length=41 Content-Type=application/json User-Agent=curl/7.54.0
2019/05/05 21:30:13 [INFO] payload req_id=tBkbeBBZ60-1 raw={"id":"raw_id","password":"raw_password"}
2019/05/05 21:30:13 [INFO] completed req_id=tBkbeBBZ60-1 status=0 bytes=0 time=143.578µs ctrl=LoginController action=login

After

ドキュメントを眺めてみると、Metadataを定義すれば型を変更できるとのこと。
https://godoc.org/github.com/goadesign/goa/design/apidsl#Metadata

design/design.go
Payload(func() {
	Param("id", func() {
		Description("Login ID")
		Metadata("struct:field:type", "secretstr.SecretString", "github.com/75py/secretstr")
	})
	Param("password", func() {
		Description("Login password")
		Metadata("struct:field:type", "secretstr.SecretString", "github.com/75py/secretstr")
	})
})
app/contexts.go(自動生成)
// LoginLoginPayload is the login login action payload.
type LoginLoginPayload struct {
	// Login ID
	ID *secretstr.SecretString `form:"id,omitempty" json:"id,omitempty" yaml:"id,omitempty" xml:"id,omitempty"`
	// Login password
	Password *secretstr.SecretString `form:"password,omitempty" json:"password,omitempty" yaml:"password,omitempty" xml:"password,omitempty"`
}

ログは以下のようになる。

2019/05/05 21:31:15 [INFO] started req_id=tBkbeBBZ60-2 POST=/auth/login/secretstr from=::1 ctrl=LoginController action=login_secretstr
2019/05/05 21:31:15 [INFO] headers req_id=tBkbeBBZ60-2 Accept=*/* Content-Length=41 Content-Type=application/json User-Agent=curl/7.54.0
2019/05/05 21:31:15 [INFO] payload req_id=tBkbeBBZ60-2 raw={"id":"[FILTERED]","password":"[FILTERED]"}
2019/05/05 21:31:15 [INFO] completed req_id=tBkbeBBZ60-2 status=0 bytes=0 time=80.848µs ctrl=LoginController action=login_secretstr

少し困っているところ

この方法だと、MaxLengthなどのバリデーションが使えなくなる。

app/contexts.go(自動生成)
	if utf8.RuneCountInString(payload.ID) > 5 { // cannot use *payload.ID (type secretstr.SecretString) as type string in argument to utf8.RuneCountInString
		err = goa.MergeErrors(err, goa.InvalidLengthError(`raw.id`, payload.ID, utf8.RuneCountInString(payload.ID), 5, false))
	}

このくらいなら自分で実装すれば良いので大した手間ではないけど、もっと良い方法があればぜひ教えてください。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?