Webセキュリティの心臓部!JWT署名アルゴリズム(HS/RS/ES256/384/512)とCookieを徹底解説【初心者も安心】
「ログイン状態を保持する」「APIアクセスを安全に行う」… 私たちが普段何気なく利用しているWebサービスの裏側では、JWT (JSON Web Token) や Cookie といった技術が重要な役割を担っています。しかし、これらの仕組み、特にセキュリティの要となる「署名」について、あなたはどれだけ知っていますか?
この記事では、プロのブロガーであり、Webセキュリティの専門家である私が、JWTの核心である署名アルゴリズム(HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, そして危険な "none"
)と、それに関連する秘密鍵、そしてCookieについて、初心者の方にも分かりやすく、かつ深く掘り下げて解説します。
この記事を読めば、以下の点が理解できるようになります。
- JWTがなぜ必要で、どのような仕組みで動いているのか
- JWTの安全性を担保する「署名」の重要性と種類
- 各署名アルゴリズム(HMAC, RSA, ECDSA)の違いと選び方
- 絶対に使うべきではない
"none"
アルゴリズムの危険性 - セキュリティの鍵となる「秘密鍵」の管理方法
- JWTと密接に関わる「Cookie」の役割とセキュリティ設定
Web開発者の方はもちろん、Webサービスのセキュリティに関心のあるすべての方にとって、必読の内容です。さあ、安全なWebの世界への扉を開きましょう!
JWTとは?Web認証の鍵を握るトークン
JWTが必要とされる背景 (HTTPのステートレス性)
Web通信の基本プロトコルであるHTTPは、「ステートレス」な性質を持っています。これは、サーバーが過去のリクエストを記憶せず、リクエストごとにクライアントを認識できないことを意味します。しかし、ログイン状態の維持など、多くのWebサービスではユーザーの状態を管理する必要があります。この問題を解決する手段の一つがJWTです。
JWTの構造:ヘッダー、ペイロード、署名の3部構成
JWTは、.
(ドット)で区切られた3つの部分から構成される文字列です。
- ヘッダー (Header): トークンの種類(JWT)と、使用されている署名アルゴリズム(例:
HS256
,RS256
)などの情報を含みます。Base64URLエンコードされています。{ "alg": "HS256", "typ": "JWT" }
- ペイロード (Payload): 実際のデータ(クレーム)を含みます。ユーザーID、名前、権限、有効期限など、伝えたい情報をここに格納します。ヘッダー同様、Base64URLエンコードされていますが、暗号化されているわけではないため、機密情報は含めるべきではありません。
{ "sub": "1234567890", "name": "John Doe", "iat": 1516239022, "exp": 1516242622 // 有効期限 (Expiration Time) }
- 署名 (Signature): ヘッダーとペイロードが改ざんされていないこと、そして送信者が正当であることを証明するための部分です。ヘッダー、ペイロード、そして秘密鍵(または秘密鍵と公開鍵)を使って、ヘッダーで指定されたアルゴリズムで計算されます。
ヘッダー(Base64URLエンコード) + "." + ペイロード(Base64URLエンコード) + "." + 署名
これがJWTの基本的な形です。
JWTは何に使われるの? (認証、認可、情報伝達)
- 認証 (Authentication): ユーザーがログインすると、サーバーはJWTを生成してユーザーに返します。ユーザーはその後のリクエストでJWTを提示することで、「私はログイン済みのユーザーです」と証明できます。
- 認可 (Authorization): ペイロードにユーザーの権限情報(例: 管理者権限があるか)を含めることで、特定のリソースへのアクセス制御を行えます。
- 情報伝達 (Information Exchange): 署名によって情報の完全性が保証されるため、安全に情報を交換する手段としても利用できます。
JWTの心臓部!署名アルゴリズムの世界
なぜ署名が必要?改ざん防止と送信者認証
署名の主な目的は以下の2つです。
- 改ざん防止 (Integrity): ヘッダーやペイロードが途中で誰かに書き換えられていないことを保証します。受信者は受け取ったJWTのヘッダーとペイロード、そして(アルゴリズムに応じた)鍵を使って署名を再計算し、トークンに含まれる署名と比較することで検証します。
- 送信者認証 (Authentication): HMAC系の場合は共有鍵を知っていること、RSA/ECDSA系の場合は秘密鍵を持っていることが署名生成の条件となるため、「そのJWTが正当な発行者によって作られたものである」ことを証明します。
署名の仕組み:基本ステップ
署名は一般的に以下のステップで生成されます。
- Base64URLエンコードされたヘッダーとペイロードを
.
で連結します (unsignedToken
)。 unsignedToken
と秘密鍵(または秘密鍵/公開鍵ペア)を、ヘッダーのalg
で指定された署名アルゴリズムに入力します。- アルゴリズムが署名を計算して出力します。
HMAC系 (HS256, HS384, HS512):共有鍵で高速検証
- アルゴリズム:
- HS256: HMAC (Hash-based Message Authentication Code) using SHA-256
- HS384: HMAC using SHA-384
- HS512: HMAC using SHA-512
- 仕組み: 送信者と受信者が同じ秘密鍵(共有鍵)を使って署名の生成と検証を行います。ハッシュ関数(SHA-256/384/512)を利用してメッセージ認証コードを生成します。
- 特徴:
- 計算が比較的軽量で高速。
- 署名と検証に同じ鍵を使うため、鍵管理がシンプル(しかし、鍵の共有が必要)。
- 秘密鍵(共有鍵)の重要性: この鍵が漏洩すると、誰でも有効なJWTを生成できてしまいます。厳重な管理が必須です。
RSA系 (RS256, RS384, RS512):公開鍵暗号で安全な検証
- アルゴリズム:
- RS256: RSA Signature with SHA-256
- RS384: RSA Signature with SHA-384
- RS512: RSA Signature with SHA-512
- 仕組み: 秘密鍵と公開鍵のペアを使用する公開鍵暗号方式に基づきます。
- 署名生成: 送信者(サーバー)が自身の秘密鍵を使って署名します。
- 署名検証: 受信者(クライアントや他のサーバー)が送信者の公開鍵を使って署名を検証します。公開鍵は事前に共有されていても安全です。
- 特徴:
- 秘密鍵を知らなくても検証できるため、鍵の配布が安全かつ容易。
- HMAC系に比べて計算コストが高い。
- 鍵ペア管理: 秘密鍵は絶対に漏洩させてはいけません。公開鍵は検証に必要な相手に配布します。
ECDSA系 (ES256, ES384, ES512):より強力な楕円曲線暗号
- アルゴリズム:
- ES256: ECDSA (Elliptic Curve Digital Signature Algorithm) using P-256 curve and SHA-256
- ES384: ECDSA using P-384 curve and SHA-384
- ES512: ECDSA using P-521 curve and SHA-512
- 仕組み: RSA同様、公開鍵暗号方式(楕円曲線暗号)に基づき、秘密鍵で署名し、公開鍵で検証します。
- 特徴:
- RSAよりも短い鍵長で同等以上のセキュリティ強度を実現できます。これにより、署名サイズが小さくなり、パフォーマンスが向上する場合があります。
- RSAよりも複雑な数学に基づいています。
- 鍵ペア管理: RSAと同様、秘密鍵の厳重な管理と、公開鍵の安全な配布が必要です。
【警告】”none” アルゴリズム:絶対に使ってはいけない理由
JWTの仕様には alg
ヘッダーに "none"
を指定できるオプションがあります。これは「署名を行わない」という意味です。これは絶対に、絶対に、使用してはいけません。
- 危険性: 署名がないため、ヘッダーやペイロードの内容は誰でも自由に改ざんできます。攻撃者は
alg
を"none"
に書き換え、ペイロードを自分に都合の良い内容(例: 管理者権限を付与)に変更し、有効なトークンとしてサーバーに送信できてしまいます。 - 対策: サーバーサイドのJWT検証ライブラリでは、受け入れるアルゴリズムを明示的に指定し、決して
"none"
を許可しないように設定する必要があります。多くのライブラリはデフォルトで安全な設定になっていますが、常に確認が重要です。
どのアルゴリズムを選ぶべき?選択のポイント (セキュリティ vs パフォーマンス)
アルゴリズム選択は、セキュリティ要件とパフォーマンス要件のトレードオフになります。
- HS256 (HMAC系):
- メリット: 高速、実装が比較的容易。
- デメリット: 署名と検証に同じ鍵が必要。鍵が漏洩した場合のリスクが大きい。鍵を安全に共有する必要がある。
- ユースケース: 単一のサーバー内や、完全に信頼できるシステム間での通信など、鍵共有が問題にならない場合。
- RS256 / ES256 (公開鍵暗号系):
- メリット: 秘密鍵を知らなくても検証可能。鍵配布が安全。第三者による検証が可能。ES256はRSAより短い鍵で高強度。
- デメリット: HMACより計算コストが高い。鍵ペアの管理が必要。
- ユースケース: マイクロサービスアーキテクチャのように、複数のサービス間でJWTを検証する必要がある場合。クライアント側で検証が必要な場合。より高いセキュリティが求められる場合。
- 強度 (XXX256 vs XXX384 vs XXX512): 数字が大きいほど、使用するハッシュ関数が強力になり、セキュリティ強度が高まりますが、計算コストも増加します。一般的に、256ビット(HS256, RS256, ES256)でも十分なセキュリティ強度があるとされていますが、より高い保証が必要な場合は384や512を選択します。NIST(アメリカ国立標準技術研究所)などの公的機関の推奨に従うのが良いでしょう。
専門家の意見: OWASP (Open Web Application Security Project) は、可能な限り非対称アルゴリズム(RS/ES系)の使用を推奨しています。特にマイクロサービス環境など、トークン発行者と検証者が異なる場合に有効です。
秘密鍵・公開鍵:JWTセキュリティの生命線
署名アルゴリズムの安全性は、使用する鍵の管理に大きく依存します。
秘密鍵とは?絶対に漏洩させてはいけない情報
- HMAC系 (HS***): 署名と検証の両方に使われる共有鍵。これが漏れると、誰でも有効なJWTを偽造できます。
- RSA/ECDSA系 (RS***/ES***): 署名生成に使われる秘密鍵。これが漏れると、発行者をなりすましてJWTを偽造できます。
秘密鍵は、パスワードやAPIキーと同様に、厳重に管理する必要があります。ソースコードにハードコーディングしたり、バージョン管理システムにコミットしたりしてはいけません。環境変数や、AWS Secrets Manager, Google Secret Manager, HashiCorp Vaultなどのシークレット管理サービスを利用するのがベストプラクティスです。
公開鍵とは?検証のために公開される鍵
- RSA/ECDSA系 (RS***/ES***): 秘密鍵とペアになる鍵で、署名の検証に使われます。この鍵は、JWTを検証する必要がある関係者に配布しても安全です。通常、JWK (JSON Web Key)形式で公開エンドポイント(JWKS URL)を通じて提供されます。
鍵管理のベストプラクティス
- 強力な鍵の生成: 十分な長さとランダム性を持つ鍵を生成します。
- 定期的な鍵のローテーション: 万が一鍵が漏洩した場合の影響を最小限にするため、定期的に鍵を更新します。JWKS URLを利用すると、古い鍵での検証も一定期間可能にしつつ、スムーズな移行が可能です。
- 最小権限の原則: 鍵へのアクセス権限を必要最小限の関係者に限定します。
- 安全な保管: シークレット管理サービスなどを活用し、安全に保管します。
Cookieとは?JWTを運ぶ運び屋
JWTは生成されただけでは役に立ちません。クライアント(通常はブラウザ)とサーバー間でやり取りされる必要があります。その一般的な方法の一つがCookieを利用することです。
Cookieの基本:Webサイトがあなたを覚えている仕組み
Cookieは、サーバーから送信され、ブラウザに保存される小さなテキストデータです。ブラウザは、同じサーバーへの後続のリクエスト時に、保存されているCookieを自動的に送信します。これにより、HTTPのステートレス性を補い、サーバーはユーザーの状態(例: ログインしているか、カートに何が入っているか)を維持できます。
JWTとCookieはどう連携する? (Cookieへの格納)
サーバーは認証成功時に生成したJWTを、Set-Cookie
HTTPヘッダーを使ってブラウザに送信します。ブラウザはそのJWTをCookieとして保存し、以降のリクエストで自動的に Cookie
ヘッダーに含めてサーバーに送信します。サーバーは受け取ったCookieからJWTを取り出し、署名を検証してユーザーを認証・認可します。
HTTP/1.1 200 OK
Set-Cookie: accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c; HttpOnly; Secure; SameSite=Lax
Content-Type: application/json
...
Cookieのセキュリティ属性:HttpOnly, Secure, SameSiteで防御力UP
JWTをCookieに保存する場合、以下の属性を設定することが強く推奨されます。これらはクロスサイトスクリプティング (XSS) やクロスサイトリクエストフォージェリ (CSRF) といった攻撃から保護するのに役立ちます。
HttpOnly
: この属性が付いたCookieは、JavaScriptのdocument.cookie
APIからアクセスできなくなります。これにより、XSS攻撃によってCookie(JWT)が盗まれるリスクを大幅に軽減できます。認証情報を格納するCookieには必須の設定です。Secure
: この属性が付いたCookieは、HTTPS接続の場合のみサーバーに送信されます。これにより、通信経路上での盗聴(中間者攻撃)を防ぎます。機密情報を含む可能性のあるCookieには必須です。SameSite
: サイトをまたいだリクエスト(クロスサイトリクエスト)時にCookieを送信するかどうかを制御します。CSRF攻撃対策に有効です。Strict
: 同じサイトからのリクエストにのみCookieを送信します。最も安全ですが、別サイトからのリンク遷移などで不便が生じる場合があります。Lax
:Strict
より少し緩やかで、GETリクエストによるトップレベルナビゲーション(リンククリックなど)ではクロスサイトでもCookieを送信します。多くの場合、セキュリティと利便性のバランスが良い選択肢です。None
: クロスサイトリクエストでも常にCookieを送信します。Secure
属性も同時に指定する必要があります。特別な理由がない限り避けるべきです。
注意: JWTをCookieではなく、ブラウザの localStorage
や sessionStorage
に保存する方法もありますが、これらはJavaScriptから容易にアクセスできるため、XSS攻撃に対して脆弱です。一般的に、認証トークンの保存場所としてはHttpOnly属性付きのCookieが最も安全とされています。
JWT vs Cookie:どちらを使うべき?
JWTと(セッションIDなどを格納する従来の)Cookieは、しばしば比較されますが、JWTをCookieに格納して使うのが一般的です。ここでは、JWTベースの認証と、サーバーサイドセッション(セッションIDをCookieで管理)を比較します。
特徴 | JWT (トークンベース認証) | サーバーサイドセッション (Cookieベース) |
---|---|---|
状態管理 | ステートレス(サーバーはセッション状態を保持しない) | ステートフル(サーバーはセッション情報を保持) |
スケーラビリティ | 高い(サーバー間でセッション共有が不要) | 低い(セッション共有の仕組みが必要になる場合がある) |
保存場所 | クライアント側(Cookie, LocalStorageなど)にトークンを保存 | サーバー側にセッション情報を保存、クライアントはIDのみ保持 |
情報量 | ペイロードに情報を含められる | サーバーへの問い合わせが必要 |
クロスドメイン | CORS設定で対応しやすい | 設定が複雑になる場合がある |
無効化 | トークン自体は有効期限まで有効。無効化リスト管理が必要 | サーバー側でセッション情報を削除すれば即時無効化可能 |
セキュリティ | XSS (LocalStorageの場合), 鍵漏洩リスク | CSRF, セッション固定化, セッションハイジャックリスク |
ユースケースに応じた使い分け:
- JWTが適しているケース:
- マイクロサービスアーキテクチャ
- ステートレスなAPI
- モバイルアプリケーション認証
- シングルページアプリケーション (SPA)
- クロスドメインでの認証
- サーバーサイドセッションが適しているケース:
- 従来のモノリシックなWebアプリケーション
- セッションの即時無効化が重要な場合
- サーバー側で詳細なセッション管理を行いたい場合
実際には、両者の利点を組み合わせたアプローチ(例: JWTをHttpOnly Cookieに格納する)が広く採用されています。
まとめ:安全なWebサービスのために
JWTは現代のWeb認証・認可において非常に強力なツールですが、その安全性は適切な署名アルゴリズムの選択と、鍵の厳重な管理にかかっています。
- 署名は必須: JWTの完全性と信頼性を保証します。
"none"
アルゴリズムは絶対に使用しないでください。 - アルゴリズム選択: セキュリティ要件とシステム構成に応じて、HS (HMAC), RS (RSA), ES (ECDSA) 系から適切なものを選択します。一般的にはRS/ES系が推奨されます。
- 鍵管理: 秘密鍵(共有鍵または秘密鍵)はサービスの生命線です。絶対に漏洩させず、安全に管理・保管し、定期的にローテーションしましょう。
- Cookieの活用: JWTの伝達には、
HttpOnly
,Secure
,SameSite
属性を適切に設定したCookieを利用するのが安全な方法の一つです。
この記事を通じて、JWTとCookie、そしてそれらを支える署名技術についての理解が深まったなら幸いです。Webセキュリティは常に進化しています。常に最新の情報を学び、安全なサービス構築・利用を心がけましょう。
たび友|サイトマップ
関連webアプリ
たび友|サイトマップ:https://tabui-tomo.com/sitemap
索友:https://kentomo.tabui-tomo.com
ピー友:https://pdftomo.tabui-tomo.com
パス友:https://passtomo.tabui-tomo.com
クリプ友:https://cryptomo.tabui-tomo.com