JWTの「alg: none」攻撃とは - 仕組みと対策
jwt none attack(alg: none 攻撃)は、署名アルゴリズムを示すJWTヘッダーを 悪用して署名検証を回避する攻撃です。JWTの危険性や認証の脆弱性として有名ですが、原因はJWTそのものではなく、 検証側がトークン内の指定を無条件に信用する実装にあります。
The JWT "alg: none" attack replaces the token's declared signing algorithm withnone and removes its signature. It succeeds only when a vulnerable verifier trusts that untrusted header and skips signature verification.
TL;DR
- JWTのheaderには必須の
algがあり、RFC 7518は署名なしを表すnoneも定義している - 検証側が
alg: noneを見て署名検証を省略すると、攻撃者が任意のpayloadを偽装できる - 許可アルゴリズムはサーバー設定のホワイトリストで固定し、headerだけで決定しない
- 主要ライブラリは対策済みだが、自前実装・古いバージョン・危険な設定には注意する
1. alg: noneとは / What RFC 7518 defines
JWSとして表現されるJWTのheaderには、署名またはMACに使うアルゴリズムを示す alg フィールドがあります。 RFC 7518はアルゴリズム識別子の一つとして none を定義しており、これはデジタル署名もMACも持たない 「Unsecured JWS」を表します。仕様に存在することは、認証用途のサーバーが受け入れるべきという意味ではありません。
| 部分 / Part | 通常のHS256 JWT | 改ざんされたnone JWT |
|---|---|---|
| Header | {"alg":"HS256","typ":"JWT"} | {"alg":"none","typ":"JWT"} |
| Payload | {"role":"user"} | {"role":"admin"} |
| Signature | HMAC署名あり | 空(末尾のピリオドだけ) |
2. jwt none attackの仕組み / Attack flow
- 攻撃者が正規のJWTを取得し、headerの
algをnoneに書き換える - payloadを
{"role":"admin"}など任意の内容に変更する - signature部分を空にし、
header.payload.の3部分形式でサーバーへ送る - 脆弱な実装が「algがnoneなので検証不要」と判断すると、偽造payloadが認証済みとして通る
// 攻撃の概念例(実際の値はBase64URLエンコードされる)
base64url('{"alg":"none","typ":"JWT"}')
+ "."
+ base64url('{"sub":"victim","role":"admin"}')
+ "." // signatureは空3. 対策 / Pin an algorithm allow-list
検証側は期待するアルゴリズムをサーバー設定から明示的に指定します。クライアントが送った alg は 検証処理への入力の一つにすぎず、それだけを根拠に検証方法や検証省略を決めてはいけません。
Node.js (jsonwebtoken)
import jwt from "jsonwebtoken";
const payload = jwt.verify(token, secret, {
algorithms: ["HS256"], // サーバー側のallow-list
issuer: "https://example.com",
audience: "api.example.com",
});Python (PyJWT)
import jwt
payload = jwt.decode(
token, secret,
algorithms=["HS256"], # headerから自動選択しない
issuer="https://example.com",
audience="api.example.com",
)jsonwebtoken など主要なJWTライブラリは現在、署名鍵なしで none を暗黙に受理しない対策を 備えています。それでも、古いライブラリ、自前のJWT実装、署名検証を無効化するオプション、広すぎる許可設定は危険です。 依存関係を更新し、alg: none のトークンが必ず拒否されるテストを追加してください。
4. JWT Decoderと署名検証の違い / Decode vs verify
当サイトの JWT Decoder は、JWTをデコードしてheaderとpayloadの中身を見るための ツールです。通常のデコード表示は署名検証を行わない設計なので、表示できても安全性や真正性は確認できません。 実際の認証では、当サイトのHS256対応の署名検証機能、または信頼できるサーバーサイドライブラリを使ってください。
5. JWTを使うべきでない場面 / When not to use JWT
「JWTは使うな」「JWTを使ってはいけない」という主張は、用途を分けて考える必要があります。JWTのpayloadは暗号化ではなく Base64URLエンコードされるだけなので、パスワードや個人情報など機密性の高いデータを入れてはいけません。また、漏えいした トークンの即時失効が必須なら、サーバー側で状態を管理するセッション方式の方が単純で安全な場合があります。
一方、分散したAPI間で短寿命のclaimsを受け渡す用途ではJWTが適することがあります。短い有効期限、安全な保存、 署名とclaimsの厳格な検証を組み合わせることがJWTの安全性を支えます。正しく実装すればJWTは安全に利用できます。
6. English summary
RFC 7518 defines none for an Unsecured JWS: a token with no digital signature or MAC. The attack changes the JWT header to {"alg":"none"}, modifies claims such as role: admin, and leaves the signature segment empty. It works only if a flawed verifier trusts the token's algorithm and skips verification. Pin an explicit server-side algorithm allow-list, keep JWT libraries current, and test that unsecured tokens are rejected. Decoding is not verification. JWT can be safe when implemented correctly, but do not put secrets in its readable payload; consider server-side sessions when immediate revocation is required.