その「鍵」、ただのプラスチックかも?OpenID Connectの署名検証で絶対にやってはいけないこと
こんにちは!セキュリティの世界へようこそ。
日々、開発の現場でコードを書いていると、「とりあえず動くものを作らなきゃ!」と焦る気持ち、よく分かります。でも、ちょっと待ってください。その認証の仕組み、実は「おもちゃの鍵」で玄関を閉めているのと同じ状態かもしれません。
今日は、OpenID Connect(OIDC)という、今やWeb認証のスタンダードとなっている技術の「署名検証」における、エンジニアが陥りやすい致命的な罠についてお話しします。
—
1. 「署名」って、何のためにあるの?
まず、身近な例えから入りますね。
皆さんが役所で書類を出すとき、必ず「印鑑」を押しますよね。あれは「この書類は間違いなく本人(私)が作成し、改ざんされていない」という証明です。
OpenID Connectで使われる「IDトークン(JWT)」も全く同じです。
サーバーから届いたトークンが「本物か」「途中で誰かに書き換えられていないか」を確認するために、サーバーは「デジタル署名」という特殊な封蝋(ふうろう)を施します。
もし、この封蝋を確認せずに「あ、トークンが届いたから中身を信じよう!」と中身を鵜呑みにしたらどうなるでしょう?
攻撃者はその隙に、「私は管理者です」という嘘の情報をトークンに書き込んで、あなたのシステムに侵入してくるわけです。
—
2. 攻撃者が狙う「none」という名の盲点
ここで、攻撃者が最も好む「卑劣なテクニック」を紹介します。それがアルゴリズムの固定を忘れることです。
IDトークンのヘッダー部分には、こんな情報が書かれています。
{
“alg”: “RS256”,
“typ”: “JWT”
}
この alg(アルゴリズム)という項目は、「この署名はどんな複雑な計算式で作られたか」を教えてくれる場所です。通常は RS256 や ES256 といった強固な暗号方式が指定されます。
しかし、もしあなたの書いたプログラムが、「送られてきたトークンの alg をそのまま信じてチェックする」という実装になっていたら……攻撃者はこう書き換えて送りつけてきます。
{
“alg”: “none”,
“typ”: “JWT”
}
「none」とは、「署名なんてないよ、だからチェックしないでね」という意味です。
もし、あなたのプログラムがこの「none」を許容してしまったら、プログラムは「あ、署名チェックしなくていいんだな!」と判断し、攻撃者が自由に書き換えた悪意あるトークンを本物として受け入れてしまいます。これが、いわゆるインジェクション攻撃の一種です。
—
3. 「ハードコーディング」こそが最強の防壁
では、どうすればいいのか? 答えはシンプルで、「相手の言いなりにならないこと」です。
ライブラリを使う際、よくやってしまいがちなのが「トークンの中身を見て、そこに書いてあるアルゴリズムを動的に適用する」という実装です。これは絶対にNGです。
そうではなく、「このシステムは絶対に RS256 以外認めない!」とコード内にガチガチに固定(ハードコーディング)しておくのです。
安全な実装のイメージ(擬似コード)
例えば、Node.jsでライブラリを使う場合、以下のように設定を固定します。
// 悪い例:受け取ったトークンのalgをそのまま信頼してしまう
// jwt.verify(token, secret);
// 良い例:アルゴリズムを明示的に指定して、それ以外を弾く
const jwt = require(‘jsonwebtoken’);
const verifyOptions = {
algorithms: [‘RS256’], // ここで「RS256以外は受け付けない!」と明言する
issuer: ‘https://your-auth-server.com’ // 発行元も固定する
};
try {
// これにより、もしalgがnoneやHS256だったらエラーを吐いて止まってくれる
const decoded = jwt.verify(token, publicKey, verifyOptions);
console.log(“正当なユーザーです:”, decoded.sub);
} catch (err) {
console.error(“不正なトークンが検出されました!処理を中断します:”, err.message);
}
—
4. 一歩ずつ、信頼できるエンジニアへ
セキュリティ対策というと、何か特別な魔法が必要だと思われがちです。でも実際は、今日お話ししたような「相手(外部からの入力)を一切信用せず、自分のルールを押し通す」という泥臭い確認作業の積み重ねなんです。
1. アルゴリズムをハードコーディングする(none を絶対に許さない)。
2. 発行元(Issuer)を検証する(知らない相手からの手紙は開けない)。
3. 期限(exp)をチェックする(古い鍵は使わせない)。
これらを守るだけで、あなたのアプリケーションの堅牢性は劇的に向上します。
最初は難しく感じるかもしれませんが、一度この「疑うクセ」を身につけてしまえば、どんなシステムを作るときでも自然と安全な設計ができるようになりますよ。
さあ、今日からあなたのコードを少しだけ「頑固」にしてみませんか?それが、ユーザーの安心を守る第一歩です。
コメント