ログイン処理や認証処理にJSON Web Tokenというものが使用されているようです。
仕組み自体は2017年くらいからあって、Yahoo!で使用されていたりするようです。仕様はRFC7519で定義されています。

このJWTを使用するにはライブラリを使用するのが一般的らしいです。
ライブラリなどは自由にインストールしてもらっていいよ~みたいな場合は遠慮なくライブラリをインストールさせていただきますが、
期限がある中、説明して、レビューして、上長承認下りないとダメみたいな案件もあるため上手くいかないのが現状です。

一方でライブラリを使用すると、JWTの仕組みなんて知らずに簡単に実装も可能です。
ライブラリありきで、説明しているサイトが大半でした。

今回は、JWTについて勉強しながらライブラリを使用せずPHPで実装してみたので、その備忘録となります。
なお、脆弱性の検証は、別途行う必要があります。

 

目次

仕組みから学ぶ

Yahoo!の技術ブログが仕組みを学ぶには最適だと思います。
読んで頂くとわかりますが、結局はJsonをBase64でエンコードして、繋げているだけになります(以下、繋げたものを電文と呼びます)。

仕組み自体は非常に簡単なため、取り出すときは「.」で繋がっているので、Splitして配列にでも入れればOK そのあとBase64でデコード。
作成するときは適当なJsonをBase64でエンコードすればいいだけです。

問題はデコード時の署名検証です。
署名検証せずに、Payload部だけデコードすればぶっちゃけそれだけで動くといえば動きますが、それだと改ざん検知できません。

署名検証は、HeaderとPayloadから署名を作り直して、電文の署名と一致をチェックします。
今回はHS256の場合を想定し、署名を作成します。

$token = $header . '.' . $payload;
$signature = hash_hmac('sha256' , $token , $key , true );
$signature = rtrim(strtr(base64_encode($signature), '+/', '-_'), '=');

base64_encode時に、プラスなどの記号が変換されないため変換時は工夫が必要らしいです。
公式マニュアルにも書いてありました。

 

この作成した署名と、電文の署名を一致させれば改ざんは検知できるかな、と。

 

HS256ってどうなの?

で、HS256の場合簡単に突破される可能性が高いです。
結局はKeyとしてパスワードをどこかに定義しないといけないためです。
GitやSVNでパスワードをハードコードしているソースをコミットして、そこから情報が漏洩する可能性だってあります。

上記ソースコードは、HS256のためパスコードが漏洩した瞬間乗っ取り放題となります。

RS256は公開鍵方式なので、多少はセキュリティ向上させれます。
この仕組みを学んで、RS256で実装すべきと思いました。

この記事を必要としている人、ここまで読んで頂いた方はおそらくHS256だろうという予想をしています。
少しでも良くしたいという意識のある技術者の方は、先方にRS256での実装の提案及びライブラリの使用をおすすめします。