【実務・中級編】 RSA暗号におけるパディング方式(PKCS#1 v1.5 vs OAEP)の選択基準 – 暗号理論・認証基盤 & エンドポイントセキュリティ防御ガイド

RSAパディングの「禁忌」:なぜ今すぐPKCS#1 v1.5を捨て、OAEPへ移行すべきなのか

現場でコードをレビューしていると、いまだに「なんとなく」でRSAのパディング方式を選んでいるエンジニアに遭遇する。正直に言おう。PKCS#1 v1.5の使用は、現代において「鍵のかかっていない玄関を放置する」のと同義だ。

今日は、なぜBleichenbacher攻撃があなたのシステムを沈没させるのか、そしてどうすれば安全な実装に切り替えられるのか、実戦的な話をしよう。

—

1. なぜPKCS#1 v1.5が「地雷」なのか

RSA暗号の数学的構造は堅牢だが、実装時に「パディング(詰め物)」を適切に行わないと、数学的な脆弱性が露呈する。PKCS#1 v1.5は、1990年代後半に考案された規格だ。

Bleichenbacher攻撃の恐怖

この方式の致命的な欠陥は、復号エラーの「応答」にある。攻撃者は、適当に改ざんした暗号文を送信し、サーバーが返すエラー内容(「復号失敗」なのか「パディング不正」なのか)というわずかな情報の差を観測する。これを数百万回繰り返すだけで、秘密鍵を使わずに暗号文を復号できてしまう。

これが有名な「Bleichenbacher攻撃(Padding Oracle Attack)」だ。現代の高速なネットワーク環境では、この試行回数は数分から数時間で完遂される。つまり、あなたのWebアプリやAPIがPKCS#1 v1.5を採用しているなら、それは「時間をかければ必ず破られる」ことを意味している。

—

2. 現代の防壁:RSA-OAEPへの転換

この脆弱性を根本的に解決するために導入されたのが OAEP (Optimal Asymmetric Encryption Padding) だ。OAEPはハッシュ関数を用いたランダム化処理を含んでおり、攻撃者が暗号文を少しずつ書き換えて試行する「オラクル攻撃」を数学的に不可能にする。

現場の鉄則として、新しい実装では必ず RSA-OAEP を指定すること。

—

3. 実践:セキュアな実装コード

理屈はわかっても、実装で間違えれば台無しだ。主要言語での正しい実装例を挙げる。

Pythonでの実装例(cryptographyライブラリ)

標準ライブラリではなく、モダンな cryptography を使うのが今のエンジニアの常識だ。

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding, rsa

# 安全なOAEPパディングの設定
# MGF1はマスク生成関数。SHA256を使用するのが現在の推奨
padding_oaep = padding.OAEP(
    mgf=padding.MGF1(algorithm=hashes.SHA256()),
    algorithm=hashes.SHA256(),
    label=None
)

# 暗号化の実行
ciphertext = public_key.encrypt(
    b"機密データ",
    padding_oaep
)

# 復号の実行
plaintext = private_key.decrypt(
    ciphertext,
    padding_oaep
)

Node.jsでの実装例(cryptoモジュール)

Node.jsでも同様に、オプションで明示的に padding: crypto.constants.RSA_PKCS1_OAEP_PADDING を指定する。

const crypto = require('crypto');

const buffer = Buffer.from('機密データ', 'utf8');

// 公開鍵で暗号化
const encrypted = crypto.publicEncrypt({
    key: publicKey,
    padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, // これが重要
    oaepHash: "sha256" // OAEPのハッシュアルゴリズムを明示
}, buffer);

—

4. 運用エンジニアが忘れてはならないこと

コードを書くだけがセキュリティではない。インフラ層でも次のポイントを確認してほしい。

1. エラーハンドリングの共通化:
復号に失敗した際、詳細なエラーメッセージ(例: Padding Error や Invalid Key)をクライアントに返してはいけない。「復号失敗」という一律のメッセージを返すことで、攻撃者にヒントを与えないことが重要だ。
2. 古いライブラリの棚卸し:
レガシーなOpenSSLの古いバージョンや、EOLを迎えた言語の標準ライブラリには、デフォルトでPKCS#1 v1.5を強制するものがある。一度 ldd や pip list で依存関係を精査し、最新の暗号スイートに対応しているか確認してくれ。
3. WAFでの検知:
もし移行に時間がかかる場合、WAFで「特定のパディングエラーを誘発するような異常なリクエストパターン」を監視するルールを組むことも検討すべきだが、これはあくまで「延命措置」だ。本質的な解決はコードの書き換え以外にない。

最後に:なぜ「今」やるべきか

セキュリティの世界では、「動いているから大丈夫」という言葉は禁句だ。PKCS#1 v1.5は、かつては正解だったが、今や攻撃者にとっての「入り口」でしかない。

後輩諸君、明日のリリースで古い実装を一つずつ剥がしていこう。それが、君たちの書いたコードを、そして君たちが守るべきユーザーのデータを未来に繋ぐ唯一の道だ。

コードは嘘をつかない。だが、過去の遺産は牙を剥く。さあ、今すぐリポジトリを検索して、PKCS1_v1_5 という文字列を検索してくれ。それが修正のスタートラインだ。

コメント

タイトルとURLをコピーしました