🙆‍♀️

ONSEN GOODS 開発記録 No.10

に公開

本アプリはユーザー認証成功時にjwtトークンを生成し、それをクライアント側に渡していたが、そのままだとクライアント側でjwtトークンをブラウザのlocal_strageに保存されることになる。これはセキュリティ上非常に危険

jwtのみで認証する危険性

jwtトークンのみだと何が危険なのだろうか?
そもそもの話、jwtは署名に用いられるもので、トークンが改ざんされていないことの証明が目的、これを踏まえたうえでjwtが一体何なのかを見ていく。

jwtは、ヘッダー・ペイロード・署名で構成されており、それをエンコードし、照らし合わせることで署名の働きをしている。

ちなみにこんな感じでjwtは超簡単に生成できる

const token = jwt.sign({ id: user.id, username: user.username }, process.env.JWT_SECRET, {expiresIn: '2h'});

「jwtはエンコードされているのになぜ危険なの?」となると思うかもしれないが、エンコードはデータを別の形式に変換することでデータを隠すことが目的ではないため、簡単にでコードされてしまう。したがってこれがそのままブラウザのlocal_strageに入っているということは、XXSに対しほぼ無力であることを意味する。

ペイロード(データの本体)を暗号化してトークンを機密化できるjweという規格であるが、これは実装が難しいためあまり使われない。

Cookieを使った対策

XXSでトークンを不正に取得されないための主な対策として最も効果的なのは、生成したjwtトークンをCookieに入れてクライアントに渡すことだ。CookieはhttpOnlyによってXXSでブラウザのJavascriptからトークンを読み取ることができなくなる。

const token = jwt.sign({ id: user.id, username: user.username }, process.env.JWT_SECRET, {expiresIn: '2h'});

    // Cookieにtokenをセット
    res.cookie('token', token, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge: 2 * 60 * 60 * 1000 // ==2h
    });

補足

「Cookieといえばユーザーに同意をもらわなければならないのでは?」となるが、ユーザー認証などに使われるサイトの機能に不可欠なCookieは「第一者Cookie」(ファーストパーティCookie)と呼ばれ、ユーザーの同意を得ずに使うことができる。

Discussion