自分は認証にJWTをよく使っています。
そのJWTをざっくり理解したいと思い、JWTを作ってみました。
目次
早速作る
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"strings"
)
var (
hs256Key = "secret-key"
headerJSON = `{"alg": "HS256", "typ": "JWT"}`
payloadJSON = `{"iss": "yuyan", "id": "123456"}`
)
func main() {
// headerをbase64URLでエンコード
base64Header := base64.RawURLEncoding.EncodeToString([]byte(headerJSON))
// payloadをbase64URLでエンコードする
base64Payload := base64.RawURLEncoding.EncodeToString([]byte(payloadJSON))
// HMAC SHA256で header.payload をハッシュ化
mac := hmac.New(sha256.New, []byte(hs256Key))
mac.Write([]byte(fmt.Sprintf("%s.%s", base64Header, base64Payload)))
// ハッシュ化した値をbase64URLでエンコードする
base64Signature := base64.RawURLEncoding.EncodeToString((mac.Sum(nil)))
// base64Signatureから = を取り除く
// header.payload.signatureでJWTが完成!
jwt := fmt.Sprintf("%s.%s.%s", base64Header, base64Payload, base64Signature)
fmt.Println(jwt)
// eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAieXV5YW4iLCAiaWQiOiAiMTIzNDU2In0.rbpRDicBTBVeqLvTA-Pw1LKZyb7u8Xqid0rgSNGThDY
}
デコードしてみる
func decodeJWT(token string) bool {
arr := strings.Split(token, ".")
if len(arr) != 3 {
fmt.Println("invalid token")
return false
}
header := arr[0]
payload := arr[1]
signature := arr[2]
mac := hmac.New(sha256.New, []byte("secret-key"))
mac.Write([]byte(fmt.Sprintf("%s.%s", header, payload)))
verify := base64.RawURLEncoding.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature), []byte(verify)) {
fmt.Println("invalid hs256key")
return false
}
return true
}
感想
結構お手軽に作成できるんですね。
これだと「絶対にJWTに秘密情報を入れるな!」っていう理由がわかりますね。ペイロードはただbase64でエンコードしているだけなんですね。誰でも中身見放題ですもん。
参考
JWT.IO
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
コメント