ログイン機能を実装するためにJWT(JSON Web Token)を調べてみた

Web開発

皆さん、こんにちは。

最近、ログイン機能を実装する際に、JWT(JSON Web Token)について調べたのですが。

今回はその調べた内容について書きたいと思います。

JWT(JSON Web Token)とは?

安全にJSONオブジェクトをやり取りするための表現形式。

HTTP認証ヘッダーやURIクエリーパラメータに、Tokenとして設置できる。

Header/Payload/Signatureの3つの要素から構成される。

3つの要素をdot(.)でつないだ形式が最終的なTokenの形式となる。

また、☝の3要素はそれぞれURL-safeな文字列(base64)で表現される。

Signature(サイン)は、Header.Paylaod をハッシュ化したもので、受信時にデータ(Header&Payload)が改ざんされていないのかを証明することができる(完全性)。

具体的な使用例としては、

  • ログイン認証後に発行するTokenをHTTP認証ヘッダーへ追加する
  • ユーザ新規登録時に発行するEメールへ、URIのクエリーパラメータとしてTokenを追加する

など。

JWTとCSRFについて考えてみる

CSRF(Cross-Site Request Forgery)対策になるのかどうかについて考えてみたいと思います。

CSRF(Cross-Site Request Forgery)とは?

CSRFとは、外部のサイトから不正なHTTPリクエストを受け取り、処理してしまうことです。

簡単な図を用意しました。

例えば、攻撃者はある会社のWeb Serverに対して、なんらかの攻撃をしようとしているとします。

攻撃の流れとしては、

①攻撃者は、不正なHTTPリクエストを送信するためのサイトを用意する。

②攻撃者は、ある特定のユーザ or 不特定多数のユーザを攻撃用サイトに誘導する。誘導方法としては、メール/TwitterなどのSNSなどでメッセージを送信するなどが考えられる。

③ユーザAは、攻撃者が用意したサイトにアクセスしてしまい、自動でHTTPリクエスト(JSでformをsubmitなど)が送信される。

④ターゲットである自社Web Serverは、③のHTTPリクエストを受け付けてしまい、処理されてしまう。

補足:不正なHTTPリクエストというのは、意図しない書き込み・DDoS攻撃など、さまざま考えられます。

JWTでCSRFの不正リクエストは防げるのか

さて、ここからが本題です。

上の例をもとに考えてみましょう。

JWTの認証では、通常サーバサイドでToken中に含まれるユーザIDを参照して、このリクエストを送信したユーザは誰であるのかを確認しています。

そのため、Tokenが盗まれることさえなければ、問題ないです。

CSRF攻撃で送信されたHTTPリクエストはサーバサイドの認証ではじかれるので。

上の図では、ユーザAはすでにJWTの認証を行っており、Tokenを持っているとします。

ユーザAが攻撃者が用意したサイトを訪れたとしても、Tokenを取得できなければ、サーバサイドのTokenの認証ではじかれることになります。

上記のことから、JWTではTokenをどのようにフロント(ブラウザ)側で扱うのかが、CSRF対策として大切なことになってきます。

調べたところ、Tokenの管理には以下の3パターンがあるようです。

  • Cookieで管理
  • Web storageで管理
  • メモリで管理

TokenをCookieで管理する

他のブログでもこれをお勧めしてましたね。

Cookie内にTokenを保存するにあたって、以下のことを実装する必要があります。

  • JSからCookie内のTokenを読み書きできないようにHttpOnly属性を使用すること。
  • httpsでのみCookieをサーバーへ送信できるようにするためにSecure属性を使用すること。
  • SameSite属性をStrictまたはLaxに設定すること。
  • CookieまたはTokenの持続時間(有効時間)を短くする。

TokenをWeb storageで管理する

Web storage(Local Storage, Session Storage)でTokenを管理する場合は、3rdパーティ製のJSからTokenを読み取られる可能性があるので、あまりおすすめしないとのことです。

しかしながら、Local StorageでTokenを保持しておくのが多くみられるパターンですよね。。。

Tokenをメモリで管理する

一番おすすめされていた方法が、このメモリでTokenを管理する方法です。

しかし、この方法は基本的にSPA(Single page application)くらいしか、使い道がないと思います。

JSの変数でメモリ上にTokenを保持した場合、ブラウザを閉じる or 画面をリロードすると保持していた値も消えるので、ログイン状態を維持することはできません。

まとめ

SPAの開発 && ブラウザを閉じた後もログイン状態を保持する必要がないなら、メモリ上にTokenを保持する。

それ以外の場合、基本的にCookie内でTokenを保持して使用する。

※ただし、上に記載した項目をCookie内に追加するようにする。

以上です!

次回は、Pythonで実際にCookieを使ってどのようにTokenを保持して認証できるのかを試してみたいと思います。

参考

JWT.IO - JSON Web Tokens Introduction
Learn about JSON Web Tokens, what are they, how they work, when and why you should use them.
JWT(JSON Web Token)でCSRF脆弱性を回避できるワケを調べてみた話 - Qiita
はじめにこんにちは。流通事業部、新卒2年目の@mejilebenです。ガチアサリ難しすぎる。。。※本記事はLIFULL Advent Calendar 2017 20日目の記事です。背景JW…
HTTP Cookie の使用 - HTTP | MDN
Cookie(ウェブ Cookie、ブラウザー Cookie とも呼ぶ)は、サーバーがユーザーのウェブブラウザーに送信する小さなデータです。ブラウザーは Cookie を保存したり、新しい Cookie を作成したり、既存の Cookie を変更したり、後でリクエストされたときに同じサーバーにそれらを送り返したりするこ...
タイトルとURLをコピーしました