こんにちは!インフラやアプリの開発現場に飛び込んだばかりの新人IT担当者の皆さん、そしてセキュリティの扉を叩いたばかりの一般開発者の皆さん、日々の業務本当にお疲れ様です!
セキュリティの世界に足を踏み入れると、RSAやAES、パディングといった聞き慣れない用語がたくさん出てきて、「なんだか難しそうだな…」と圧倒されてしまいますよね。でも、安心してください!一歩ずつ、身近な例えから紐解いていけば、決して越えられない壁ではありません。
今回は、現代の暗号通信を裏で支える「RSA暗号のパディング方式(PKCS#1 v1.5 と OAEP)」について、泥棒と防犯の仕組みに例えながら、なぜ古いやり方が危なくて、新しいやり方が絶対に必要なのかを優しく解説していきます。一緒に実務で使える安全なコードの書き方までマスターしていきましょう!
—
1. 家の鍵で例える「RSA暗号」と「パディング」の基本
まずは、RSA暗号がどんなものなのか、そして今回の主役である「パディング」がなぜ必要なのかを、私たちの身近な「郵便受け(ポスト)」に例えて考えてみましょう。
郵便受けの仕組みとRSA暗号
会社のオフィスやマンションの入口にある郵便受けを思い浮かべてみてください。
郵便受けの「投入口」は誰でも開けられますよね。つまり、誰でもあなた宛ての分厚い手紙(データ)をその中に「ポン」と投げ入れることができます。これが公開鍵暗号(RSA暗号)の仕組みです。誰でも暗号化(手紙をポストに投函)できるけれど、中身を取り出せるのは、専用の鍵を持っているあなた(秘密鍵の持ち主)だけ、というわけです。
なぜ「パディング(詰め物)」が必要なの?
さて、ここで問題が発生します。
RSA暗号という仕組みは、実はそのままの状態でデータを暗号化しようとすると、数学的な「長さのルール」が厳しく決まっています。もし送りたい手紙(データ)が短すぎたり変な形をしていたりすると、数学的に計算が解きやすくなってしまい、悪意ある泥棒に中身を簡単に透視されてしまう弱点があるのです。
そこで登場するのが「パディング(詰め物)」です。
短い手紙をそのままポストに入れるのではなく、まわりに「意味のないランダムなデータ(ゴミのようなもの)」をモリモリと詰めて、全体を規定の長さに膨らませてから暗号化します。
受け取った側は、暗号を解読したあとにその「詰め物」を綺麗に取り除いて、本来の手紙を読むわけですね。この詰め物の仕組みをパディング方式と呼びます。
—
2. 古いパディング「PKCS#1 v1.5」が抱える致命的な欠陥
実は、このパディングの歴史には少し暗い過去があります。昔から使われてきた「PKCS#1 v1.5」という古い方式には、泥棒(攻撃者)にとって大好物となる致命的な「隙(脆弱性)」があったのです。
オレオレ詐欺ならぬ「エラーメッセージ泥棒」
想像してみてください。あなたが暗号化された手紙をポストに投函しました。
もし、受け取り手がその手紙を開けようとしたときに、こんな風に叫んでしまったらどうでしょう?
- 「わっ、中身の詰め物(パディング)の形がちょっと崩れてるよ!」
- 「あれ、鍵は開いたけど、最後の署名データがおかしいぞ!」
攻撃者は、この「エラーの違い」を何度も何度も試します。わざと崩れたパディングの手紙を何万回も送りつけ、システムの「あ、それパディングエラーです」「あ、こっちは中身のサイズエラーです」という微妙な返事(エラーメッセージ)の違いを観察するのです。
これをセキュリティ用語で「パディングオラクル攻撃(Bleichenbacher攻撃など)」と呼びます。
攻撃者は、このエラーの返事の傾向を手がかりに、まるで金庫のダイヤルをカチャカチャと探るように、最終的にあなたの大切な秘密を丸裸にしてしまいます。古いやり方(PKCS#1 v1.5)は、エラーの返答の仕方に「ヒント」が漏れすぎていたのです。
—
3. 現代の救世主「OAEP」が安全な理由
この古いやり方の弱点を克服するために生まれたのが、現代のスタンダードである「OAEP(Optimal Asymmetric Encryption Padding)」です。
ガードマンが厳重に監視する最新の詰め物
OAEPは、ただランダムなデータを詰めるだけではありません。数学的な「かき混ぜ機(ハッシュ関数)」を使って、手紙全体とランダムなデータをめちゃくちゃに混ぜ合わせます。
何がすごいかと言うと、もし攻撃者が不正な手紙を送り込んできても、システム側は「どこが間違っていたか」を絶対に細かく教えません。
ただ一言、冷たくこう返します。
- 「エラーです(何がダメだったかは絶対に教えません)」
これによって、攻撃者はエラーのヒントを得ることができなくなり、手紙の中身を推測することが完全に不可能になります。現代のセキュリティの世界では、RSA暗号を使うならこの「OAEP」を選ぶことが絶対の鉄則(マスト)となっています。
—
4. 【実践】安全なコードを書こう(PHPのサンプル)
それでは、実際のシステム開発の現場で、どうやって安全なOAEPを使うべきか、PHPを例に見ていきましょう。
古いPHPの関数や不適切な設定のまま実装すると、知らず知らずのうちに古いPKCS#1 v1.5が選ばれてしまうことがあります。以下のように明示的にOAEPを指定することが重要です。
<?php
/**
* 現代の暗号化の基本:RSA-OAEPを使った安全な暗号化のサンプルコード
* ※新人エンジニアの皆さんは、レガシーな設定を見つけたら必ずこのように改修しましょう!
*/
// 1. 送信したい機密データ(例:ユーザーのパスワードや個人情報など)
$plainText = "超機密データ:社外秘のプロジェクト名です";
// 2. 公開鍵の読み込み(実際の運用では安全なパスから読み込みます)
// ※実務では秘密鍵・公開鍵の管理場所の権限設定にも注意しましょう
$publicKeyPem = <<<'EOD'
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...(ここに実際の公開鍵が入ります)
...
-----END PUBLIC KEY-----
EOD;
$publicKeyResource = openssl_get_publickey($publicKeyPem);
if (!$publicKeyResource) {
die("エラー: 公開鍵の読み込みに失敗しました。");
}
/**
* 3. 暗号化の実行
* ここが最大のポイントです!
* 第4引数に [OPENSSL_PKCS1_OAEP_PADDING] を明示的に指定することで、
* 脆弱な v1.5 ではなく、安全な OAEP パディングを強制します。
*/
$encryptedData = "";
$success = openssl_public_encrypt(
$plainText,
$encryptedData,
$publicKeyResource,
OPENSSL_PKCS1_OAEP_PADDING // ← これが現代の必須設定です!
);
if ($success) {
// 成功したら、安全に保存したりネットワーク経由で送信します
$encodedResult = base64_encode($encryptedData);
echo "暗号化成功(Base64エンコード済み):\n" . $encodedResult . "\n";
} else {
// 失敗した場合は詳細なエラーをログに出し、ユーザーには一律のメッセージを返します
echo "エラー: 暗号化処理に失敗しました。\n";
}
開発・インフラ担当者がチェックすべきポイント
- ライブラリのデフォルト値に頼らない: プログラミング言語やフレームワークによっては、暗号化のデフォルトが古い「PKCS#1 v1.5」になっている場合があります。必ずパラメータで
OAEPを明示してください。 - エラーハンドリングの徹底: 先ほど説明した通り、復号(デコード)に失敗したときに「パディングエラーです」と詳細に例外を返すような実装は避け、一律で「復号に失敗しました(Invalid Request等)」という汎用的なエラーを返すように心がけましょう。
—
まとめ
いかがでしたでしょうか?今回は、RSA暗号における古いパディング方式(PKCS#1 v1.5)の脆弱性と、現代の必須である「OAEP」の仕組みについて紐解いてきました。
- PKCS#1 v1.5は古い: エラーの返答から中身が推測される脆弱性(オラクル攻撃)があるため、新規開発では絶対に避ける。
- OAEPが現代のスタンダード: ランダムな攪拌と一律のエラー返却により、攻撃者のアプローチを完全にシャットアウトする。
- 実装時は明示的に指定する: コードを書くときは
OPENSSL_PKCS1_OAEP_PADDINGなどのパラメータを必ず確認し、安全な設定を選ぶ。
セキュリティの技術は日進月歩ですが、「なぜそれが危ないのか」「どうやって守るのか」を基本から理解していけば、どんな新しい技術や脅威に出会っても怖くありません。一歩ずつ、堅牢で安全なシステムを作れるエンジニアを目指して一緒に頑張っていきましょう!
コメント