こんにちは!日々の開発やインフラの管理、本当にお疲れ様です。
新しい技術やセキュリティの仕組みって、最初は覚えることがたくさんあって大変ですよね。「JWT」とか「署名」とか、なんだか難しそうな言葉を聞くだけで、頭がクラッとしてしまうこともあるかもしれません。
でも、安心してください!今回は、Webアプリでよく使われる「JWT(JSON Web Token)」という仕組みの、ちょっと怖いけれどすごく大切な「秘密鍵の推測とブルートフォース攻撃(総当たり攻撃)」について、身近な例えを交えながら一歩ずつ優しく紐解いていきたいと思います。
今日のお話を読めば、「なぜ弱いパスワードや鍵が危ないのか」「どうやって攻撃者は侵入してくるのか」、そして「どうやって自分たちのシステムを守ればいいのか」がバッチリ分かりますよ。それでは、一緒にセキュリティの扉を開けていきましょう!
—
1. 身近な例えで理解する「JWT」と「合鍵」の仕組み
まずは、そもそもJWTって何なんだろう?というところからですね。
例えば、あなたがとある高級マンションの住人だと想像してみてください。管理会社から「あなたはこの部屋の住人ですよ」という証明書をもらいますよね。
Webの世界でも同じです。あなたがログインしたときに、サーバーは「この人はパスワードを入力して正しくログインしたユーザーです」という証明書を発行します。これが JWT です。
JWTの中身は、大きく分けると次の3つのパーツでできています。
1. ヘッダー(Header): 「使っている鍵の種類や暗号化のルール」が書かれています。
2. ペイロード(Payload): 「誰がログインしているか(ユーザーIDや権限など)」の大切なデータが入っています。
3. 署名(Signature): ここが一番重要です!「この証明書は、サーバーが本気で発行したもので、途中で誰も偽造していません」と証明するための「特殊なスタンプ(秘密の鍵)」です。
「秘密の鍵」ってなに?
サーバーは、この署名を作るときに、自分しか知らない秘密のパスワード(これを 秘密鍵 / Secret と呼びます)を使います。
例えるなら、マンションの管理人が持っている「絶対に他人に知られてはいけないマスターキーの型(はんこ)」のようなものです。
サーバーはこのはんこをペタッと押してJWTをあなたに渡します。ブラウザはページを移動するたびに、そのJWTをサーバーに見せます。サーバーは「お、このはんこは本物だな。偽物じゃないから通してあげよう」と確認するわけです。
—
2. 攻撃者が狙う「甘い鍵」とブルートフォースの正体
ここで、もしマンションの管理人が、「誰でも簡単に推測できるはんこ」を使っていたらどうなるでしょうか?
例えば、鍵のパスワードが secret だったり、会社名やシステム名の password123 だったりしたら……。
泥棒(攻撃者)は、あなたが持っているJWTをこっそり盗み見ます(JWTは暗号化されているわけではなく、ただエンコードされているだけなので、中身は誰でも簡単に覗き見ることができます)。
そして、攻撃者はこう考えます。
> 「このJWTの署名、もしかしてすごく簡単な言葉で作られてるんじゃないか?」
ここで登場するのが、ブルートフォース攻撃(総当たり攻撃)です。
攻撃者は、自分のもっているコンピュータに「ありそうなパスワードのリスト(辞書)」を何百万個も読み込ませ、1秒間に何万回ものスピードで「この鍵かな?」「違う、じゃあこの鍵かな?」と、正しい合鍵の文字を当てはまるまで自動で試させ続けます。
もし、サーバーが設定した秘密鍵が 123456 や admin のような弱いものだったらどうでしょう?
コンピュータにかかれば、わずか数秒〜数分で「ビンゴ!鍵の文字列は secret123 です!」と見破られてしまうのです。
—
3. 実際に攻撃者はどうやって偽造するのか?(コードで見る手口)
攻撃者が秘密鍵を突き止めてしまったら、何が起きるでしょうか?
それはもう、「合費自由のマスターキーを手に入れた泥棒が、自分の手で好き勝手にはんこを偽造し放題になる状態」です。
例えば、攻撃者はペイロードの中身をこっそり書き換えます。
- 書き換え前:
{"user_id": 100, "role": "viewer"}(普通の一般ユーザー) - 書き換え後:
{"user_id": 100, "role": "admin"}(システムの管理者!)
そして、突き止めた秘密鍵を使って、自分で新しい「本物そっくりの正しい署名」を作り出し、サーバーに送りつけます。
サーバーは、送られてきた署名を確認して、「おっ、正しい秘密鍵で押されたハンコだな!じゃあ管理者権限を通してあげよう」と、まんまと騙されてしまうのです。これがJWT偽造の恐ろしい仕組みです。
Pythonのコードを使って、攻撃者がどのようにオフラインで秘密鍵をブルートフォースするか、そのイメージを見てみましょう(※学習・検証目的以外の悪用は絶対に厳禁です!)。
import hmac
import hashlib
# 1. 盗み出したJWTの「ヘッダー.ペイロード」の部分(固定値)
message = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMDAsInJvbGUiOiJ2aWV3ZXIifQ"
# 2. 盗み出した本物の署名(これと一致する鍵を探す)
target_signature = "b'some_target_signature_bytes...'"
# 3. 攻撃者が用意した「よくあるパスワードのリスト(辞書)」
common_secrets = ["password", "123456", "secret", "secret123", "admin"]
print("[-] 秘密鍵のブルートフォース攻撃を開始します...")
# 4. リストのパスワードを1つずつ試していく
for secret in common_secrets:
# HMAC-SHA256アルゴリズムを使って署名を計算してみる
calculated_sig = hmac.new(
secret.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).digest()
# 計算した署名が、ターゲットの署名と一致するかチェック!
# ※実際のツール(hashcatやjwt_toolなど)ではこれが高速に何万回も行われます
if secret == "secret123": # 例としてヒットしたと仮定
print(f"[+] 秘密鍵を発見しました!! -> 鍵の文字列: {secret}")
break
else:
[-] 辞書攻撃では見つかりませんでした。より大きな辞書が必要です。
このように、脆弱な秘密鍵を使っていると、サーバーに負荷をかけることなく、自分の手元のパソコン(オフライン)で安全に時間をかけて鍵を暴かれてしまうのです。
—
4. 新人の今だからこそ知っておきたい!確実な防御策
「うわぁ、JWTって怖い仕組みなんだな……使わない方がいいのかな?」と思ったそこのあなた、ちょっと待ってください!
JWT自体は、大規模なシステムやスマホアプリなどでも広く使われている非常に便利な技術です。大切なのは、「正しい防犯対策」をしっかりと行うことです。
身の回りの防犯に例えるなら、以下の対策を必ず行いましょう。
① 「絶対に破られない」長くて複雑な秘密鍵を使う
一番の基本はこれです。ピッキングされやすい「短い鍵」や「単純な単語」を絶対にやめること。
鍵の長さにランダムな文字列(英大文字・小文字・数字・記号を混ぜた32文字以上など)を使用すれば、先ほどのようなブルートフォース攻撃は何百年経っても絶対に解読できません。
② 環境変数で鍵を管理し、ソースコードに直書きしない
よくあるミスが、プログラムのソースコード(config.php や index.js など)の中に、次のように直接鍵を書いてしまうことです。
// 【危険な例】ソースコードに鍵を直接書かないでください!
const JWT_SECRET = "my_secret_password";
もしこのコードがGitHubなどのパブリックな場所にうっかりアップロードされてしまったら、世界中の攻撃者に一瞬で鍵をプレゼントしてしまうことになります。
鍵は必ずサーバーの「環境変数」として安全に保管しましょう。
// 【安全な例】環境変数から安全に秘密鍵を読み込む
const jwtSecret = process.env.JWT_SECRET;
if (!jwtSecret) {
throw new Error("エラー: JWTの秘密鍵が環境変数に設定されていません!");
}
③ アルゴリズムの指定ミス(Noneアルゴリズムなど)に注意する
JWTの脆弱性には、今回紹介したブルートフォース以外にも、「アルゴリズムを none(署名なし)に書き換えてもサーバーが検証をスルーしてしまう」という有名な実装ミス(脆弱性)があります。信頼できるライブラリを正しく使い、署名の検証プロセスを自前で適当に実装しないようにしましょう。
—
5. おわりに:一歩ずつ、セキュアな開発者へ!
今回は、JWTの秘密鍵の推測とブルートフォース攻撃について、家の鍵や泥棒に例えながら解説しましたがいかがでしたでしょうか?
最初は難しい用語や攻撃手法に圧倒されるかもしれませんが、セキュリティの基本は「攻撃者がどうやって攻めてくるか(相手視点)」を知ることで、「どう守ればいいか(自分たちの対策)」がハッキリ見えてくるようになります。
今日学んだ、
- 簡単なパスワードを秘密鍵にしないこと
- ソースコードに鍵をハードコードせず、環境変数で厳重に管理すること
この2つを意識するだけでも、あなたの作るシステムのセキュリティレベルはグッと上がります。
焦らず、一歩ずつ確実に知識とスキルを身につけて、頼れるエンジニアを目指していきましょう!応援しています!
コメント