バックエンドエンジニアの @y0n3yama です。
Golang において、Base64 エンコード した文字列を Cookie で扱う際に迷った点と調査してわかったことについて書いていきます。
ある API リクエスト処理の中で、
ということをしようとしていました。 RFC6265 では、 Cookie に保存する値はBase64 エンコードするべきとされています。
To maximize compatibility with user agents, servers that wish to store arbitrary data in a cookie-value SHOULD encode that data, for example, using Base64 [RFC4648].
Golangではビルトインの encoding/base64
パッケージを利用してエンコード/デコードをすることになります。
エンコード
func (enc *Encoding) EncodeToString(src []byte) string
デコード
func (enc *Encoding) DecodeString(s string) ([]byte, error)
なお、エンコードの方式は4つ用意されています。
この4つのうちどれを利用するか迷いました。調べた結果と見解について述べていきます。
Cookieで扱うという観点から4つの選択肢から選ぶにあたって、考えるべきは以下2つの軸になります。 ① 通常の Base64 エンコード or URLセーフな Base64 エンコード ② パディングあり or なし
それぞれの軸について考える前に、前提としての Set-Cookie
の仕様について確認しておきます。
cookie-name は任意の US-ASCII 文字の集合で、制御文字、空白、タブを除いたものです。( ) < > @ , ; : \ “ / [ ] ? = { } のような区切り文字も含めることができません。 cookie-value は任意で二重引用符で囲むことができ、制御文字、ホワイトスペース、二重引用符、カンマ、セミコロン、バックスラッシュを除くすべての US-ASCII 文字が利用できます。 Set-Cookie
上記の仕様を踏まえると、
①については、特にURLエンコードする必要性はないため、通常のbase64エンコーディングので問題なし。
②については、Cookieにおけるパディング記号 =
の性質を意識しておきたいところです。
これは個人的に勘違いしていたのですが、 valueであれば =
を許容されているので、パディングありで問題はない です。
また、パディングの必要性については以下のようにデコード時の曖昧さを省くためであるため、あるにこしたことはなさそうです。
In some circumstances, the use of padding ("=") in base-encoded data is not required or used. In the general case, when assumptions about the size of transported data cannot be made, padding is required to yield correct decoded data.
ということで、StdEncoding
を利用する判断をしました。
参考までにソースコードを共有しておきます。
sampleStr := []byte("てすと.")
encodedStr := base64.StdEncoding.EncodeToString(sampleStr)
fmt.Printf("encodeされた文字列: %s", encodedStr) // 44Gm44GZ44GoLg==
fmt.Println()
// Cookieにセット(省略)
// Cookieから取得(省略)
decodedStr, err := base64.StdEncoding.DecodeString(encodedStr)
if err != nil {
// エラーハンドリング
panic(err)
}
fmt.Printf("decodeされた文字列: %s", decodedStr) // てすと.
おそらく他の方式でも動作自体はしそう(?)な結果となりましたが、 意図しない結果を招かないためにも、複数の選択肢が存在する中でもある程度の根拠を持った選択をしていくのはこれからも意識していきたい次第です。 少しでも参考になりましたら幸いです。 積極採用中!