Closed207

『プロフェッショナルSSL/TLS』読書メモ

KIDANI AkitoKIDANI Akito

第1章 SSL/TLSと暗号技術

1.1 Transport Layer Security

p.1 セキュリティの効能

  • 正しいサーバとやりとりしている確認が持てる
  • 完全な状態で相手が情報を受け取れる

p.2 TLSの目標

  • 暗号学的なセキュリティ:二者間で安全な通信ができる(最優先)
  • 相互運用性:別のプログラム間で同じパラメータを使って暗号通信できる
  • 拡張性:新しい暗号アルゴリズムやハッシュ関数に対応しやすくする
  • 効率性:キャッシュにより他の三目標を妥当なパフォーマンスで達成する
KIDANI AkitoKIDANI Akito

第1章 SSL/TLSと暗号技術

1.2 ネットワークの階層

p.2 インターネットの根幹(IP+TCP)はセキュリティが考慮されていない、データを覗ける
p.2 DNSやBGPなど他のプロトコルも脆弱:意図しないコンピュータから返信を受け取りうる

※BGP
https://www.nic.ad.jp/ja/newsletter/No35/0800.html

  • パケットの経路制御のためのプロトコル
  • 経路制御プロトコル=EGP(Exterior Gateway Protocol)またはIGP(Interior Gateway Protocol)
  • EGP=インターネット上でやりとり、IGP=組織内でやりとり
  • BGPはEGPに分類される
KIDANI AkitoKIDANI Akito

p.2 トラフィックが正しい宛先に送られているか?=PKIで確認
p.3 OSIモデル
アプリケーション層:アプリデータ。 例)HTTP、SMTP、IMAP
プレゼンテーション層:データ表現、変換、暗号化。例)SSL/TLS
セッション層:複数のコネクションを管理
トランスポート層:パケット、ストリームの配送。例)TCP、UDP
ネットワーク層:経路制御、ノード間データグラム配送。例)IP、IPsec
データリンク層:LAN。例)Ethernet
物理層:ケーブル。例)CATS

※セッションより上は分類難。HTTP/2はセッション層にも踏み込んでいる。

p.3 HTTPはSSL/TLSなしでもTCPの上で動く。SSL/TLSはアプリケーション層の様々なプロトコルの暗号化に利用可能

KIDANI AkitoKIDANI Akito

1.3 プロトコルの歴史

p.3 SSLはNetscapeが開発、日の目を見ず
p.3 SSL2は1994リリース
p.3 SSL3.0は1995リリース
p.4 Microsoftが加わりTLS1.0として1999リリース
p.4 TLS1.1は2006リリース
p.4 TLS1.2は2008リリース

参考)TLS1.3は2018リリース

KIDANI AkitoKIDANI Akito

RFC 8996でTLS1.0とTLS1.1が廃止に

IETFで、TLS1.0とTLS1.1を正式に非推奨にする「RFC 8996 Deprecating TLS 1.0 and TLS 1.1」が公開されました。

新しいプロトコルへの以降期間は十分であるとし、TLS1.0, TLS1.1, DTLS1.0は廃止となり、TLS 1.2, TLS1.3, DTLS 1.2のみが使用できます。表現としても、MUST NOTで利用を禁止しています。

TLS 1.0 MUST NOT be used
TLS 1.1 MUST NOT be used
2015年に公開された、TLS利用時の推奨事項を定めたRFC7525がありますが、今回の禁止内容も含めて改定作業が開始されています。

KIDANI AkitoKIDANI Akito

1.4 暗号技術

p.4 数学を基盤とする暗号技術の解決する問題

  • 機密性(秘密が守られるか)
  • 真正性(本人である検証ができるか)
  • 完全性(データが改竄されないか)
KIDANI AkitoKIDANI Akito

1.4.1 要素技術

p.5 要素技術単体ではそれほど便利ではないが組み合わせることで強固なセキュリティを実現

■共通鍵暗号方式(対称暗号方式)
p.6 平文(plaintext)を暗号(cipher、アルゴリズムのこと)を利用して暗号文(ciphertext)にする
p.6 鍵のない置換暗号が数千年前から利用されてきた:安全ではない
p.6 Kerckhoffsの原則(ケルクホフスの原則):鍵以外の全てが攻撃者に掌握されても安全でなくてはならない

  • 暗号アルゴリズムは複数の相手と共有しなければ使えない
  • 他方で、たくさんの人の目にふれて精査されないと安全とは言えない

p.6 今日の暗号技術は計算量的安全性を根拠としている(↔︎情報理論的安全性もある)

KIDANI AkitoKIDANI Akito

p.7 暗号は大きく2種類、ストリーム暗号化とブロック暗号化

●ストリーム暗号化方式 例)RC4
p.7 1バイトずつ逐次暗号化/復号するような方式。排他的論理和を利用する。
p.7 ストリーム暗号は平文と暗号文が同じサイズになるため、HTTPリクエストなどリクエストメソッドやプロトコルバージョン、ヘッダー名などは位置が分かりやすいため、同じ鍵を使い回すと危険。通信のたびに一回限りの鍵を生成して利用する。

※RC4は鍵テーブルに統計的な偏りがあり平文の一部が回復可能なため脆弱であり、2015年にはRFC 7645でSSL/TLSでの利用禁止が提案された

※7.5節でRC4の弱点についてまとめられている(p.222-p.228)

●ブロック暗号化方式 例)AES
p.8 データをブロックごとにまとめて暗号化する。現在多くのブロックは128ビット(16バイト)。AESでは192ビット、256ビットも扱える。
p.8 入力が1ビット変わると出力が大きく変化する性質
p.8 欠点1:そのままでは任意の長さのデータを扱えない(ので後述のパディングを利用する)
p.8 欠点2:同じ入力・鍵については同じ結果となるので、様々な攻撃がありうる
p.8 上記の欠点については暗号化利用モードを利用し緩和

●パディング
p.8 ブロック長に満たないデータに余分なデータを追加する
p.8 TLSの場合、末尾にパディング長を示すバイトがあり、その直前に同じ個数だけ同じバイトを付加する

KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■ハッシュ関数
p.9 任意の長さの入力を固定長の出力(ハッシュ値=フィンガープリント=(メッセージ)ダイジェスト)へ変換するアルゴリズム
p.9 メリット:大きなデータを手軽に比較できる
p.9 暗号学的ハッシュ関数に求められる3つの性質

  • 原像計算困難性 Preimage resistance
  • 第2原像計算困難性 Second preimage resistance
  • 衝突耐性 Collision resistance
    p.9 例)SHA2, SHA3 ※SHA1、MD5は弱いので利用すべきでない
KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■MAC(メッセージ認証コード Message Authentication Code)
p.10 ハッシュ関数によるメッセージの完全性の検証にはハッシュ値の転送が必要だが、攻撃者により捏造されうる
p.10 MAC=鍵付きハッシュ(keyed-hash, keying-hash):ハッシュ関数を拡張して認証可能に。
p.10 暗号処理は機密性を、ハッシュ関数は完全性を与える
p.10 HMAC(Hash-based MAC)を使うとどんなハッシュ関数でもMACに使える

KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■MAC(メッセージ認証コード Message Authentication Code)
p.10 ハッシュ関数によるメッセージの完全性の検証にはハッシュ値の転送が必要だが、攻撃者により捏造されうる
p.10 MAC=鍵付きハッシュ(keyed-hash, keying-hash):ハッシュ関数を拡張して認証可能に。
p.10 暗号処理は機密性を、ハッシュ関数は完全性を与える
p.10 HMAC(Hash-based MAC)を使うとどんなハッシュ関数でもMACに使える

KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■暗号化利用モード
p.10 ブロック暗号化方式を拡張し、任意の長さのデータを暗号化できる。
p.10 ストリーム暗号化方式として使えるものもある。
p.10 ECB, CBC, CFB, OFB, CTR, GCMなどがある

GCM:認証つき暗号スイート。TLS1.2から利用可能
●ECBモード(Electronic Codebook最も単純な暗号化利用モード)
p.10 ブロック長の整数倍のデータにのみ対応=要パディング
p.10 ブロック暗号=決定論的(入力が同じなら結果も同じ)
p.11 さまざまな平文の暗号化を試すと暗号文から平文を推測できてしまう
p.11 TLSへのBEAST攻撃の原因

●CBCモード(Cipher Block Chaining)
p.11 ECBの決定論的性質への対処として、ランダムな初期化ベクター(IV, Initialization Vector)を導入:入力が同じでも出力が異なる
p.11 初期化ベクターと1つ目のブロックとの排他的論理和をとって暗号文ブロックとする
p.11 1つ目のブロックの暗号化の結果を次のブロックの初期化ベクターとして利用していく
p.11 初期化ベクターを受信側に送付することがポイント

KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■公開鍵暗号化方式
p.11 共通鍵のメリット:大きなデータを高速に扱える、デメリット:個別に鍵を用意すると危殆化しやすい、多数必要、同じ鍵の他の暗号文も危険
p.12 公開鍵暗号(非対称暗号化方式)は鍵を2種類使う:公開鍵と秘密鍵
p.12 公開鍵で暗号化したら秘密鍵で復号
p.12 秘密鍵で暗号化したら公開鍵で復号(例:ディジタル署名)
p.12 公開鍵のメリット:公開鍵をPKIの仕組みで広く安全に共有し、大きな集団での安全な通信を実現できる
p.12 公開鍵のデメリット:計算に時間がかかり容量が大きなデータには不向き→共有鍵のネゴシエーションや、認証に利用
p.12 例:RSA(2048ビットの鍵が推奨、2016年時点)

KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■ディジタル署名
p.12 電子的なメッセージの真正性(authenticity)を検証可能にするもの、例)MAC
p.13 MACの制約:事前にMAC鍵の共有が必要
p.13 公開鍵暗号方式を利用したディジタル署名:秘密鍵で署名して公開鍵で検証
p.13 RSA+ハッシュ関数のディジタル署名例

  1. 署名対象のハッシュ値を計算
  2. ハッシュ関数などのメタ情報を付加し符号化(エンコード)
  3. エンコードされたハッシュ値を秘密鍵で暗号化したものがディジタル署名。

p.13 署名検証手順は以下

  1. 同じハッシュ関数でハッシュ値を計算
  2. 公開鍵で署名から送り手の計算したハッシュ値を取得
  3. 1と2を比較
KIDANI AkitoKIDANI Akito

(1.4.1 要素技術)
■乱数生成器
p.13 秘密鍵=とても長い乱数;乱数生成器の品質が重要
p.13 予測可能な動作をするというコンピュータの特性が邪魔をする
p.14 無作為性(エントロピー)を集める:キー入力、マウスの動き、HDDの割り込み
p.14 上記をシード(種)として擬似乱数生成器(pseudo random number generator)を利用する
p.14 暗号学的PRNGには予測不可能性が必要:リバースエンジニアリングされないように

KIDANI AkitoKIDANI Akito

1.4.2 プロトコル
p.14 要素技術は機密性、完全性、真正性のいずれかを満たしてくれる:組み合わせてプロトコルを構成する
p.14 セキュリティプロトコルの最小構成の例

  • 機密性:AESを使ってメッセージを暗号化する
  • 完全性:当事者だけが知るハッシュ鍵でMACを計算し、メッセージと一緒に送る、連番つき、終了メッセージあり
  • 真正性:事前に公開鍵暗号化方式でお互いを認証(+データ交換のために必要な鍵を交換)
    p.15 ハンドシェイク:認証と鍵公開の一連のやりとり
KIDANI AkitoKIDANI Akito

1.4.3 暗号技術に対する攻撃

p.15 暗号技術は単純で用途特化:通常十分に問題点が解明されている <-> より複雑なスキーム、プロトコルの方が攻撃の余地が大きい
p.15 スキーム:要素技術の組み合わせ
p.15 プロトコルの実装への攻撃(ソフトウェアのバグ、脆弱性を悪用)もある
p.15 例)タイミング攻撃:処理時間を観察することで暗号を破られる
(参考:有名な例としてCPUの投機的実行に由来する2018年のMeltdown/Spectreがある)
(参考:Rebuild 200 34.37〜
p.15 暗号をバイパスする:サーバーに侵入して暗号鍵を入手すれば時間のかかる総当たり攻撃は不要
p.16 ポイント:自分でプロトコルやスキームを設計しない、暗号処理を実装しない、確立された暗号アルゴリズムを十分な鍵長で使う

KIDANI AkitoKIDANI Akito

1.4.4 暗号強度

p.16 暗号の強度=暗号アルゴリズムを破るのに必要な操作数で測定(ビット安全性)
p.16 128ビットの鍵=2^128の操作が必要:1ビット増やすと2倍強力になる
p.16 ENCRYPT2(2012)によれば、共通鍵暗号、楕円曲線暗号、ハッシュ値は256ビットでも長期間(30年)の攻撃に耐えうる:公開鍵暗号、DHは1776ビットでようやく短期間(10年)の攻撃に耐えられる

ディフィー・ヘルマン鍵共有(Wikipedia)
公開鍵暗号の一種。RSAより処理負荷高い。認証がなく中間者攻撃に脆弱、2015年には事前計算を利用したLogjam攻撃が明らかに。詳細は本書p.167(6.5. Logjam)。

p.16 現在のセキュリティだけでなく、長期間のセキュリティも考慮すべし:コンピュータが高速になり廉価になれば暗号の強度は変化する

※等価安全性について SSL/TLS暗号設定ガイドライン by IPA p.17

KIDANI AkitoKIDANI Akito

1.4.5 MITM攻撃(中間者攻撃、man-in-the-middle)

p.17 受動的ネットワーク攻撃:第三者が会話を聞いているだけ
p.18 能動的ネットワーク攻撃:通信内容を操作したり当事者間の会話に影響を与える

■アクセスの奪取
p.18 攻撃の前提条件:犠牲者、サーバ、通信インフラへの接近・接続
p.18 通信会社と結託した事例:おそらくアメリカ国家安全保障局(National Security Agency)とAT&T。脚注31のサイトはリンク切れだったのでNY Timesなどが参考になる)
p.18 通信機器を乗っ取った事例:光ファイバーケーブルを盗聴するイギリスの政府通信本部(GCHQ、Government Communications Headquarters)によるTEMPORAプログラム。

※NSAおよびCIAの元局員エドワード・スノーデンによるこれらの告発は2013年6月に行われた

  • ARPスプーフィング:MACアドレスとIPアドレスを関連づけるアドレス解決プロトコル(Address Resolution Protocol)を利用してLAN上で通信機器のなりすましを行う
  • WPADハイジャック:ブラウザのWebプロキシ自動発見(WPAD)を利用して、攻撃者がローカルでプロキシを起動してMITM攻撃を行う。2007年にIEの脆弱性があった
  • DNSハイジャック:ドメインの管理権限のない第三者が不正にドメインをのっとる
  • DNSキャッシュポイズニング:権威サーバーへのDNSメッセージの32ビットのIDベースでのリクエストに対する不正なレスポンスを送り込むことで、ドメイン名に対応する偽のIPをキャッシュさせる。DNSサーバーの脆弱性を悪用。カミンスキーアタックなどが知られる。対応策としてソースポートのランダム化がある。
  • BGP経路ハイジャック:ISPの相互接続などで利用するルーティングプロトコルであるBGPで、不正な経路を広告することで中間者攻撃を実現する。2018年に中国政府がアメリカの通信を傍受していた事例

■受動的攻撃
p.19 トラフィックが暗号化されていない場合に最も有効
p.19 RFC7258:「蔓延する監視は攻撃だ」(2014年5月)
p.19 暗号化されていても、暗号を破れるようになるまで保存することで受動的攻撃が成立しうる
p.20 前方秘匿性(perfect forward secrecy):長期的な鍵(long-term secrets、TLSでいうとサーバーの秘密鍵)からセッションキーを生成して通信を行うが、長期的な鍵が流出した場合でもセッションキーの安全性が保たれるという性質のこと。RSAをベースにしたTLSの鍵交換アルゴリズムではPFSを欠いており、RSA鍵を手に入れれば以前の通信が復号可能。2014年にはHeartbleed脆弱性により秘密鍵流出が問題に。(詳細は6.3, p.180)

■能動的な攻撃
p.20 有効なものとして受け取れる証明書を攻撃者が提示できる(詳細は第4章、Microsoft社を騙り証明書入手した事例など)
p.20 ブラウザの検証のバグをついて、有効に見える証明書を構成する(詳細は第6章、OSのAPIに問題がある場合も)
p.20 不正な証明書でも、エンドユーザーがブラウザの警告をうっかり無視することを期待して攻撃に利用するケースも。2011年シリアで電気通信省が行った?FacebookへのMITM攻撃の事例
p.20 ブラウザが能動的攻撃のターゲットとなることが多い
p.21 能動的攻撃は大規模には仕掛けにくい:主に重要人物に対して仕掛けられる
p.21 QuantumInsertプログラム:NSAとGCHQによる中間者攻撃の手法。本来のページより高速なレスポンスを返すサーバーを使い、不正なページにアクセスさせマルウェアをダウンロードさせる。LinkedInなどが狙われた。

KIDANI AkitoKIDANI Akito

第2章 プロトコル

p.23 TLSは接続指向のネットワーク通信を安全にするための暗号化プロトコル:上位層のプロトコルはなんでもよい

※接続指向:データを確実に相手に送信できる。TCP、SCTPなど。UDPは接続指向ではない。
SCTP:Stream Control Transmission Protocol(ストリーム制御伝送プロトコル)。電話網のプロトコルをIP上で転送するために作られた。LTEで利用。

NTTドコモ テクニカルレポート

KIDANI AkitoKIDANI Akito

2.1 Record プロトコル

p.24 TLSレコードがコネクション上でやりとりされる低レベルのメッセージ転送すべてを担う
p.24 TLSレコード=ヘッダ+メッセージデータ
ヘッダは以下の3つから成る。

  • コンテントタイプ:サブプロトコルのいずれかを示す以下の値。 20(Change Cipher Spec)、21(Alert)、22(Handshake)、23(Application Data)。Java実装
  • バージョン:majorバージョンとminorバージョン。それぞれuint8型(8 ビットの符号なし整数、0-255)。 TLS1.2の場合 { 3, 3 }(TLS1.0が{ 3, 1 }、TLS1.3は{ 3, 4 })。Java実装
  • レコード長:uint16型。最長で2^14バイト(16,384バイト)。
    p.24 上記のほか、64ビットのシーケンス番号が割り当てられ、通信両側がそれぞれ記録する。送受信されるデータには含まれない。リプレイ攻撃への防御として利用。Java実装

●メッセージの転送
p.25 書式が定まっていない(opaque)データのバッファを転送する
p.25 レコードは最長16,384バイト:それより長い場合、分割される。逆に単一のレコードにまとめられることもある。

●暗号化および完全性の検証
p.25 最初の接続におけるメッセージ群は保護されない(厳密にはTLS_NULL_WITH_NULL_NULL暗号スイートが利用される)
p.25 暗号スイートによっては暗号化を利用せず完全性の検証のみを行うものもある

●圧縮
p.25 TLSの圧縮機能は現在では利用されていない(2012年にCRIME攻撃に利用されたため(詳細は7.3))
p.25 HTTPレベルですでに圧縮されている

●拡張性
p.25 Recordプロトコルは暗号処理とデータ転送:他の機能はサブプロトコルで行う
p.25 サブプロトコルはネゴシエーションされたパラメータで自動的に暗号化され保護される
p.25 4つのサブプロトコル:Handshake, Change Cipher Spec, Application Data, Alert

KIDANI AkitoKIDANI Akito

2.2 Handshakeプロトコル

p.25 TLS接続で使うパラメータのネゴシエーションと認証を行うプロトコル
p.25 通信確立=ハンドシェイクには6〜10のメッセージが必要(利用機能に応じて異なる)
p.25 実用的には3つ

  • サーバ認証を伴うフルハンドシェイク
  • 前回のセッションを再開する場合の一部メッセージを省略したハンドシェイク
  • クライアントとサーバの認証を伴うハンドシェイク

p.26 Handshakeプロトコルのメッセージの先頭のヘッダ

  • メッセージの種類(HandshakeType):1バイト。Java実装
  • メッセージの長さ:3バイト(uint24)
enum {
  hello_request(0),
  client_hello(1),
  server_hello(2), 
  certificate(11),
  server_key_exchange (12), 
  certificate_request(13),
  server_hello_done(14), 
  certificate_verify(15),
  client_key_exchange(16), 
  finished(20),
  (255)
} HandshakeType;
KIDANI AkitoKIDANI Akito

2.2.1 フルハンドシェイク

p.26 TLS Sessionを確立するためにフルハンドシェイクを実行

  1. 接続で利用したいパラメータを双方が提示・合意
  2. 認証:証明書or他の方法
  3. セッション保護に利用するマスターシクレットを共有
  4. ハンドシェイクメッセージ群が第三者に書き換えられていないことの検証

p.26 上記の2と3は実際には1ステップで行う=鍵交換(key exchange)

p.27 フルハンドシェイクの10ステップ

  1. ClientHello (C->S):新規ハンドシェイクをクライアントが開始。暗号スイートや鍵交換方法のパラメータ群を送信。
  2. ServerHello (C<-S):サーバがパラメータを決定
  3. Certificate* (C<-S):サーバの証明書チェーンを送信(サーバ認証が必要な場合のみ)
  4. ServerKeyExchange* (C<-S):マスターシークレット生成に必要な情報がある場合これを送信
  5. ServerHelloDone (C<-S):サーバの番が終わったことを通知
  6. ClientKeyExchange (C->S):マスターシークレット生成に必要な情報を送信
  7. ChangeCipherSpec (C->S):クライアントが暗号通信に切り替え、そのことをサーバに通知
  8. Finished (C->S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
  9. ChangeCipherSpec (C<-S):サーバが暗号通信に切り替え、そのことをクライアントに通知
  10. Finished (C<-S):ハンドシェイクメッセージのMACを送る(改竄検知のため)

p.27 何もエラーがなければこの後アプリケーションデータを送信する

KIDANI AkitoKIDANI Akito

2.2.1 フルハンドシェイク

■ClientHello
p.27 クライアントが希望するパラメータ群とその優先度を伝えるメッセージ
p.27 以下の3つの場合に送信

  • 新規にコネクションを開始するとき
  • 再ネゴシエーションをしたいとき
  • サーバからの再ネゴシエーション要求(HelloRequest)に応えるとき
    p.28 Versionフィールド:クライアントがサポートする最良のバージョンを表す(RFCの記載ではclient_versionフィールド)
    p.28 Randomフィールド
  • 32バイト=4バイトのクライアント時刻情報+28バイトのランダムな値。16進数表記になっている(4ビットで1文字)ので56文字。
  • クライアント時刻情報は1994年のNetscape Navigatorの脆弱性以降非推奨となり、ランダム値が送信されることもある。
  • この乱数が完全性検証における重要な役割をもつ(リプレイ攻撃も防止)
    p.29 Session IDフィールド:ランダムな32バイトが含まれる(意味はない)。初回接続時は空。再ネゴシエーション時は一意の識別子が含まれサーバがセッションをキャッシュするのに利用。
    p.29 Cipher Suitesフィールド:クライアントの対応可能な暗号スイートが適切な順番で格納される
    p.29 Compression methodsフィールド:クライアントの対応している圧縮方法。デフォルトはnullで圧縮しない(前述のCRIME攻撃の脆弱性のため(p.25))
    p.29 Extensionsフィールド:拡張情報が任意の数含まれる。server_nameやelliptic_curvesなど。詳細は後述。
struct {
     ProtocolVersion client_version;
     Random random;
     SessionID session_id;
     CipherSuite cipher_suites<2..2^16-2>;
     CompressionMethod compression_methods<1..2^8-1>;
     select (extensions_present) {
         case false:
             struct {};
         case true:
             Extension extensions<0..2^16-1>;
     };
} ClientHello;
KIDANI AkitoKIDANI Akito

■ServerHello

p.29 サーバが接続で使うパラメータを選択して返答する:構造はClientHelloと同じ
p.29 クライアントと同じ最新バージョンに対応している必要はなく、別の下位バージョンを提案することもある

※クライアントがサポートしていない場合、JavaだとSSLHandshakeExceptionが発生する

KIDANI AkitoKIDANI Akito

■Certificate

p.29 主に、サーバからクライアントにX.509証明書チェーンを運ぶ
p.29 証明書チェーン:ASN.1のDER(Distinguished Encoding Rules)を使用してエンコードされた証明書を順番に並べたもの(詳細は3.4を参照)

X.509:ITU-Tの公開鍵基盤 (PKI)の規格。公開鍵証明書の標準形式や証明書パス検証アルゴリズムなどを定めている。

https://www.ipa.go.jp/security/pki/033.html

ITU-T(International Telecommunication Union Telecommunication Standardization Sector):世界規模で電気通信を標準化することを目的として勧告Recommendationsを作成する国連機関。アルファベット1文字で○シリーズ勧告がある(Aシリーズ、Bシリーズなど)。Xシリーズ勧告は「データ網及びオープン・システム・コミュニケーション」に関する規定。ITU-Tで公開されているX.509標準の目次

DER:ITU-TのX.690標準で定められているASN.1符号化規則の一つ。X.690 は、基本符号化規則(BER、Basic Encoding Rules)と 2 つのサブセット、標準符号化規則(CER、Canonical Encoding Rules)と識別符号化規則(DER)を定義する。
CISCOの解説

例: DER では、20 ビット値 1010 1011 1100 1101 1110 が、次のように符号化されます。
タグ: 0x03(ビット列)
長さ: 0x04(バイト)
値: 0x04ABCDE0
DER 符号化全体: 0x030404ABCDE0

ASN.1:Abstract Syntax Notation One(抽象構文記法1)。ASN.1記法とASN.1符号化(エンコード)規則を組み合わせて使う。

p.30 サーバ証明書が先頭、中間証明書が続く。ルート証明書は省くべきとされている。
p.30 サーバには複数の証明書を設定できる:選択された暗号スイートによって、利用できる証明書の公開鍵アルゴリズムが変わるため
p.30 Certificateメッセージは必須ではない:証明書を必要としない認証方式、認証を利用しない暗号スイートもあるため(DH_anonなど)。
p.30 X.509でなくPGP鍵を用いる暗号スイートもある

RFCで定義されている構造体

      opaque ASN.1Cert<1..2^24-1>;
      struct {
          ASN.1Cert certificate_list<0..2^24-1>;
      } Certificate;
KIDANI AkitoKIDANI Akito

■ServerKeyExchange

p.30 目的:鍵交換に必要な付加的データを運ぶ
p.30 中身は暗号スイートによって異なる、送られない場合もある。

鍵交換手法のうち、以下の場合にServerKeyExchangeが送られる

  • DHE_DSS
  • DHE_RSA
  • DH_anon

下記の鍵交換手法の場合にはServerKeyExchangeが送られない

  • RSA
  • DH_DSS
  • DH_RSA

※鍵交換手法についてはRFC2246を参照

      enum { dhe_dss, dhe_rsa, dh_anon, rsa, dh_dss, dh_rsa
            /* 拡張される可能性がある。(例:ECDH について [TLSECC] 参照)*/
           } KeyExchangeAlgorithm;
      struct {
          opaque dh_p<1..2^16-1>;
          opaque dh_g<1..2^16-1>;
          opaque dh_Ys<1..2^16-1>;
      } ServerDHParams;     /* 超短期(Ephemeral)DH パラメータ */
      dh_p
         The prime modulus used for the Diffie-Hellman 処理。
      dh_g
         The generator used for the Diffie-Hellman 処理。
      dh_Ys
         サーバの Diffie-Hellman 公開値 (g^X mod p)。
      struct {
          select (KeyExchangeAlgorithm) {
              case dh_anon:
                  ServerDHParams params;
              case dhe_dss:
              case dhe_rsa:
                  ServerDHParams params;
                  digitally-signed struct {
                      opaque client_random[32];
                      opaque server_random[32];
                      ServerDHParams params;
                  } signed_params;
              case rsa:
              case dh_dss:
              case dh_rsa:
                  struct {} ;
                 /* メッセージは、rsa、dh_dss について省略される。*/
              /* そして、dh_rsa は、拡張される可能性がある。(例:ECDH について [TLSECC] 参照) */
          };
      } ServerKeyExchange;
      params
         そのサーバの鍵交換パラメータ。
      signed_params
         非匿名鍵交換用に、サーバの鍵交換パラメータ上の署名。
KIDANI AkitoKIDANI Akito

■ServerHelloDone

p.30 予定していたハンドシェイクメッセージをすべて送信したときにサーバから送る合図
p.30 サーバが待機状態に入る

※ServerHello および関連するメッセージの終りを示す。
※クライアントは、「そのサーバは、(要求される場合)有効な証明書を提供したか?」を検証する。

構造体

struct { } ServerHelloDone;
KIDANI AkitoKIDANI Akito

■ClientKeyExchange

p.30 鍵交換に必要な情報をクライアントから送信するための必須のメッセージ
p.30 中身は暗号スイートによって異なる。

構造体

struct {
    select (KeyExchangeAlgorithm) {
        case rsa:
            EncryptedPreMasterSecret;
        case dhe_dss:
        case dhe_rsa:
        case dh_dss:
        case dh_rsa:
        case dh_anon:
            ClientDiffieHellmanPublic;
        case ecdhe:
            ClientECDiffieHellmanPublic;
    } exchange_keys;
} ClientKeyExchange;
KIDANI AkitoKIDANI Akito

■ChangeCipherSpec

p.30 クライアント、サーバ両方が送信する
p.30 このメッセージの意味は以下の通り

  • 接続で使うパラメータを組み立てるのに十分な情報を手に入れたこと
  • 暗号鍵を生成したこと
  • これから暗号処理へ移行すること

p.30 サブプロトコルChangeCipherSpecのメッセージ。
p.30 これはハンドシェイクメッセージではない:完全性の検証対象外。ゆえにOpenSSLでは攻撃を受けやすい状態になっていた(2014年)。

※このメッセージは、値が 1 の 1byte から成る。

構造体

   struct {
       enum { change_cipher_spec(1), (255) } type;
   } ChangeCipherSpec;
KIDANI AkitoKIDANI Akito

■Finished

p.31 ハンドシェイクが完了したという合図:このメッセージ以前にApplication Dataプロトコルのメッセージを送信することは認められていない(攻撃を避けるため)

構造体

struct {
    opaque verify_data[verify_data_length];
} Finished;

verify_data
   PRF(master_secret, finished_label, Hash(handshake_messages))
      [0..verify_data_length-1];

p.31 verify_dataフィールド:受信した全ハンドシェイクメッセージをハッシュかしてマスターシークレットと合わせて計算した値
p.31 finished_label:クライアント側は「client finished」、サーバ側は「server finished」
p.31 このメッセージは暗号化されている:ネゴシエーション済みのMACで完全性保証[1]。=マスターシークレットとハンドシェイクメッセージのハッシュ値を知るのは非常に困難。
p.31 TLS1.2のFinishedメッセージ、つまりverify_dataのデフォルトの長さは12バイト(96ビット)。暗号スイートによって変わる[2][3]

RFC5246
ハンドシェイクメッセージとは?

  • HelloRequest以外のメッセージ、このFinishedメッセージまで(このメッセージ自身は含まない)のすべてのデータ
  • レコード層のヘッダは含まない
  • ※ChangeCipherSpecの節で見た通り、ChangeCipherSpecはハンドシェイクメッセージに含まれない。
    https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-5c5c5f435668d1
  • しかし、Finishedメッセージはハンドシェイクメッセージに含まれるので、後から送られるFinishedメッセージのハッシュには先に送られたFinishedメッセージが含まれる
脚注
  1. これってどういうこと? ↩︎

  2. SSL3.0では合計36バイト, TLS1.0TLS1.1では12バイトだった ↩︎

  3. 変わることは変わるらしいが、具体的にどの暗号スイートがいくつなのか不明。stackoverflowJava8の初期実装では12バイトとして扱われている。Java16ではTLS1.3のときに変更になりverifyDataLen = context.negotiatedCipherSuite.hashAlg.hashLength;とある。CipherSuiteのHashAlg定義によれば、SHA-256のとき32、SHA-384のとき48。 ↩︎

KIDANI AkitoKIDANI Akito

2.2.2 クライアント認証

p.31 クライアントとサーバの相互認証は必須ではない
p.32 サーバがクライアント認証を求めるときCertificateRequestメッセージを送る
p.32 クライアントはCertificateメッセージとCertificateVerifyメッセージを送る

p.32 相互認証フルハンドシェイクの13ステップ

  1. ClientHello (C->S):新規ハンドシェイクをクライアントが開始。暗号スイートや鍵交換方法のパラメータ群を送信。
  2. ServerHello (C<-S):サーバがパラメータを決定
  3. Certificate* (C<-S):サーバの証明書チェーンを送信(サーバ認証が必要な場合のみ)
  4. ServerKeyExchange* (C<-S):マスターシークレット生成に必要な情報がある場合これを送信
  5. CertificateRequest (C<-S):クライアントに認証を要求
  6. ServerHelloDone (C<-S):サーバの番が終わったことを通知
  7. Certificate (C->S):クライアントの証明書を送信
  8. ClientKeyExchange (C->S):マスターシークレット生成に必要な情報を送信
  9. CertificateVerify (C->S):秘密鍵でハンドシェイクメッセージに署名して送信
  10. ChangeCipherSpec (C->S):クライアントが暗号通信に切り替え、そのことをサーバに通知
  11. Finished (C->S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
  12. ChangeCipherSpec (C<-S):サーバが暗号通信に切り替え、そのことをクライアントに通知
  13. Finished (C<-S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
KIDANI AkitoKIDANI Akito

■CertificateRequest

構造体

      enum {
          rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
          rsa_ephemeral_dh_RESERVED(5), dss_ephemeral_dh_RESERVED(6),
          fortezza_dms_RESERVED(20), (255)
      } ClientCertificateType;
      opaque DistinguishedName<1..2^16-1>;

      struct {
          ClientCertificateType certificate_types<1..2^8-1>;
          SignatureAndHashAlgorithm
            supported_signature_algorithms<2^16-1>;
          DistinguishedName certificate_authorities<0..2^16-1>;
      } CertificateRequest;

p.32 certificate_types:許容できる証明書(クライアントが提供してよい)の公開鍵を示す。

  • rsa_sign:RSA 鍵を含む証明書
  • dss_sign:DSA 鍵を含む証明書
  • rsa_fixed_dh:無期の(static)DH 鍵を含む証明書
  • dss_fixed_dh:無期の(static)DH 鍵を含む証明書

p.32 supported_signature_algorithms:サーバが検証できるハッシュ/署名アルゴリズムペアのリスト
p.32 certificate_authorities:許容できるCA(認証局)の識別名DistinguishedNameのリスト

KIDANI AkitoKIDANI Akito

■CertificateVerify

構造体

struct {
     digitally-signed struct {
         opaque handshake_messages[handshake_messages_length];
     }
} CertificateVerify;

p.33 これまでにやりとりした全ハンドシェイクメッセージの署名Signature

RFC5246より

  • 署名において使われるハッシュアルゴリズムおよび署名アルゴリズムは、CertificateRequest メッセージの supported_signature_algorithms フィールド中にあるもののひとつでなければならない
  • そのハッシュアルゴリズムおよび署名アルゴリズムは、クライアントのエンド主体証明書中の鍵と互換性がなければならない[1]
脚注
  1. RSAが署名に使われるなら、証明書の公開鍵もRSA、ECDSAで署名するなら証明書の鍵もECDSAということか?[1] ↩︎

KIDANI AkitoKIDANI Akito

2.2.3 セッションリザンプション

p.33 フルハンドシェイクはコストがかかる

  • アプリケーションデータ送信までにクライアント・サーバ間のやりとりが2往復必要
  • CPU負荷の高い暗号処理が何度も必要
  • 認証時の証明書検証はさらに負荷が高い

p.33 Session IDを利用してセッションを再開可能にする
p.33 以前共有したマスターシークレット(ClientKeyExchangeで共有したプリマスターシークレットから生死したもの)から、新たな暗号鍵を生成して通信に利用する

  1. ClientHello (C->S):以前のセッション再開リクエストをクライアントが送信
  2. ServerHello (C<-S):サーバが同一のSession IDを送信
  3. ChangeCipherSpec (C<-S):サーバが暗号通信に切り替え、そのことをクライアントに通知
  4. Finished (C<-S):ハンドシェイクメッセージのMACを送る(改竄検知のため)
  5. ChangeCipherSpec (C->S):クライアントが暗号通信に切り替え、そのことをサーバに通知
  6. Finished (C->S):ハンドシェイクメッセージのMACを送る(改竄検知のため)

p.34 HTTPクッキーに似たセッションチケットの仕組みもある:こちらはクライアントがすべての情報を保持する。サーバがセッション情報を管理しなくてもよい。チケットはサーバの公開鍵で暗号化されている。
TLS Session resumptionに関する英語のブログより

※TLS1.3ではPSK(Pre-Shared Keys、事前共有鍵)を用いてセッションリザンプションを実現する
TLS Session resumptionに関する英語のブログより

KIDANI AkitoKIDANI Akito

2.3 鍵交換

p.34 鍵交換の目的:プリマスターシークレットを生成し共有する
p.34 プリマスターシークレットからマスターシークレット(48バイト)を構成する
p.34 マスターシークレットがTLSセッションのセキュリティを支えている
p.34 よく利用される鍵交換アルゴリズム

鍵交換 説明
dh_anon 認証なしDHカギコウカン
dhe_rsa RSA認証を伴う一時的DH鍵交換
ecdh_anon 認証なしECDH鍵交換(RFC4492)[1]
ecdhe_rsa RSA認証を伴う一時的ECDH鍵交換(RFC4492)
ecdhe_ecdsa ECDSA認証を伴う一時的ECDH鍵交換(RFC4492)
krb5 Kerberos鍵交換(RFC2712)
rsa RSA鍵交換および認証
psk PSK(Pre-Shared Key)鍵交換および認証(RFC4279)
dhe_psk PSK認証を伴う一時的DH鍵交換(RFC4279)
rsa_psk PSK鍵交換およびRSA認証(RFC4279)
srp SRP鍵交換および認証(RFC5054)(Secure Remote Password)[2]

p.34 よく利用される4つ:RSA, DHE_RSA, ECDHE_RSA, ECDHE_ECDSA

脚注
  1. テキスト本文ではECDHE鍵交換となっているが誤記と思われる ↩︎

  2. SRP自体はRFC2945で定められている。Wikipediaによると、辞書攻撃に強く、信頼された第三者機関が必要ない。2021年現在のバージョンは6a。 ↩︎

KIDANI AkitoKIDANI Akito

●RSA鍵交換アルゴリズム

p.34 事実上の標準ともいえる
p.34 深刻な設計上の問題:サーバの秘密鍵が漏洩すると過去のやりとりもすべて復号可能(cf. Heartbleed)
p.35 従って、前方秘匿性のある他のアルゴリズムに置き換えが進んでいる
p.35 クライアントがプリマスターシークレットを生成、サーバの公開鍵で暗号化してClientKeyExchangeメッセージで送信
p.35 鍵転送のアルゴリズム

KIDANI AkitoKIDANI Akito

●DHE_RSA

p.35 一時的DH(Ephemeral Diffie-Hellman)の長所は前方秘匿性があること、短所は遅いこと
p.35 サーバとクライアント双方が処理に参加して共通の鍵を決定する鍵合意のアルゴリズム

KIDANI AkitoKIDANI Akito

●ECDHE_RSAおよびECDHE_ECDSA

p.35 一時的楕円曲線Diffie-Hellman(Ephemeral elliptic curve-):鍵合意アルゴリズム
p.35 処理が高速かつ前方秘匿性がある
p.35 現代的なクライアントでは広くサポートされている[1]

脚注
  1. ブラウザが対応するSSL/TLS CipherSuite一覧によると2010年時点でもそこそこサポートされている ↩︎

KIDANI AkitoKIDANI Akito

p.35 鍵交換はServerKeyExchangeメッセージから開始
p.35 rsa、dh_rsaの場合にはServerKeyExchangeメッセージは送られない=必要な情報は他で手に入る
p.35 鍵交換パラメータとともに署名も送られる(認証方法がanonでない場合のみ、サーバの証明書の秘密鍵で署名):クライアントはサーバの真正性を検証できる

p.35 ClientKeyExchangeメッセージは常に必須

KIDANI AkitoKIDANI Akito

2.3.1 RSA鍵交換

p.36 クライアントが48バイトの乱数=プリマスターシークレットを生成、サーバの公開鍵で暗号化、ClientKeyExchangeメッセージで送信
p.36 TLSで利用されるRSA暗号化スキームはRSAES-PKCS1-v1_5(RFC3447 Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1[1]
p.36 前方秘匿性がない:簡単さゆえに、サーバの秘密鍵が漏洩するとプリマスターシークレットも漏洩し、セッションが乗っ取られる(リアルタイムでなくても通信を記録しておけばよい)

脚注
  1. 署名のためのスキームはRSASSA-PKCS1-v1_5など。RFC 8017 PKCS #1: RSA Cryptography Specifications Version 2.2で改訂されているが暗号スキームの方は変わってなさそう ↩︎

KIDANI AkitoKIDANI Akito

2.3.2 Diffie-Hellman鍵交換

p.37 安全でない通信路で共有の秘密鍵を確立するためのアルゴリズム:能動的攻撃(通信経路ののっとり)には脆弱なので認証と合わせて利用するのが一般的
p.37 逆方向の計算が非常に困難な数学の関数を利用:以下は簡易的な計算例[1]

dh_g 99
dh_p(素数) 13
dh_Ys 5
dh_Yc 6

S=dh_g^dh_Ys mod dh_p= 9509900499 mod 13=8
C=dh_g^dh_Yc mod dh_p=941480149401 mod 13 =12

C^dh_Ys mod dh_p = 248832 mod 13 =12
S^dh_Yc mod dh_p = 262144 mod 13 = 12

p.37 dh_g とdh_pをドメインパラメータ(またはDHパラメータ、グループパラメータ)と呼ぶ:サーバが選択し、ServerKeyExchangeメッセージで送信される
p.37 DHE(一時的DH、Ephemeral DH):前回のDH鍵交換で利用したパラメータを再利用しない
p.37 サーバおよびクライアント証明書に静的に埋め込まれたパラメータでDH鍵交換を行うこともできるが、同一鍵が使いまわされるため前方秘匿性がないため、TLSではまず使われない

DH鍵交換の問題点
p.38 DHパラメータのセキュリティ:サーバが選ぶパラメータの品質に依存する。弱いDHパラメータの場合、再ネゴシエーション時の脆弱性をつくトリプルハンドシェイク攻撃が可能(詳細は7.6節で後述)
p.38 DHパラメータ強度のネゴシエーションができない:DHパラメータがクライアントに受け入れられることを期待するしかない
p.38 不十分なDHパラメータ強度:2048ビット以上が強いが、かつては512ビットを利用しているサーバも珍しくなかった。2015年のLogjam攻撃は512ビットのDHパラメータをリアルタイムで破れることが判明。詳細は6.5節。

p.38 ネゴシエーションが可能になれば解消されるはず:テキスト脚注22のドラフトは2016年8月にRFC7919としてまとめられた[2]

脚注
  1. 実際にはもっと大きな値が利用される。参考:RFC3562 ↩︎

  2. Qiita TLSとDiffie-Hellmanグループパラメータ ↩︎

KIDANI AkitoKIDANI Akito

2.3.3 楕円曲線Diffie-Hellman鍵交換

p.39 ECDHE(一時的楕円曲線DH)の数学的基盤は楕円曲線[1]暗号[2]

p.39 理論上、一時的でない楕円曲線DHもあるが実際には利用されない
p.39 利用する楕円曲線を定義するのはサーバの役目(DHにおけるドメインパラメータと同じ役割):ServerKeyExchangeメッセージで送信(RFC8422で以下のように拡張されている)。

struct


      select (KeyExchangeAlgorithm) {
          ..(省略)..
          case ec_diffie_hellman:
              ServerECDHParams    params;
              Signature           signed_params;
      } ServerKeyExchange;


      enum { ecdsa } SignatureAlgorithm;  
      select (SignatureAlgorithm) {
          case ecdsa:
              digitally-signed struct {
                  opaque sha_hash[sha_size];
              };
      } Signature;
      ServerKeyExchange.signed_params.sha_hash
           SHA(ClientHello.random + ServerHello.random + ServerKeyExchange.params);

      struct {
           ECParameters    curve_params;
           ECPoint         public;
      } ServerECDHParams;

       struct {
           opaque point <1..2^8-1>;
       } ECPoint;

       struct {
           ECCurveType    curve_type;
           select (curve_type) {
               case named_curve:
                   NamedCurve namedcurve;
           };
       } ECParameters;

       enum {
           deprecated (1..2),
           named_curve (3),
           reserved(248..255)
       } ECCurveType;


       enum {
           deprecated(1..22),
           secp256r1 (23), secp384r1 (24), secp521r1 (25),
           x25519(29), x448(30),
           reserved (0xFE00..0xFEFF),
           deprecated(0xFF01..0xFF02),
           (0xFFFF)
       } NamedCurve;

楕円曲線

p.39 上記のようにサーバは名前つき曲線を指定する:これを受けてクライアントは以下のように公開パラメータを送信、その後それぞれがプリマスターシークレットを計算

       struct {
           select (KeyExchangeAlgorithm) {
               case ec_diffie_hellman: ClientECDiffieHellmanPublic;
           } exchange_keys;
       } ClientKeyExchange;

       struct {
           ECPoint ecdh_Yc;
       } ClientECDiffieHellmanPublic;

p.39 クライアントが対応する曲線をTLS拡張 elliptic_curvesで伝達する(ClientHelloメッセージ。RFC8422)詳細は2.12.3節。

脚注
  1. y^2=x^3+ax+bという方程式で定義される平面曲線としてあらわされる。Wikipedia ↩︎

  2. 楕円曲線上の離散対数問題 (EC-DLP) の困難性を安全性の根拠とする暗号。離散対数を計算する問題は整数の因数分解と以下の点が共通している:
    1.両方とも難しい(量子コンピュータ以外では効率的に解くアルゴリズムが得られていない)
    2.片方に対するアルゴリズムはしばしばもう片方にも利用できる
    3.問題の困難性が暗号系の構築に利用されている ↩︎

  3. https://asecuritysite.com/encryption/go_x448 ↩︎

KIDANI AkitoKIDANI Akito

2.4 認証

p.39 TLSでは認証と鍵交換が一体化:コストがかかる暗号処理の回数を減らすため
p.39 基本は証明書を利用した公開鍵暗号方式

RSAの場合
p.40 クライアントがランダム値を生成(=プリマスターシークレット):サーバの公開鍵で暗号化して送信(ClientKeyExchangeメッセージ)
p.40 秘密鍵をもつサーバだけがClientKeyExchangeメッセージを復号でき、マスターシークレットを生成して正しいFinishedメッセージを生成できる:暗黙的に認証完了

DHEおよびECDHEの場合
p.40 サーバの秘密鍵でパラメータに署名:クライアントは証明書から公開鍵を取得して、パラメータの出自を検証する
p.40 2.3.3 ECDHでみたように、パラメータ署名はClientHelloのRandomとServerHelloのRandomを利用する=ハンドシェイクごとに異なる。暗号化されずに署名が送られるが、再利用されることはない。ただし、弱い鍵の場合は事前計算によりLogjam攻撃が可能。

KIDANI AkitoKIDANI Akito

2.5 暗号化

p.40 多様な暗号化アルゴリズムでアプリケーションデータを暗号化:AES, 3DES, ARIA, CAMELLIA, RC4, SEEDなど

2.5.1 ストリーム暗号化方式

p.40 暗号化は2段階

  1. シーケンス番号+Recordヘッダ+平文を結合しMAC計算
  2. MACと平文を暗号化

p.40 RecordヘッダがMACに含まれる=暗号化されていないRecordヘッダが改竄されていないことを保障
p.40 シーケンス番号がMACに含まれる=リプレイ攻撃がないことを保障

2.5.2 ブロック暗号化方式

p.41 暗号化は5段階

  1. シーケンス番号、Recordヘッダ、平文データのMAC計算
  2. 暗号化前のデータに対しパディングを作る(通常16バイトの整数倍)
  3. 暗号化ブロックと同じ長さで初期化ベクター(IV)を生成(同じ平文でも違う暗号文を得るため)
  4. 平文データ、MAC、パディングをCBCモードで暗号化(Cipher Block Chaining、p.11
  5. IVと暗号文を一緒に送る

p.41 上記手順をMAC-then-encryptと呼ぶ:数多くの問題の元凶
p.41 TLS1.1以降ではレコードごとに明示的なIVが含まれる:TLS1.0以前は暗黙のIVを利用(前のTLSレコードを暗号化したブロックを次のIVとする)していたが、2011年に安全でないと判明(BEAST攻撃、7.2節参照)
p.41 パディングがMAC計算に含まれないため、パディングオラクル攻撃が可能(7.4節参照)
p.41 2014年9月、Encrypt-then-MACとよばれるTLS拡張が公開:平文データとパディングを暗号化し結果をMACに渡す

2.5.3 AEAD(認証付き暗号、Authenticated Encryption with Associated Data)

p.41 暗号化および完全性検証を1つのアルゴリズムにまとめた
p.41 ストリーム暗号化方式とブロック暗号化方式の折衷案

  1. 64ビットのナンス(nonce, 特別な乱数)を生成
  2. 平文を暗号化し、同時に完全性検証のためシーケンス番号とRecordヘッダも利用
  3. ナンスと暗号文を一緒に送る[1]

p.42 TLSで利用できる現在最良の暗号化利用モード:MAC-then-encryptの問題を回避できる
p.42 認証方式の選択肢としてGCMモード[2]およびCCMモード[3]が規程されているが、実際に利用可能なのはGCMのみ
p.42 AEADの新しい暗号スイートとしてChaCha20ストリーム暗号化方式に基づくものが標準化(RFC7905[4]

脚注
  1. ナンスの役割が分からん...... ↩︎

  2. Galois/Counter_Modeの略。暗号化利用モードのCTR(Counter)モードに認証としてGaloisモードを組み合わせたもの。並列計算が可能なため連鎖の必要なCBCモードより高速。2007年NISTが標準化。 ↩︎

  3. Counter with CBC-MACの略。CCMモードは128ビットブロック暗号に対してのみ定義されている。暗号のCTRモードと認証のCBC-MACモード。 ↩︎

  4. 2016年標準化。たとえばTLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256など。Poly1305は認証モード。 ↩︎

KIDANI AkitoKIDANI Akito

2.6 再ネゴシエーションrenegotiation

p.43 新しい接続のセキュリティパラメータの合意のため、改めてハンドシェイクを実行する。以下の場合に便利:

クライアント証明書

p.43 二要素認証の1つ。
p.43 全接続にクライアント証明書を要求すると不親切(クライアントがエラーを受け取れない)
p.43 トップページはクライアント証明書なしで許可する運用方法が好まれる
p.44 クライアント証明書が必要なページへのアクセスがあった場合に、サーバが再ネゴシエーションでクライアント証明書を要求する

情報の隠蔽

p.44 前述のように、二段階でクライアント証明書を有効にすると、2回目のハンドシェイクが暗号化される
p.44 つまり、クライアント証明書の盗聴、ネゴシエーションの監視といった受動的攻撃ができなくなる
p.44 Torの通信で利用されている方式[1]

暗号強度の変更

p.44 昔、Webサイトとの通信を暗号化するのが先進的だった時代は、暗号化強度を分割しているサイトがあった(前述のページによってクライアント証明書の要不要をきりかえるのと類似)

以下の2つの状況になる可能性は低い。

SGC: Server-Gated Crypto

p.44 1990年代に強い暗号技術を米国が輸出規制していた:アメリカだけが強い暗号を使えるようにする機能
p.44 デフォルトでは弱い暗号:限られたCAが発行するクライアント証明書をもつ場合のみ、再ネゴシエーションで強い暗号を利用できた
p.44 2000年の規制緩和でSGCは廃れた

TLSレコードのカウンタオーバーフロー

p.44 各レコードは64ビットのシーケンス番号が割り当てられる
p.44 オーバーフローしそうな場合は再ネゴシエーションするしかない(64ビットもあるのでほぼない)
p.45 クライアントが再ネゴシエーションしたい場合、ClientHelloを送る(Client-initiated Renegotiation)
p.45 サーバが再ネゴシエーションしたい場合、HelloRequestプロトコルメッセージを送る:クライアントはアプリケーションデータの送信を中止し、新しいハンドシェイクを開始

構造体

      struct { } HelloRequest;

p.45 もともと、再ネゴシエーションは能動的攻撃に悪用の恐れ:2009年に発見され(詳細は7.1節)[2]、renegotiation_info拡張の導入によって修正された[3]

脚注
  1. 諜報活動をオンラインで匿名で行うために米海軍が開発したネットワーク技術『The Onion Routing』をもとに、オープンソース・コミュニティーのプログラマーたちが海軍公認で開発を進めたもの。Torは主として接続経路を匿名化するものであり、通信内容の秘匿を保証するものではない。TCP通信は可能だが、UDP通信は現時点で不可能。参考:パソコン遠隔操作事件 ↩︎

  2. 中間者攻撃が可能になるらしい。 ↩︎

  3. とはいえ再ネゴシエーション周りは脆弱性が多そう。2021年でも、TLSらじお第2回でとりあげたOpenSSLの脆弱性がある。 ↩︎

KIDANI AkitoKIDANI Akito

2.7 Application Dataプロトコル

p.45 アプリケーションのデータを運ぶバッファ
p.45 セキュリティパラメータに従ってRecordプロトコルのレイヤでパッケージ化、細分化[1]、暗号化される

脚注
  1. p.25 レコードは最長16,384バイト(2^14):それより長い場合、分割される。逆に単一のレコードにまとめられることもある。https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-369ba9c2435126 ↩︎

KIDANI AkitoKIDANI Akito

2.8 Alertプロトコル

p.45 例外的な状況を伝える通知の仕組み
p.45 ほとんどはエラー:接続シャットダウンを通知するclose_notifyもある[1]

構造体(RFC5246)

      struct {
          AlertLevel level;
          AlertDescription description;
      } Alert;

      enum { warning(1), fatal(2), (255) } AlertLevel;

      enum {
          close_notify(0),
          unexpected_message(10),
          bad_record_mac(20),
          decryption_failed_RESERVED(21),
          record_overflow(22),
          decompression_failure(30),
          handshake_failure(40),
          no_certificate_RESERVED(41),
          bad_certificate(42),
          unsupported_certificate(43),
          certificate_revoked(44),
          certificate_expired(45),
          certificate_unknown(46),
          illegal_parameter(47),
          unknown_ca(48),
          access_denied(49),
          decode_error(50),
          decrypt_error(51),
          export_restriction_RESERVED(60),
          protocol_version(70),
          insufficient_security(71),
          internal_error(80),
          user_canceled(90),
          no_renegotiation(100),
          unsupported_extension(110),
          (255)
      } AlertDescription;

p.45 AlertDescriptionに任意の情報を入れる機能はない
p.45 深刻度がfatalの場合、現在の接続を即中断してセッションを無効化(同じセッションで進行中の接続は続く場合もあるが、再開はされない)
p.45 warningの場合、アラート送信側が接続を終えることはない(受信側はfatal扱いすることも)

脚注
  1. ネットワークファイアウォールなどで通信が遮断される場合、これがfatalで送信される ↩︎

KIDANI AkitoKIDANI Akito

2.9 接続を閉じる

p.45 接続を切断する場合close_notifyアラートを送る(SSL3.0で追加された、後述の強制切断攻撃対策)
p.45 受信側は書き込み中の内容を破棄し、自身もclose_nofityを送信:その後受け取ったメッセージは無視する
p.46 シャットダウンプロトコルが必要なのは、強制切断攻撃(truncation attack)への防御
p.46 強制切断攻撃に脆弱な実装は多数ある(6.7節によれば古いIEがそう)

KIDANI AkitoKIDANI Akito

2.10 暗号処理

2.10.1 疑似乱数生成器(Pseudorandom number generator / Pseudorandom function)

p.46 引数:シークレット、シード、一意なラベル
p.46 TLS1.2以降、暗号スイートでPRFを明示することが要求されている(TLS1.2(RFC5246)ではP_SHA256がデフォルト)[1]

p.46 TLS1.2のPRF:HMACとSHA256に基づく(暗号スイートに依らない)

PRF(secret, label, seed) = P_<hash>(secret, label + seed)

P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
                             HMAC_hash(secret, A(2) + seed) +
                             HMAC_hash(secret, A(3) + seed) + ...

      A(0) = seed
      A(i) = HMAC_hash(secret, A(i-1))

p.46 シードとラベルが異なるので同じシークレットでもマスターシークレット生成時と鍵生成時で出力が異なる

2.10.2 マスターシークレット

p.47 鍵交換によってプリマスターシークレットを得る:さらにPRFで処理し、48バイト(384ビット)のマスターシークレットを生成する

      master_secret = PRF(pre_master_secret, "master secret",
                          ClientHello.random + ServerHello.random)

p.47 マスターシークレットは事実上ランダムで、ハンドシェイクに紐づいている
p.47 根拠となっているのが交換した乱数値のみなので、これらの値を観察して複製すると同じマスターシークレットを共有する複数のセッションを生成できる(トリプルハンドシェイク攻撃、詳細は7.6節)

2.10.3 鍵生成

p.47 アプリケーションデータの通信に必要な鍵素材は以下のように生成される

      key_block = PRF(SecurityParameters.master_secret,
                      "key expansion",
                      SecurityParameters.server_random +
                      SecurityParameters.client_random);

p.47 鍵ブロックはネゴシエーションしたパラメータによって長さが異なる
p.47 鍵ブロックは6つに分割される:MAC鍵2つ、暗号鍵2つ、IVが2つ[2][3][4]

      client_write_MAC_key[SecurityParameters.mac_key_length]
      server_write_MAC_key[SecurityParameters.mac_key_length]
      client_write_key[SecurityParameters.enc_key_length]
      server_write_key[SecurityParameters.enc_key_length]
      client_write_IV[SecurityParameters.fixed_iv_length]
      server_write_IV[SecurityParameters.fixed_iv_length]

p.47 セッション再開時に、鍵ブロック生成の際に利用するマスターシークレットは以前のセッションと同じものを利用する。しかし、新しいハンドシェイクから乱数を取得するので、結果として鍵は異なるものになる。

脚注
  1. TLS1.3ではPRFがHKDFに置き換えられている模様。https://datatracker.ietf.org/doc/html/rfc8447#page-8HMAC-based Key Derivation Function↩︎

  2. ストリーム暗号化方式(ChaCha20など)ではIVは利用されない。AEAD(GCM、ChaCha20)ではMAC鍵を使わない。 ↩︎

  3. RFC5246)ではIVが生成されるのはAEADの場合のみで、nonce値として利用される。 ↩︎

  4. AES_256_CBC_SHA256スイートの場合、32バイトの暗号キー2つと32バイトのMACキー2つで合計128バイトとなる(RFC5246↩︎

KIDANI AkitoKIDANI Akito

2.11 暗号スイート

p.48 TLSはセキュリティプロトコルを作り出すためのフレームワーク:柔軟な実装ができる
p.48 以前のバージョンではプロトコルにハードコードされている要素技術もあった[1]
p.48 暗号スイートを規定する属性の例

  • 認証の種類:RSA、ECDSAなど
  • 鍵交換の種類:RSA、ECDHEなど
  • 暗号化アルゴリズム:AES、3DESなど
  • 暗号鍵の長さ:128、256など
  • 暗号化利用モード:CBC、GCMなど
  • MACアルゴリズム:SHA(SHA1)、MD5など
  • PRF(TLS1.2以降):SHA256、SHA384など
  • Finishedメッセージのハッシュ関数(TLS1.2以降)
  • verify_data構造体の長さ(TLS1.2以降)

RFC5246 Appendix C TLS1.2のCipherSuites一覧

TLS_DH_anon_WITH_AES_128_CBC_SHA256
TLS_DH_DSS_WITH_AES_256_CBC_SHA256 など

※GCM利用スイートはRFC5288で別途定義されている

      CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9C}
      CipherSuite TLS_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9D}
      CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = {0x00,0x9E}
      CipherSuite TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = {0x00,0x9F} など

p.48 名前から類推できないパラメータはRFCで定義されている
p.48 本書執筆時点(2017年?)で300のスイート:一覧はIANAのページ参照[2]

脚注
  1. TLS1.2以前は暗号化利用モードとしてCBCしか利用できなかった....はず ↩︎

  2. tls-parameters-4.csvがダウンロードできた。442行あったが、ざっと目視で40行ほどunassignedまたはreservedのものがあったので2021年5月末時点での総数は400程度と思われる。 ↩︎

KIDANI AkitoKIDANI Akito

p.49 AEAD(認証付き暗号、GCMoyobi
ChaCha20-Poly1305)の導入に伴い、MAC不要のスイートも登場:その場合、スイート末尾のSHA256などはPRFを指す
p.49 CCM(Counter with CBC-MAC)の場合PRFは省略されている
p.49 TLS1.2以前のスイートは、TLSバージョンによってPRFが異なる
p.49 例:TLS_RSA_WITH_AES_128_CBC_SHA

  • TLS1.2: HMAC-SHA256
  • TLS1.0, TLS1.1: HMAC-MD5/HMAC-SHA1の組み合わせ[1]

p.49 SHA1は選択的プレフィクス衝突攻撃に弱いことが知られているがHMAC-SHA1に対する既知の重大な攻撃はない
p.49 使えるスイートはサーバの持つ鍵の種類などにより制限される:RSA鍵しか持たない場合、ECDSAを使うスイートは対応できない
p.49 認証の強度は証明書・鍵の長さと署名アルゴリズムによって決まる:サーバ側で設定されるが、利用者に公開していないサーバもある

脚注
  1. TLS1.1のRFCによると PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) と排他的論理和を利用している ↩︎

KIDANI AkitoKIDANI Akito

2.12 TLS拡張Extensions

p.50 RFC3546(2003年)で定義[1]:TLS1.1で仕様に追加
p.50 拡張ブロックがClientHello/ServerHello Messageのあとに配置

RFC3546より

      struct {
          ProtocolVersion client_version;
          Random random;
          SessionID session_id;
          CipherSuite cipher_suites<2..2^16-1>;
          CompressionMethod compression_methods<1..2^8-1>;
          Extension client_hello_extension_list<0..2^16-1>;
      } ClientHello;

      struct {
          ProtocolVersion server_version;
          Random random;
          SessionID session_id;
          CipherSuite cipher_suite;
          CompressionMethod compression_method;
          Extension server_hello_extension_list<0..2^16-1>;
      } ServerHello;


      struct {
          ExtensionType extension_type;
          opaque extension_data<0..2^16-1>;
      } Extension;

      enum {
          server_name(0), max_fragment_length(1),
          client_certificate_url(2), trusted_ca_keys(3),
          truncated_hmac(4), status_request(5), (65535)
      } ExtensionType; // 2バイト

      enum {
          hello_request(0), client_hello(1), server_hello(2),
          certificate(11), server_key_exchange (12),
          certificate_request(13), server_hello_done(14),
          certificate_verify(15), client_key_exchange(16), finished(20),
          certificate_url(21), certificate_status(22), // 追加部分
          (255)
      } HandshakeType;

p.50 新しい機能に対応していることの表明+必要なデータを運搬する役割
p.50 プロトコルの進化を牽引
p.50 拡張の一覧はIANAのページ

脚注
  1. TLS1.0のリリースが1999年、TLS1.1が2006年、TLS1.2が2008年。 ↩︎

KIDANI AkitoKIDANI Akito

2.12.1 ALPN(Application-Layer Protocol Negotiation)

p.50 ポート443でデフォルトはHTTP1.1、ネゴシエーションしてSPDYやHTTP/2などが可能
p.50 application_layer_protocol_negotiation(0x10):クライアントが対応するプロトコル一覧を送る、レスポンスも同じ拡張
p.50 以前からあるNext Protocol Negotiation拡張と同様:NPNは暗号化されているが、ALPNは平文(ネットワーク機器が経路制御できるように)

RFC7301で定義されている。
ハンドシェイク中にネゴシエーションが完了するため、通信のラウンドトリップを削減できる。

KIDANI AkitoKIDANI Akito

2.12.2 CT(Certificate Transparency:証明書の透明性)

p.51 公開のログサーバにCA(認証局)が自身の証明書を登録する
p.51 ログサーバはSCT(Signed Certificate Timestamp)を登録証明としてCAに返送する
p.51 末端の利用者のツール上でSCTをチェック
p.51 SCTの転送方法の1つがsinged_certificate_timestamp拡張

RFC6962で定義されている

  • ExtensionTypeは18(0x12)
  • ClientHelloでextension_dataが空で送られる
  • ServerHelloで以下のデータがextension_dataにセットされる
        opaque SerializedSCT<1..2^16-1>;

        struct {
            SerializedSCT sct_list <1..2^16-1>;
        } SignedCertificateTimestampList;
  • セッションリザンプションでセッションが再開された場合、ClientHelloは通常時と同じだが、SeverHelloにはこの拡張は含まれない
KIDANI AkitoKIDANI Akito

2.12.3 楕円曲線の利用可能性

p.51 RFC4492 Elliptic Curve Cryptography (ECC) Cipher Suites for TLS
p.51 以下の2つの拡張が定義されている

     enum { elliptic_curves(10), ec_point_formats(11) } ExtensionType;

p.51 elliptic_curves:対応する名前付き曲線の名前のリストをClientHelloで送信[1][2]
p.52 ec_point_formats:楕円曲線上の点を圧縮するオプションをネゴシエーションできる(帯域の節約のため:とはいえ256ビットの曲線で64バイト程度の節約のため、圧縮されることは実際にはほとんどない)

p.52 RFC4492のNIST選定の楕円曲線はパラメータ選定基準が不明で、Dual_EC_DRBGにはバックドアがあることが判明している。
p.52 置き換えを目指してCurve25519、Curve448が標準化された(2018年、RFC8422)

脚注
  1. 楕円曲線DH鍵交換で見た通りhttps://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-46c09a05248899 ↩︎

  2. 名前付き楕円曲線は最適化されており処理が早いという利点がある。 ↩︎

KIDANI AkitoKIDANI Akito

2.12.4 Heartbeat(RFC6520

p.53 TLS/DTLS[1]向けのキープアライブ(死活確認)およびパスMTU探索[2]機能のプロトコル拡張
p.53 TCPにはキープアライブ機能があるので、これは主にUDPベースのDTLS向け
p.53 長さゼロのTLSレコードをキープアライブに使う案もある(プロトコルで許可されている、らしいがRFCのどの部分かはっきりせず...):PMTU探索ではペイロードを変化させる必要があるため両立不可

   enum {
      peer_allowed_to_send(1),
      peer_not_allowed_to_send(2),
      (255)
   } HeartbeatMode;

   struct {
      HeartbeatMode mode;
   } HeartbeatExtension;

   enum {
      heartbeat_request(1),
      heartbeat_response(2),
      (255)
   } HeartbeatMessageType;

   struct {
      HeartbeatMessageType type;
      uint16 payload_length;
      opaque payload[HeartbeatMessage.payload_length];
      opaque padding[padding_length];
   } HeartbeatMessage;

p.53 HeartbeatはTLSのサブプロトコル:他のプロトコルメッセージやアプリケーションデータと同時にやりとり可能
p.53 RFCはハンドシェイク完了時点でHeartbeatメッセージ許可:実際のところ、OpenSSLではTLS拡張やりとり直後から許可
p.53 2014年4月までは実際に使われているか不明だったが、Heartbleed攻撃が発覚(サーバのメモリ上にあるデータが抜き出される、詳細は6.3節)

脚注
  1. Datagram Transport Layer Security ↩︎

  2. Path Maximum Transmission Unit:1回の転送で送信できるデータ長の最大値。パケットがホップする場合、有効な値を探索する必要がある。イーサネットでは1500バイトだが、ユーザー認証などのためPPPoEを使うとカプセル化で8バイト使うため、1492バイトとなる。Wikipediaより ↩︎

KIDANI AkitoKIDANI Akito

2.12.5 Next Protocol Negotiation

p.54 GoogleがSPDYプロトコルを広める際に必要となり追加された拡張、ChromeだけでなくFirefox、OpenSSLが対応していた。
p.54 標準化を目指していたが、最終的には前述のALPNが採用された(2014年)

  • 新しいハンドシェイクメッセージの導入により通常のハンドシェイクフローに変更が必要となり、破壊的で混乱を招くとされたため。
  • 経路上のネットワーク機器がネゴシエーションされるプロトコルが把握できないことによる問題も懸念された(ので平文のALPNが採用された)

p.54 NPNはバージョン違いの仕様がある:2010年の012011年の022012年の032012年の04
p.54 実際に使われているのは2011年の古いバージョン

ハンドシェイク

p.54 SPDYが有効なクライアントは空のnext_protocol_negotiation拡張と接続したいホストを示すserver_name拡張をClientHelloで送る
p.54 ServerHelloには対応しているプロトコル一覧がnext_protocol_negotiation拡張で返る
p.54 NextProtocolハンドシェイクメッセージは以下の構造体で、接続に使いたいプロトコルを示す

struct {
  opaque selected_protocol<0..255>;
  opaque padding<0..255>;
} NextProtocol;

p.54 クライアントを受動的攻撃から守るためNextProtocolは暗号化して送られる:ChangeCipherSpecのあと、Finishedの前
p.54 パディングを使って選択したプロトコルを推測されないようにしている

KIDANI AkitoKIDANI Akito

2.12.6 安全な再ネゴシエーション(RFC5764、2010年

p.55 過去にハンドシェイクを確立した二者間の再ネゴシエーションを検証するための拡張

p.55 最初のハンドシェイクでデータなしでrenegotiation_info (extension type 0xff01 [65281])を送信し合う
p.55 SSL3.0では非対応: TLS_EMPTY_RENEGOTIATION_INFO_SCSV[1]という特別な暗号スイート[2]をクライアントが利用(これもRFC5764で定義。ClientHelloのcipher_suitesにTLS_EMPTY_RENEGOTIATION_INFO_SCSVを追加してメッセージを送信するだけ)

      struct {
          opaque renegotiated_connection<0..255>;
      } RenegotiationInfo;

p.55 再ネゴシエーションのハンドシェイクでは、以前のハンドシェイクのFinishhedメッセージのverify_dataを送る
p.55 クライアントは自身が送信したverify_dataを送る[3](暗号化されているため攻撃者は取得できない)
p.55 サーバはクライアントのverify_dataと自信が送信したverify_dataを送る[4]

脚注
  1. Signaling Cipher Suite Value。 ↩︎

  2. IANAのリストにも載っている。 ↩︎

  3. TLS1.2では12バイト。SSL3.0の場合は36バイトとなる。 ↩︎

  4. TLS1.2では合計24バイト。SSL3.0の場合は72バイト。この拡張の256バイト制限を考慮すると、verify_dataの長さは暗号スイートによっては128バイトまで利用可能、ということだろうか? ↩︎

KIDANI AkitoKIDANI Akito

2.12.7 SNI(Server Name Indication)

p.55 2003年のRFC3546で提案され2006年にTLS1.1からTLSに追加(初期のTLS拡張の一つ)
p.55 server_name拡張:ClientHelloに含まれる
p.55 同じネットワークアドレスで複数の仮想サーバに安全に接続できるようになる:サーバに該当の証明書を見つけさせる

extension_dataはServerNameList

      struct {
          NameType name_type;
          select (name_type) {
              case host_name: HostName;
          } name;
      } ServerName;

      enum {
          host_name(0), (255)
      } NameType;

      opaque HostName<1..2^16-1>;

      struct {
          ServerName server_name_list<1..2^16-1>
      } ServerNameList;

p.55 SNI未対応の製品:Windows XP、Androidの初期バージョンなど[1][2]

脚注
  1. 2011年2月リリースのAndroid 3.0の標準ブラウザは対応している。https://knowledge.sakura.ad.jp/1706/ ↩︎

  2. Javaの場合、2011年7月リリースのJava 7から対応している。https://docs.oracle.com/javase/7/docs/technotes/guides/security/enhancements-7.html ↩︎

KIDANI AkitoKIDANI Akito

2.12.8 セッションチケット(2008年のRFC5077

p.55 サーバ側でセッション情報を保持せずセッション再開可能にする拡張:暗号化したチケットとチケット鍵をクライアントに送る
p.55 Webサーバ間でセッションの同期が不要になるので、クラスタの大規模化が容易になるかも
p.56 チケット鍵の強度が重要:実装によっては接続のための暗号より弱い場合もある。
p.56 OpenSSLは128ビットのAES鍵を利用し、同一チケット鍵が複数セッションで再利用される:チケット鍵を周期的に交換しなければならない
p.56 session_ticket拡張:クライアントは最初、空の拡張を送信。2回目はチケットを送信。
p.56 対応しているサーバはServerHelloに空の拡張を送信。Finishedメッセージのあとに、チケットをNewSessionTicketハンドシェイクメッセージ(新規追加された)に格納して送信。

     struct {
          HandshakeType msg_type;
          uint24 length;
          select (HandshakeType) {
              case hello_request:       HelloRequest;
              case client_hello:        ClientHello;
              case server_hello:        ServerHello;
              case certificate:         Certificate;
              case server_key_exchange: ServerKeyExchange;
              case certificate_request: CertificateRequest;
              case server_hello_done:   ServerHelloDone;
              case certificate_verify:  CertificateVerify;
              case client_key_exchange: ClientKeyExchange;
              case finished:            Finished;
              case session_ticket:      NewSessionTicket; /* NEW */
          } body;
      } Handshake;

      struct {
          uint32 ticket_lifetime_hint;
          opaque ticket<0..2^16-1>;
      } NewSessionTicket;

      struct {
          opaque key_name[16];
          opaque iv[16];
          opaque encrypted_state<0..2^16-1>;
          opaque mac[32];
      } ticket;

     /* encrypted_stateの暗号化前 */
      struct {
          ProtocolVersion protocol_version;
          CipherSuite cipher_suite;
          CompressionMethod compression_method;
          opaque master_secret[48];
          ClientIdentity client_identity;
          uint32 timestamp;
      } StatePlaintext;

      enum {
         anonymous(0),
         certificate_based(1),
         psk(2)
     } ClientAuthenticationType;

      struct {
          ClientAuthenticationType client_authentication_type;
          select (ClientAuthenticationType) {
              case anonymous: struct {};
              case certificate_based:
                  ASN.1Cert certificate_list<0..2^24-1>;
              case psk:
                  opaque psk_identity<0..2^16-1>;   /* from [RFC4279] */
          };
       } ClientIdentity;

p.56 サーバがセッションチケットでセッション再開する場合、ServerHelloのSession IDフィールドを空で送る:クライアントがセッションIDを生成してもよく、その場合サーバが同じIDで応答する。

KIDANI AkitoKIDANI Akito

2.12.9 署名アルゴリズム(RFC5246=TLS1.2

p.56 signature_algorithms拡張:対応している署名アルゴリズムとハッシュ関数をクライアントが伝える。
p.56 署名アルゴリズム:RSA、DSA、ECDSA
p.56 ハッシュ関数:MD5、SHA1、SHA224、SHA256、SHHA384、SHA512
p.56 拡張なので必須ではない:サーバは暗号スイートを元に署名アルゴリズムを推察する

  • 鍵交換アルゴリズムがRSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA:SHA1またはRSA
  • 鍵交換アルゴリズムがDHE_DSS, DH_DSS:SHA1またはDSA
  • 鍵交換アルゴリズムがECDH_ECDSA, ECDHE_ECDSA:SHA1またはECDSA

RFC5246 7.4.1.4.1. Signature Algorithms

      enum {
          signature_algorithms(13), (65535)
      } ExtensionType;

      /* extension_dataはsupported_signature_algorithms */

      enum {
          none(0), // 将来のハッシュ化不要な署名アルゴリズム用
          md5(1), sha1(2), sha224(3), sha256(4), sha384(5),
          sha512(6), (255)
      } HashAlgorithm;

      enum { anonymous(0), // この拡張で使ってはいけない(DH_anonとか用)
       rsa(1), dsa(2), ecdsa(3), (255) }
        SignatureAlgorithm;

      struct {
            HashAlgorithm hash;
            SignatureAlgorithm signature;
      } SignatureAndHashAlgorithm;

      SignatureAndHashAlgorithm
        supported_signature_algorithms<2..2^16-2>;

セッションリザンプションの際にClientHelloに含まれていた場合は無視される(すでに合意済みのため)

KIDANI AkitoKIDANI Akito

2.12.10 OCSPステープル(RFC4366、およびRFC6066

p.56 status_request拡張(0x05):クライアントがOCSPステープリングに対応していることを示す
p.56 OCSPステープル:サーバからクライアントに証明書の失効情報を送る(失効については5.11節)

ClientHello"extension_data"は"CertificateStatusRequest"

      struct {
          CertificateStatusType status_type;
          select (status_type) {
              case ocsp: OCSPStatusRequest;
          } request;
      } CertificateStatusRequest;

      enum { ocsp(1), (255) } CertificateStatusType;

      struct {
          ResponderID responder_id_list<0..2^16-1>;
          Extensions  request_extensions;
      } OCSPStatusRequest;

      opaque ResponderID<1..2^16-1>;
      opaque Extensions<0..2^16-1>;

p.56 (RFC4366/6066で追加された)CertificateStatusハンドシェイクメッセージでOCSPレスポンス(DER形式)[1]を提示(1つしか送れない)

      struct {
          CertificateStatusType status_type;
          select (status_type) {
              case ocsp: OCSPResponse;
          } response;
      } CertificateStatus;

      opaque OCSPResponse<1..2^24-1>;

p.57 status_request_v2拡張(RFC6961):複数のOCSPレスポンスに対応(2016/7年あたりではクライアント、サーバともにあまりサポートされていない)

     struct {
       CertificateStatusType status_type;
       uint16 request_length; /* Length of request field in bytes */
       select (status_type) {
         case ocsp: OCSPStatusRequest;
         case ocsp_multi: OCSPStatusRequest; // 追加された複数対応
       } request;
     } CertificateStatusRequestItemV2;

     enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;

     struct {
       ResponderID responder_id_list<0..2^16-1>;
       Extensions request_extensions;
     } OCSPStatusRequest;

     opaque ResponderID<1..2^16-1>;
     opaque Extensions<0..2^16-1>;

     struct {
       CertificateStatusRequestItemV2
                        certificate_status_req_list<1..2^16-1>;
     } CertificateStatusRequestListV2;
     struct {
       CertificateStatusType status_type;
       select (status_type) {
         case ocsp: OCSPResponse;
         case ocsp_multi: OCSPResponseList;
       } response;
     } CertificateStatus;

     opaque OCSPResponse<0..2^24-1>;

     struct {
       OCSPResponse ocsp_response_list<1..2^24-1>;
     } OCSPResponseList;
脚注
  1. RFC2560Rubyのリファレンス ↩︎

KIDANI AkitoKIDANI Akito

2.13 プロトコルの限界

p.57 TLSには意図しない弱点や、OSIレイヤや設計方針に由来する制限がある
p.57 TCPは平文なので送信元と宛先のIPアドレスは判別可能
WiresharkでIPアドレスを確認できる

p.57 TLSでも多くの情報は平文(特に最初のハンドシェイク):回避策はあるが採用されていない

  • クライアントのブラウザーフィンガープリント
  • SNI情報
  • ホスト/クライアントの証明書

p.57 暗号化が有効でも観察できる情報:サブプロトコルや各メッセージの長さ
例)リクエストとレスポンスからHTTPでどのリソースにアクセスしているか推測可能[1]

脚注
  1. 2009年くらいの研究を見つけた:George Danezis, Traffic Analysis of the HTTP Protocol over TLSによれば、暗号化されたリクエストからリソースを絞り込むことはできるし、Referrerヘッダーなども参照してユーザーの興味関心を知ることができる。サーバーからのレスポンスも、公開されているサイトならば攻撃者は事前に知ることができるので、ユーザーがどこにアクセスしているか推測可能。 ↩︎

KIDANI AkitoKIDANI Akito

2.14 プロトコルのバージョンによる相違

p.57 SSL3.0(1995年):以降プロトコルの中核はそれほど変更なし
p.57 TLS1.0(1999年):名前の修正のみ
p.57 TLS1.1(2006年):セキュリティ上の問題修正
p.57 TLS1.2(2008年):AEADの導入、ハッシュ関数の一掃、ハードコードされたプリミティブの除去

2.14.1 SSL3.0

p.58 スクラッチから開発された
p.58 詳細な変更はAnalysis of the SSL 3.0 protocol, 1997

2.14.2 TLS1.0

p.58 HMACによってPRFが規定される(HMAC-MD5とHMAC-SHA1の排他的論理和)[1]
p.58 マスターシークレットがPRFによって生成されるようになった
p.58 Finishedメッセージのverify_dataの値がPRFによって生成されるようになった
p.58 MACにおいて標準化されたHMACを利用(SSL3.0は古いバージョンを利用)
p.58 パディングのフォーマットが強固に(SSL3.0のパディングは2014年のPOODLE攻撃の対象)
p.58 暗号スイートからFORTEZZA[2]が除外

p.58 TLS1.0はFIPS認証取得:アメリカ政府機関で利用可能に
p.58 プロトコル設計方針については『マスタリングTCP/IP SSL/TLS編』が詳しい

2.14.3 TLS1.1

p.58 CBC暗号化利用モードで明示的なIVを利用(のちのBEAST攻撃で悪用される問題への対処)[3]
p.58 パティング攻撃への防御:bad_record_macアラート(20)[4]
p.58 TLS拡張の参照(RFCではClientHelloのstructに含まれず)

2.14.4 TLS1.2

p.59 AEADのサポート
p.59 HMAC-SHA256暗号スイートのサポート
p.59 IDEAおよびDES暗号スイートの除外
p.59 主要なTLS拡張が組み込まれた(RFCでもClientHelloのstructにExtensionが追加された)
p.59 signature_algorithms拡張でクライアントの希望アルゴリズムを伝達可能
p.59 PRF、ディジタル署名がMD5+SHA1からSHA256に。暗号スイートが独自のハッシュ関数を指定することも可能。
p.59 Finishedメッセージのverify_dataの長さを暗号スイートで明示的に指定可能

脚注
  1. 2.11 暗号スイート https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-c1840870a17ff2 ↩︎

  2. アメリカ政府が利用していたPCカードを利用したハードウェアベースの暗号標準。暗号化アルゴリズムにSKIPJACKというブロック暗号を利用していたが、機密扱いで詳細が公表されなかったため、IETFが標準化を拒んだためTLSで除外された。『マスタリングTCP/IP SSL/TLS編』pp.118-119 ↩︎

  3. 2.5 暗号化 https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-6e19c7679b29ce ↩︎

  4. 2.8 アラートプロトコル https://zenn.dev/kdnakt/scraps/1146d7c00cd3ce#comment-d84dd400d77a97 ↩︎

KIDANI AkitoKIDANI Akito

第3章 公開鍵基盤

p.61 Public Key Infrastructure(PKI)

  • 会ったことがない相手と安全に通信する
  • 公開鍵を保管・失効する
  • 世界規模で使える:数百万のサーバ、数十億のデバイス

3.1 インターネットPKI

p.61 もともとはインターネット用ではなかったPKI[1]
p.61 Web PKI:ブラウザにおける証明書利用・検証に主眼
p.61 現在のPKI:信頼のおける第三者機関であるCA(Certificate Authority、認証局)[2]が発行する証明書を無条件に信頼するモデル

p.62 証明書所有者(Subscriber):エンドエンティティ(End-Entity)ともよぶ
p.62 登録局(RA, Registration Authority):本人性の検証が仕事。実際にはCAがRAを兼ねる。
p.62 認証局(CA, Certificate Authority):証明書所有者の本人性を保証する証明書を発行する。証明書の失効情報をオンラインで提供する。
p.62 証明書利用者(Relying party):厳密には、証明書を検証するのはWebブラウザなどのプログラムやOS。プログラムやOSは、トラストアンカー(デフォルトのルート証明書)を含むルートトラストストアを利用する。

脚注
  1. Wikipediaによると1970年台前半にイギリスのGCHQで開発されたが、1990年代まで公開されなかった。 ↩︎

  2. GlobalSignDigiCertなどがある ↩︎

KIDANI AkitoKIDANI Akito

p.63 信頼(trust):証明書がトラストストアに含まれるCAのルート証明書によって検証し得る、という意味
p.63 本人性(identity):正しいサーバである、というだけ。オフラインの本人性はEV証明書でないと得られない[1]

脚注
  1. EV(Extended Validation)証明書。SSL証明書にはDV(Domain Validation)、OV(Organization Validation)、EVの3種類があり、その中で最も厳格な審査方式を採用しているのがEV。EV証明書の企業名表示は、2018年9月にリリースされたChrome 77よりアドレスバーに表示されないよう仕様変更された。 ↩︎

KIDANI AkitoKIDANI Akito

3.2 証明書の標準

p.63 X.509:公開鍵基盤の国際標準(詳細はCertificateハンドシェイクメッセージの項を参照)、元々は電子ディレクトリサービス向け。
p.63 RFC5280:X.509をベースにPKIXワーキンググループがインターネットでの利用に適した仕組みにしたもの。主に以下を規定。

  • 証明書のフォーマット
  • 信頼パス(trust path)
  • 証明書失効リスト(CRL、Certificate Revocation List)

p.64 CA/Browser Forum (CAB Forum):証明書の発行および処理の標準を確立、徹底することに関心を持つCAやブラウザベンダーを中心とした団体。2007年〜。
p.64 Baseline Requirements:正式名称はBaseline Requirements for the Issuance and Management of Publicly-Trusted Certificates。2012年発表、以後定期的にアップデートされている[1][2]
p.64 CABフォーラムには2021年6月現在で、51のCAが参加している[3]
p.64 Baseline Requirementsは事実上すべてのCAに適用される:BRがCA向け監査プログラムであるWebTrustに組み込まれており、ルートトラストストアの運営元(Mozillaなど)が明示的にBRを要求するため。

脚注
  1. 2021年6月3日にバージョン1.7.6が公開された。 ↩︎

  2. これに関連して、先日GlobalSign社からSSLサーバ証明書のドメイン認証情報の再利用期間短縮のお知らせが発表された。再利用期間を825日から397日に短縮するというもの。これはBaselime Requirements 1.7.5での変更による。おそらく、2020年9月より証明書の有効期限を398日間以上にすることを禁じたことと関連すると思われる。 ↩︎

  3. Androidには100以上のCAのルート証明書が登録されているらしい。Wikipediaより ↩︎

KIDANI AkitoKIDANI Akito

3.3 証明書

p.64 証明書には、公開鍵、公開鍵に紐づけられた主体に関する情報、証明書発行主体のディジタル署名が含まれる
p.64 証明書はPKIの基本的な構成要素

p.64 ASN.1(Abstract Syntax Notation 1、抽象構文記法1):複雑なデータ構造やオブジェクトの定義、転送、交換のためのルール集。様々なプラットフォーム間でのネットワーク通信の手段として、実装に依存しない形で設計された。1998年に規定、2008年に更新。
p.64 ASN.1のエンコード方法はBERなどの標準がある。
p.64 BER(Basic Encoding Rules)のサブセットのDER(Distinguished Encoding Rules)がX.509では利用される
p.64 DERをBase64でエンコードするとPEM(Privacy-Enhanced Mail)になる
p.65 証明書はPEM形式がほとんどだが、一部DER形式のものも。

Amazonのルート証明書(Amazon Root CA 1)をASN.1デコーダーでデコードした結果。

KIDANI AkitoKIDANI Akito

p.65 Version(バージョン):バージョン1(0)、バージョン2(1)、バージョン3(2)がある。

  • バージョン1:基本的なフィールドのみ[1]
  • バージョン2:一意の識別子が加わる[2]
  • バージョン3:拡張が利用可能となった

p.65 Serial Number(シリアル番号):あるCAの発行した証明書を一意に区別する番号。かつては連番の正の整数が利用されたが、選択プレフィクス衝突攻撃の防止のため、現在は予測不能な値を利用する。
p.65 Signature Algorithm(署名アルゴリズム):署名によって保護できるよう証明書内部に格納。
p.65 Issuer(発行者):主体の識別名(DN, Distinguished Name)。国(Country)、組織(Organization)、部門(Organizational-Unit)の3つから成る。
p.65 Validity(有効性):開始日と終了日の2つの日付で表される。
p.65 Subject(主体者):公開鍵にひもづく団体の識別名が格納される。自己署名証明書の場合、Issuerと同じ。かつてはCommonNameがサーバのホスト名として使われたが、複数ホストの場合に問題があるため現在では代わりにSAN拡張(Subject Alternative Name)が利用される
p.66 Public Key(公開鍵):Subject Public-Key Info構造体で示される(アルゴリズムの識別子+公開鍵)

※バージョン2で追加された一意の識別子は利用されず、バージョン3ではAuthority Key Identifierおよび
Subject Key Identifier拡張が利用される。

脚注
  1. RFC1422によれば、次の7つ:version, serial number, signature (algorithm ID and parameters), issuer name, validity period, subject name, subject public key (and associated algorithm ID)。 ↩︎

  2. Wikipediaによれば、issuer unique identifier / subject unique identifierが追加された。 ↩︎

KIDANI AkitoKIDANI Akito

3.3.2 証明書の拡張

p.66 バージョン3で導入:フォーマットに柔軟性を持たせるため
p.66 拡張=識別子(OID、Object Identifier)+重要度(critical)+値(ASN.1構造体)

Extension  ::=  SEQUENCE  {
        extnID      OBJECT IDENTIFIER,
        critical    BOOLEAN DEFAULT FALSE,
        extnValue   OCTET STRING
                    -- contains the DER encoding of an ASN.1 value
                    -- corresponding to the extension type identified
                    -- by extnID
        }

p.66 criticalな拡張は正しく処理できない場合、証明書ごと破棄することになっている

p.66 Subject Alternative Name(主体者の別名):単一のホスト名しか指定できない基本のSubject(主体者)フィールドにかわって、DNS名やIPアドレスやURIによって示される複数の主体を公開鍵に紐づけられる。

   id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }

   SubjectAltName ::= GeneralNames

   GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName

   GeneralName ::= CHOICE {
        otherName                       [0]     OtherName,
        rfc822Name                      [1]     IA5String,
        dNSName                         [2]     IA5String,
        x400Address                     [3]     ORAddress,
        directoryName                   [4]     Name,
        ediPartyName                    [5]     EDIPartyName,
        uniformResourceIdentifier       [6]     IA5String,
        iPAddress                       [7]     OCTET STRING,
        registeredID                    [8]     OBJECT IDENTIFIER }

   OtherName ::= SEQUENCE {
        type-id    OBJECT IDENTIFIER,
        value      [0] EXPLICIT ANY DEFINED BY type-id }

   EDIPartyName ::= SEQUENCE {
        nameAssigner            [0]     DirectoryString OPTIONAL,
        partyName               [1]     DirectoryString }

p.66 Name Constraints(名前制約):CAが証明書を発行できる主体を制限するのに利用。たとえば、下位のCAを設置して自社ドメインに対してのみ証明書を発行できるようにする、など。RFC5280ではName Constraintsをcriticalな拡張としているが、実際にはcriticalに設定せずに利用されることもある。

KIDANI AkitoKIDANI Akito

p.67 Basic Constraints(基本制約):CA証明書かどうかを示す。同時に、下位CAの証明書パスの深さを制御する。すべてのCA証明書はこれを含まなければならないが、2016/17年当時はまだバージョン1で拡張のないルート証明書もあった[1]

   id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }

   BasicConstraints ::= SEQUENCE {
        cA                      BOOLEAN DEFAULT FALSE,
        pathLenConstraint       INTEGER (0..MAX) OPTIONAL }



脚注
  1. 手元のmacOS Catalina 10.15.7のキーチェーンアクセスをざっと確認したところ、バージョン1の証明書は見つからなかった(シリアル番号が1のものはいくつか見つかった) ↩︎

KIDANI AkitoKIDANI Akito

p.67 Key Usage(鍵用途):この証明書に含まれる鍵の用途を示す。

id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }

KeyUsage ::= BIT STRING {
     digitalSignature        (0), // ディジタル署名
     nonRepudiation          (1),  // 否認防止
     keyEncipherment         (2), // 鍵暗号
     dataEncipherment        (3), // データ暗号
     keyAgreement            (4), // 鍵交換
     keyCertSign             (5), // 電子証明書の検証
     cRLSign                 (6), // CRLの署名検証
     encipherOnly            (7), // 鍵交換時のデータ暗号用
     decipherOnly            (8) } // 鍵交換時のデータ復号用

KIDANI AkitoKIDANI Akito

p.67 Extended Key Usage(鍵拡張用途):任意の用途をOIDを利用して追加で指定できる。

   id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }

   ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId

   KeyPurposeId ::= OBJECT IDENTIFIER

-- extended key purpose OIDs

id-kp-serverAuth             OBJECT IDENTIFIER ::= { id-kp 1 }
id-kp-clientAuth             OBJECT IDENTIFIER ::= { id-kp 2 }
id-kp-codeSigning            OBJECT IDENTIFIER ::= { id-kp 3 }
id-kp-emailProtection        OBJECT IDENTIFIER ::= { id-kp 4 }
id-kp-timeStamping           OBJECT IDENTIFIER ::= { id-kp 8 }
id-kp-OCSPSigning            OBJECT IDENTIFIER ::= { id-kp 9 }

p.67 RFC5280ではエンドエンティティ用証明書に対してのみEKU拡張を利用すべきとされているが、実際には中間CAの証明書の用途制限にも利用[1]


脚注
  1. つまりどういうこと? ↩︎

KIDANI AkitoKIDANI Akito

p.67 Certificate Policy(証明書ポリシー):1つまたは複数のポリシーを示すOIDと、オプションでポリシー全文を示すURL。

   id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }

   anyPolicy OBJECT IDENTIFIER ::= { id-ce-certificatePolicies 0 }

   certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation

   PolicyInformation ::= SEQUENCE {
        policyIdentifier   CertPolicyId,
        policyQualifiers   SEQUENCE SIZE (1..MAX) OF
                                PolicyQualifierInfo OPTIONAL }

   CertPolicyId ::= OBJECT IDENTIFIER

   PolicyQualifierInfo ::= SEQUENCE {
        policyQualifierId  PolicyQualifierId,
        qualifier          ANY DEFINED BY policyQualifierId }

p.67 Baseline Requirementsではエンドエンティティ用証明書にはポリシーを最低1つ含め、BR準拠であることを示すべしとしている。
p.67 この拡張を用いて証明書の検証の種類を指定できる[1]

脚注
  1. RFCをざっくり読んだがどこの話かよくわからず... ↩︎

KIDANI AkitoKIDANI Akito

p.67 CRL Distribution Points(CRL配布点):証明書失効リスト(CRL)の場所を示す。通常、LDAPやHTTPのURIで示される。
p.67 Baseline RequirementsではCRLかOCSPいずれかで失効情報を示すこととなっている

   id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::=  { id-ce 31 }

   CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint

   DistributionPoint ::= SEQUENCE {
        distributionPoint       [0]     DistributionPointName OPTIONAL,
        reasons                 [1]     ReasonFlags OPTIONAL,
        cRLIssuer               [2]     GeneralNames OPTIONAL }

   DistributionPointName ::= CHOICE {
        fullName                [0]     GeneralNames,
        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }

このURLにアクセスするとバイナリが返ってくるためcurlで直接表示はできない。以下のようにopensslを利用する。

$ curl http://crls.pki.goog/gts1d4/E0jY99efK8g.crl | openssl crl -inform der -text
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 77323  100 77323    0     0  2288k      0 --:--:-- --:--:-- --:--:-- 2359k
Certificate Revocation List (CRL):
        Version 2 (0x1)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: /C=US/O=Google Trust Services LLC/CN=GTS CA 1D4
        Last Update: Jul  4 07:22:28 2021 GMT
        Next Update: Jul 14 06:22:27 2021 GMT
        CRL extensions:
            X509v3 Authority Key Identifier: 
                keyid:25:E2:18:0E:B2:57:91:94:2A:E5:D4:5D:86:90:83:DE:53:B3:B8:92

            X509v3 CRL Number: 
                772
            X509v3 Issuing Distribution Point: critical
                Full Name:
                  URI:http://crls.pki.goog/gts1d4/E0jY99efK8g.crl
                Only User Certificates

Revoked Certificates:
    Serial Number: 02470B5B0FC19F5A09000000005DD138
        Revocation Date: Mar 29 09:04:14 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Cessation Of Operation
    Serial Number: FB9AA96CC279D675090000000076FACD
        Revocation Date: Jun 26 11:56:32 2021 GMT
    Serial Number: 55DA994202A25FB50A00000000EA2A6D
        Revocation Date: Jun 26 11:17:45 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Cessation Of Operation
    Serial Number: 0EFD60DB5C7C8635090000000076F9BD
        Revocation Date: Jun 26 19:19:55 2021 GMT
        CRL entry extensions:
            X509v3 CRL Reason Code: 
                Cessation Of Operation
...(以下大量に表示されたので省略)
KIDANI AkitoKIDANI Akito

p.68 Authority Information Access(認証機関アクセス情報):証明書を発行したCAの付加的な情報やサービスへのアクセス情報を示す。下記のように、リアルタイムで失効情報を確認するためのOCSPレスポンダのURLなど。他に、発行者の証明書を発見できるURLも(不完全な証明書チェーンの再構築に役立つ)。

   id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }

   AuthorityInfoAccessSyntax  ::=
           SEQUENCE SIZE (1..MAX) OF AccessDescription

   AccessDescription  ::=  SEQUENCE {
           accessMethod          OBJECT IDENTIFIER,
           accessLocation        GeneralName  }

   id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }

   id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }

   id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }

KIDANI AkitoKIDANI Akito

p.68 Subject Key Identifier(主体者鍵識別子):特定の公開鍵を含む証明書を区別するための識別子。公開鍵のハッシュ値などが識別子として推奨される。CA証明書はすべてこの拡張を含まねばならないし、この値が発行済み証明書のAuthority Key Identifier(機関鍵識別子)と同じでなくてはならない。

id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }

SubjectKeyIdentifier ::= KeyIdentifier

p.68 Authority Key Identifier(機関鍵識別子):証明書に対する署名鍵を一意に特定する。証明書パスを構築するために使われる。

   id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }

   AuthorityKeyIdentifier ::= SEQUENCE {
      keyIdentifier             [0] KeyIdentifier           OPTIONAL,
      authorityCertIssuer       [1] GeneralNames            OPTIONAL,
      authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }

   KeyIdentifier ::= OCTET STRING



KIDANI AkitoKIDANI Akito

p.68 その他のRFC 5280拡張(あまり使われない)

  • Delta CRL Distribution Point(Freshest CRLとも)
  • Inhibit anyPolicy
  • Issuer Alternative Name
  • Policy Constraints
  • Policy Mappings
  • Subject Directory Attributes
  • Subject Information Access
KIDANI AkitoKIDANI Akito

3.4 証明書チェーン

p.68 証明書の検証にはエンドエンティティの証明書だけでは不十分:信頼の起点となるルート証明書へのチェーンが必要

【ルートを安全に保つ】
p.69 ルートCAの鍵はPKIのエコシステム全体にとってとても重要:ルートトラストストアの多くは更新されず、古くからの鍵は事実上替えが効かない
p.69 Baseline Requirementsでは、ルート鍵を使う場合手作業が要求される(自動化しない)
p.69 いくつかのCAはルート証明書を直接使ってエンドエンティティの証明書を発行しているが、そうしたやり方は認められていない

【相互認証証明書(Cross-certification)】
p.69 新しくCAの運用を開始する場合の唯一の方法:相互認証
p.69 新しいCAのルート鍵が広範囲に配布されるのには時間がかかるので、他のルート鍵で署名してもらう(古いデバイス向け)[1]

【区画化(Compartmentalization)】
p.69 下位CA(非ルートCA)は証明書発行を自動化、オンライン化
p.69 CAのリスク回避として、下位CAを複数に分割する:例)証明書のクラス、ビジネス部門などで分割[2]

【委譲(Delegation)】
p.69 CAが自分たちと関連のない別組織を下位CAにすることもある:大企業がプライベートCAを運営したくない場合など
p.69 下位CAの証明書を親CAがコントロールすることもあれば、自由に発行できる場合もある(その場合は、発行可能な名前空間に制約がつく、Name Constraints拡張を参照)

p.69 証明書チェーンは一つだが、信頼パスは多様:相互認証の場合、メインのCAだけではなく、他方のルートCAに連なるパスもある
p.70 パスの構築は実装が貧弱で、様々な問題を引き起こす:サーバー側の問題(ヒューマンエラーや証明書設定のユーザビリティ)も、クライアント側の問題(信頼パスの構築と検証にまつわるセキュリティ問題、詳細は6.1節)もある。

脚注
  1. StarfieldのリポジトリにはMicrosoftからの相互認証証明書が記載されている。 ↩︎

  2. StarfieldはEV証明書やコード署名証明書などで中間証明書を分けている。 ↩︎

KIDANI AkitoKIDANI Akito

3.5 証明書利用者

p.70 証明書検証のために信頼できるルートCA証明書の一覧が必要:OSの提供するルートトラストストア
p.70 例外:Mozillaは独自のトラストストアを用意

(画像はFirefoxの証明書ストアとMacBookのキーチェーン)

【Apple】
p.70 Apple Root Certificate Programを運用:監査を通過しないと追加してもらえない

【Chrome】
p.70 ChromeはホストOSのトラストストアを利用するが、Linux上ではMozillaのものを利用
p.70 OSの提供するものだけでは不十分として、独自の機能レイヤを持つ

  • 証明書のブラックリスト機能[1]
  • EV証明書を発行できるCAのリスト
  • 一部もしくは全部の証明書へのCTへの追加対応への要求[2]

【Microsoft】
p.70 Microsoft Root Certificate Programを運用:一年間の監査を通過しないと追加してもらえない

【Mozilla】
p.71 Mozilla CA Certificate Policy(2021年現在はMozilla Root Store Policy)にもとづき運用
p.71 様々なLinuxディストリビューションのルートトラストストアのベースとして利用される

p.71 いずれのプログラムも、CAが独立した監査を受けることを要求:DV、OVであれば以下。

  • WebTrust for CA[3][4]:EV証明書の発行についての監査のみ?(GlobalSignのページを見るとそうでもなさそう)
  • ETSI TS 101 456[5] Electronic Signatures and Infrastructures (ESI); Policy requirements for certification authorities issuing public key certificates
  • ETSI TS 102 042 Electronic Signatures and Infrastructures (ESI); Policy requirements for certification authorities issuing public key certificates
  • ISO 21188:2006 Public key infrastructure for financial services
脚注
  1. Digicertの資料によれば、2011年のComodo/Diginotar事件で登録局がハッキングされ、Gmailなどの証明書が偽造された際に、Comodoなどの証明書をブラックリストに追加してブラウザベンダが配布した、とされている。 ↩︎

  2. 2.12.2節 CTを参照。CT:Certificate Transparency(証明書の透明性)はSSL/TLSの信頼性を高めるための技術で、Google社により提唱され、2013年にRFC6962としてまとめられた。認証局が証明書を発行する都度、全ての証明書発行の証跡を、第三者の監査ログに記載し、Signed Certificate Timestamp(SCT)と呼ばれるデータが返される。Webサーバはこれを証明書とともにブラウザに提示し、ブラウザが検証する。 ↩︎

  3. https://jp.globalsign.com/webtrust/ によれば、AICPA(米国公認会計士協会)とカナダ勅許会計士協会によって共同開発された国際的な電子商取引認証局監査プログラム ↩︎

  4. 正確には、WebTrust
    Principles and Criteria for Certification Authoritiesのことか。 ↩︎

  5. European Telecommunications Standards InstituteのTechnical Specification。 ↩︎

KIDANI AkitoKIDANI Akito

3.6 CA

p.71 パブリックCAになるために必要なこと

  1. 競争力のあるCAを構築する
  2. 各国の法律を遵守する(ライセンス取得が必要な場合も)[1]
  3. ルートCA証明書プログラムで要求される監査をパスする
  4. 自分のルートCA証明書をさまざまなルートCA証明書プログラムに配置する
  5. ルート証明書の相互認証を行って運用を開始する

p.71 競争力のあるCAを構築する、とは...

  • PKIおよびCAの運用に深い知識をもつ
  • ルートCA証明書と下位CAの証明書鍵を防御しつつ、強固で安全な区画化されたネットワークを設計する
  • 証明書のライフサイクルに対応する
  • Baseline Requirementsに従う
  • EV SSL Certificate Guidlinesに従う[2]
  • グローバルなCRL、OCSP基盤を用意する

p.71 初期はDV証明書販売は割の良い仕事だった:2015年にLet's Encryptという無償CAが登場し、価格急落[3]
p.71 EV証明書関連は利益率が高くなるはず[4]

脚注
  1. 日本の場合、電子署名法にもとづきJIPDEC(一般財団法人日本情報経済社会推進協会)が認定している。参考:認証局の種別と関連制度 ↩︎

  2. こちらもCAB Forumのだしているガイドライン。 ↩︎

  3. 最近ではZeroSSLというサービスもあるらしい。参考:無料の SSL 証明書が得られる ZeroSSL を使ってみた ↩︎

  4. 参考:GlobalSignだとEV証明書は¥140,800、マルチドメインEV証明書は¥222,200。 ↩︎

KIDANI AkitoKIDANI Akito

3.7 証明書のライフサイクル

p.72 証明書所有者がCSR(Certificate Signing Request)を用意、CAに送信
p.72 CSR:公開鍵を格納すること、対応する秘密鍵で署名し秘密鍵の所有を明らかにする
p.72 CSRにはメタデータを格納できるが一部しか使われない:CAが他から手に入れた情報で上書きすることもある[1]

【DV証明書(Domain Validation)】
p.72 証明書所有者がメールアドレス宛に送られてきたメールに記載のリンクをクリックして承認すると、証明書が発行される
p.72 完全に自動化されており迅速に発行される
p.72 メール以外にも電話や郵送による確認もある

【OV証明書(Organization Validation)】
p.72 サイトを運営する組織が実在するか、本物の組織化を確認する
p.72 Baseline Requirements登場までOV証明書発行手続きは標準化されておらず、現在でも一貫していない部分がある

【EV証明書(Extended Validation)】
p.72 非常に厳格が本人性の検証が行われる。証明書の審査過程が業界統一の規格になった。[2]
p.72 証明書の入手には数日から数週間かかることもある。

p.73 上記検証が完了後、CAが証明書を発行する
p.73 証明書の再発行という言葉があるがそのような手続きはない:失効した場合は、単に新しい証明書を発行するだけ

脚注
  1. Nginx+opensslの場合のCSR作成手順。Country, Name, State or Province Name, Locality Name, Organization Name, Organization Unit Name, Common Name(ウェブサーバのFQDN。例:ssl.globalsign.com), Email Addressなどのメタデータがある。 ↩︎

  2. CA/B Forumの定めるGuidelines for the Issuance and Management of Extended Validation Certificates、通称EV SSL Certificate Guidelines。対面での本人確認には写真つきの免許証、パスポートなどを用いるべし、などと書かれている。 ↩︎

KIDANI AkitoKIDANI Akito

3.8 失効

p.73 証明書の秘密鍵が危殆化した場合、証明書が必要なくなった場合に失効される:2つの標準

【CRL(Certificate Revocation List)】[1]
p.73 期限切れになっていない、失効した証明書のシリアル番号一覧[2]
p.73 証明書のCRL Distribution Points拡張を利用してURLが格納されている
p.73 肥大化するためリアルタイム検索が遅い

【OCSP(Onlince Certificate Status Protocol)】
p.73 単一の証明書の失効状態を取得できる仕組み。OCSPのサーバをOCSPレスポンダという。
p.73 Authority Information Access拡張を利用してOSCPレスポンダの場所を示す。
p.73 リアルタイム検索ができるが、パフォーマンスとプライバシの問題がある[3]
p.73 こうした問題を解決する技術:OSCPステープリング(WebサーバがOSCPレスポンダと通信し、TLSハンドシェイクにOSCPレスポンスを埋め込む)[4]

脚注
  1. Digicertのホワイトペーパーに詳しい ↩︎

  2. 現物はhttps://zenn.dev/link/comments/ec15e852430d54 ↩︎

  3. Wikipediaの記事によれば、Google Chromeは待ち時間やプライバシーの問題を理由に、2012年に OCSP チェックをデフォルトでは無効にした。同記事の注にあるWebサイトによると、OSCPリクエストを受け取るCAがOSCPリクエスト送信元のIPと失効チェック対象の証明書から、どこからどのサイトが見られているか分かるのを問題視した模様。また、同サイトによれば、OSCPのレスポンスの中央値は300ms程度で、平均値は1秒程度とのこと。確かに遅い。 ↩︎

  4. RFC6066 Transport Layer Security (TLS) Extensions: Extension Definitionsで定義されている。本書2.12.10 OCSPステープルを参照。 ↩︎

KIDANI AkitoKIDANI Akito

3.9 弱点

p.73 1995年ごろ、インターネットはまだ重要性が低かった:Eコマースの発展とともに暗号化が必要に
p.74 Eコマースにとって十分なセキュリティが実現された:商業的セキュリティ
p.74 CAとブラウザベンダが制御
p.74 CAの立場の難しさ:何百ものCAがとても低いエラー率で証明書を発行し全体が動作しているのに、無償かつ完璧なセキュリティを求める人々がいる
p.74 インターネットPKIのさまざまな欠点

証明書の発行に際してドメイン所有者の許可が求められない

p.74 全てのCAが許可なくどんなドメイン名の証明書でも発行できる
p.74 数百あるCAの質も様々:監査を受けていても安全ではない ex.2011年のComodo/DigiNotar社の事件
p.74 CAがセキュリティより商業的利益を優先するケースも:2011年Trustwave社が証明書のでっちあげを認めた[1][2]
p.75 政府がCAのシステムを悪用している可能性も

信頼を迅速に回復できない

p.75 Trust agilityが欠如している:証明書に問題がある場合、ルートトラストストアからCAの証明書を除去すればいいが、大手は除外しづらい
p.75 ブラウザが、発行済み証明書を信頼するが新規の証明書を信頼しない、としたこともある(2017年、WoSignおよびStartCom)[3]

弱いドメインの検証

p.75 DV証明書は安全ではないWHOISプロトコルで取得できるドメイン所有者情報をもとに発行される
p.75 ドメインをのっとったり、電子メールやCAネットワークへの不正アクセスで偽のDV証明書を取得できる[4]

失効がうまくいかない

p.75 2011年にいくつかのCAで問題発生:ブラウザが自前のブラックリストなどで確実に失効させる必要があった
p.75 理由1:失効情報が各システムへ波及するまでの遅延(Baseline RequirementsではCRL/OCSPについて10 日間、中間証明書については12ヶ月までの有効にすることを認めている[5]
p.75 理由2:ブラウザのソフトフェイル・ポリシーにより、失効情報が取得できなくても接続が遮断されない
p.76 これらの理由から、ブラウザベンダーは失効確認を放棄[6]
p.76 失効については5.11節でさらに説明がある

証明書の警告がセキュリティの意図を台無しにする

p.76 証明書の検証が手ぬるい[7]:検証を完全に端折っているアプリやライブラリが多数、ブラウザの警告も迂回可能[8]
p.76 HSTS(HTTP Strict Transport Security)と呼ばれる新しい標準:ブラウザに証明書警告をエラーに置き換え、迂回をできなくさせる[9]

脚注
  1. ある記事によれば、ある会社が社内ネットワーク上でTLS接続を盗み見るために中間者攻撃を可能にする下位のルート証明書をTrustwaveが発行した。これを受けてMozillaがルート証明書プログラムからの除外を検討したとされているが、2021年7月現在のFirefoxのストアにはTrustwaveの証明書が確認できるので、結果としては除外されなかった? ↩︎

  2. 2011年のこれらの事件を受けて翌2012年にBaseline Requirementsが発表された。 ↩︎

  3. Wikipediaの記事によれば、日付を偽装して証明書を発行していたため、MozillaがWoSignをブロックした。WoSignはStartComを買収していた。別のサイトによれば、ルート証明書もその後Mozillaのストアから削除され、Googleも同様の対応をとった模様。 ↩︎

  4. CAへの不正アクセスについては、 ↩︎

  5. 最新のBaseline Requirementsを確認すると、中間証明書は失効から24時間以内にOCSPを更新すること、とされている。通常の証明書については最低8時間最大10日間OCSP情報を有効にしておくことを認めている。 ↩︎

  6. 最近のChromeはそうでもなさそう?Chromeのヘルプでは「Chrome が失効のステータス情報を取得できない場合、証明書は失効したものとして扱われます。」と書かれていた。 ↩︎

  7. このサイトによれば、iOS4.Xの証明書検証はBasicConstraints拡張を完全に無視しており、なりすましが可能であった。 ↩︎

  8. 本書1.4.5節 中間者攻撃のシリアの事例。 ↩︎

  9. RFC6797で規定。HTTPでの接続時にHTTPSを強制するのが主な機能。 ↩︎

KIDANI AkitoKIDANI Akito

3.10 ルートCA証明書の鍵の危殆化

p.76 PKIへの最も確実な攻撃=ルートCA証明書を狙う:政府機関の要求、100万ドルで新規にCAを設置
p.76 エンドエンティティ証明書を発行した形跡のないCAもいる
p.76 こうした状況への対策:公開鍵ピンニング(HPKP)[1]、HTTPS Everywhere拡張[2]
p.76 最も手間がかからない攻撃=既存のルートCA証明書、中間CA証明書を狙う:偽の証明書を発行しても発行元が同じなので見分けるのは困難
p.77 2003年のShamir/Tromerの発表:1024ビットの鍵は1000万ドルのマシンで約1年で破れる
p.77 2013年のTromerの見積もり:1024ビットの鍵は100万ドルでいける
p.77 => 政府機関にとっては容易に破りうるレベル
p.77 Googleは2013年に1024ビットの証明書から移行[3]
p.77 Mozillaは2013年末までに弱いルートCA証明書削除を予定していたが、2015年後半にようやく完了した[4]

脚注
  1. HPKP、HTTP Public Key PinningRFC7496で2015年4月に規定されたが、非推奨となり、Google Chromeは2019年のv72でサポートを廃止した。Firefoxは2015年1月リリースのv35からこれをサポートし続けている。これを置き換えられるものとして、Certificate Transparencyがある。 ↩︎

  2. Firefox版Chrome版などがある。すべてのWebサイトに接続する際にHTTPSで接続するようになる。TorプロジェクトとEFF(Electronic Frontier Foundation)が作成。 ↩︎

  3. Googleの発表によると、2013年7月に2048ビットの鍵へ移行中。2〜3ヶ月かかる見込み。 ↩︎

  4. この記事によれば、Firefox 32(2014年)でEntrustやGoDaddyなどいくつかの弱いルート証明書が削除されている。 ↩︎

KIDANI AkitoKIDANI Akito

3.11 エコシステムの観測

p.77 2010年以降PKIエコシステムの活発なスキャニング・モニタリングが実施:それ以前のことはあまりわからない
p.77 2010年7月の筆者Ivan Ristićの調査:12億ドメインの証明書、TLSセキュリティ分析
p.77 その数日後にEEFのSSL Observatory調査:全IPv4アドレス空間の同様の調査
p,77 2011年Holzらの同様の研究
p.77 2012年EEFがHTTPS Everywhereを利用したDistributed SSL Observatoryを発表:結果は未公開
p.78 2012年、筆者Ivan RistićのSSL Labsの一環としてSSL Pulseプロジェクト:毎月15万サイトをスキャン
p.78 2012年、ISC Certificate Notaryプロジェクト(2018年以降はあまり更新されていなそう)
p.78 2013年のDurumericらによる調査が最も包括的:ZMapというOSSツール、スキャン結果を公開
p.78 2014年、IE11によるテレメトリ収集対象に証明書を含める

p.78 いずれも、深刻な問題を明らかにしたわけではないが、重要な問題に光を当てた
p.78 例)CAがプライベートIPアドレス向けの証明書や完全修飾でないドメインへの証明書を定期的に発行

p.78 2014年、CA/B Forumのガイドライン遵守状況の評価結果が公開:Baseline Requirements導入後改善が見られた

p.79 CAの正確な数ははっきりしていない:通常のルートCAは100ちょっと、上位10のルートCAが市場の90%を占める
p.79 2015年Comodo社がcrt.shという証明書検索エンジンを立ち上げ:CTのログが情報源
p.79 2015年ミシガン大学がCensysというネットワークセキュリティ検索エンジンを立ち上げ:セキュリティ研究者向け

KIDANI AkitoKIDANI Akito

3.12 改善

p.79 2011年複数のCAのセキュリティが破られ、改善の動き
p.79 失敗したものも多い:残ったのはCT、公開鍵ピンニング、DANE、CAA(詳細は10章)

【Perspectives】
p.79 TLS認証を補助する公証人の概念を最初に導入:クライアントが公証人に相談して証明書を認証
p.79 2008年立ち上げ、2021年現在も活動している[1]

脚注
  1. 元はカーネギーメロン大学のプロジェクトだった。Perspectivesプロジェクトのサイトによると、2021年現在、AWS in Educationなどの助成を受けて、8つの公証人サーバを運用している。35万サイトを1日2回チェックしている。公証人にアクセスするにはFirefox拡張などを利用することができる。 ↩︎

KIDANI AkitoKIDANI Akito

【Convergence】
p.79 Perspectivesからフォークして改良した:2011年ローンチ、2013年以降活動なし、短命
p.80 プライバシー改善のため公証人へのリクエストに複数プロキシを介在
p.80 パフォーマンス改善のためサイト証明書を一定期間キャッシュ

【公開鍵ピンニング(Public key pinning)】
p.80 信頼できるCAをサイト所有者がピン留め:CAがどんなドメインの証明書も許可なく発行できる問題を解決する
p.80 2つの標準:HTTP Public Key Pinningと動的ピンニング(dynamic pinning)(詳細は10.3節)[1]
p.80 Chromeの独自の仕組み、静的ピンニング(static pinning)(詳細は10.3節)

【DANE】
p.80 DNSSECとTLSの橋渡しをする
p.80 DNSSEC(Domain Name System Security Extensions):DNSの拡張、安全性の検証を可能にする。
p.80 DANEは公開鍵ピンニングにも利用できる
p.80 DANEでパブリックCAを迂回し、DNSをTLSの認証に使えるようにもなる

【ソブリン鍵(Sovereign Keys)】
p.80 公的に検証可能なログに記録される鍵(ソブリン鍵)でドメイン名を主張する
p.80 CAやDNSSECなど既存のセキュリティ基盤を拡張する提案
p.80 2011年に公表されたが、鍵を失った場合の回復手段がなく、まだアイデアの段階(参考:EEFのプロジェクトページ

【MECAI(Mutually Endorsing CA Infrastructure)】
p.80 公証人の一種で、その基盤をCAが運用するというもの
p.80 煩雑な作業を全てサーバで行う:プライバシーとパフォーマンス改善が期待できる
p.80 CAが証明書の鮮度を保証するバウチャーを発行するVA(Voucher Authorities)を兼ねる(参考
p.80 2011年発表、まだアイデアの段階

脚注
  1. 証明書のハッシュや証明書そのものをアプリに組み込むピンニングの場合、証明書期限切れ時にアプリのアップデートができなくなる問題があった:dynamic pinningの場合ハッシュを外部からダウンロードすることでこれを解決する。参考 ↩︎

KIDANI AkitoKIDANI Akito

【CT(Certificate Transparency)】
p.81 パブリックな証明書の監査とモニタリングのためのフレームワーク
p.81 RFC6962として2013年に策定、Googleが推進[1][2]
p.81 2015年、Chromeは新規発行されるEV証明書がCT対応することを要求:最終的に2018年4月までにすべてのパブリックな証明書がCT対応することを要求[3]

【TACK(Trust Assurances for Certificate Keys)】
p.81 2012年に登場したピンニングの一種。サーバが提供した署名鍵をピン留めする。
p.81 長期的な署名鍵を利用すればCAに依存しなくて済むようになる(その分処理が大変)
p.81 他の提案と違い、HTTP以外でもTLSで保護される全てのプロトコルで動作
p.81 本書執筆時点でサポートしているクライアントはない[4]

【CAA (Certification Authority Authorization)】
p.81 ドメインに対する証明書を発行できるCAをドメイン名所有者が指定できるようにする提案
p.81 2013年RFC6844 DNS CAA Resource Recordとして提案
p.81 CA/B Forumが2017年3月にCAA利用を義務付けている

p.81 多くのアイデアは特別な状況でうまくいかず、実装されなかった
p.81 公証人をベースにした提案は注意すべき点が多すぎる:公証人の意見が一致しない場合、複数の証明書を同じ名前でデプロイしているときの誤検出、など
p.82 公開鍵ピンニングはかなり見込みがある:2011年にGoogleがデプロイしたおかげでDigiNotarによるセキュリティ侵害が発覚した(他の障害もいくつか見つかった)
p.82 DANEは優れた解決策ではあるが、DNSが中央集権的で政府の影響を避けられないことが課題:ブラウザベンダーは2021年現在も乗り気ではなさそう(参考:caniuse.com

p.82 2つの方向性:既存システムの改善路線とサイト毎にセキュリティを選べる路線
p.82 改善路線:Mozillaの働きかけによる2012年のCA/B ForumとBaseline Requirements発表や、GoogleによるCT推進、2010年以降のモニタリング活動
p.82 そこそこのセキュリティを可能にする新しい技術:公開鍵ピンニング、HSTS(HTTP Strict Transport Security)、CSP(Content Security Policy)、強制的なOCSPステープリング

脚注
  1. Googleのサイトによれば、2021年7月25日時点でGoogleのCTログに追加された証明書は 14,128,739,375 件。同サイトではCTログを閲覧することもできる。 ↩︎

  2. Let's EncryptのCTログは https://oak.ct.letsencrypt.org/2021/ct/v1/get-roots にアクセスするとみることができる。参考 ↩︎

  3. このメールによれば、Chrome 68(2018年7月リリース)以降、2018年4月30日よりあとに発行された証明書について、CT対応が必須となっている模様。 ↩︎

  4. 2021年現在でも、Googleで1年以内の記事を検索して関連する記事が出てこないため、状況は変わってなさそう。 ↩︎

KIDANI AkitoKIDANI Akito

第4章 PKIに対する攻撃

4.1 VeriSign社のMicrosoft社に対するコード署名証明書

p.83 2001年1月、身元を詐称した何者かにVeriSignがMicrosoftのコード署名証明書2通を発行
p.83 同年3月にMicrosoftが対応策を実施したあとに公になった

https://internet.watch.impress.co.jp/www/article/2001/0323/verims.htm

p.84 VeriSignは間違いに気づき証明書を失効したが、CRL配布ポイントが指定されておらず不十分な対策
p.84 Miscrosoftはこの証明書をブラックリストに入れるOSアップデートを公開

4.2 Thawte社とlogin.live.com

p.84 2008年夏、セキュリティ研究者がThawteの証明書検証処理をだまして証明書を取得
p.84 Thawteのドメイン認証に電子メールを利用している+Microsoftが@live.comのアドレスを誰でも利用できた
p.84 この問題はDEFCON17で発表された[1]
p.84 同様の問題がMicrosoftのlive.fiドメインで2015年にも発生

脚注
  1. DEFENSE CONDITION 29が2021/08/05-08開催される ↩︎

KIDANI AkitoKIDANI Akito

4.3 StartCom社のセキュリティ侵害(2008年)

p.85 セキュリティ研究者がStartComのドメイン名検証Webサイトの欠陥を悪用して迂回
p.85 StartComが目立つWebサイトドメインをブラックリストとして管理していたため発覚:paypal.comとverisign.com
p.85 数分ですべて失効された

4.4 CertStar(Comodo社)のMozilla証明書

p.85 StartComのCTOが同社への攻撃のあと他のCAでの同様の問題を発見
p.85 ComodoのパートナーのCertStarがドメイン名を全く検証せずに証明書を発行していた
p.85 mozilla.dev.tech.cryptoメーリングリストで大きな議論に
p.85 Comodoが検証し、証明書を失効させた

4.5 偽造RapidSSL

p.85 2008年SotirovとStevensを中心とする研究グループがRapidSSLを利用して偽造CA証明書を取得:任意のドメインの証明書発行可能
p.86 MD5の衝突を利用した攻撃で偽造CA証明書を取得

MD5とPKIに対する攻撃年史

  • 1991年:MD4を置き換えるものとしてMD5が設計される
  • 〜1996年:MD5が一般化、弱点を示す兆候が見られ、別のハッシュが推奨される
  • 2004年:MD5の完全な衝突の実例が示される:攻撃自体はまだ現実的ではない
  • 2005年:異なる2通の証明書が同じMD5ハッシュ値(同じ署名)を持つ現実的な衝突の実例が示される(RSA鍵空間が異なるのみで、証明書の本人性は同一であった)
  • 2006年:選択プレフィクス衝突攻撃(当初はターゲット衝突と呼ばれた)で、本人性が異なる証明書を衝突させることに成功:実質的にMD5は完全に破られた
  • 2008年:MD5による署名での証明書発行が止まらず:SotirovとStevensを中心とする研究グループによる攻撃の事例
  • 2012年:Flameとよばれるマルウェアが中東のネットワークで感染拡大:Windows Updateのコード認証の仕組みを攻撃するため、Microsoft社のCA証明書にMD5の衝突を利用していた。2-5年程度、政府の後ろ盾を受け活動していたとみられる。
KIDANI AkitoKIDANI Akito

4.5.1 選択プレフィクス衝突攻撃

p.87 ディジタル署名:データのハッシュ値に対して署名をするため、同じハッシュ値をもつ証明書が作れれば、一方に対する署名は他方についても有効となる
p.87 攻撃者にとっての制約:CAに証明書を送っても署名してもらえず、公開鍵やドメイン名などの情報を送ってCAが証明書を生成する。(乗り越えることは可能)
p.87 異なるデータのハッシュ値を一致させるために必要な条件

  • オリジナルの文書(潔白な文書)の先頭部分(プレフィクス)を事前に知っていること
  • オリジナルの文書(潔白な文書)の途中に衝突ブロックを配置できること

p.87 ファイルの末尾は同一にする必要がある

4.5.2 衝突する証明書の構成方法

p.87 ディジタル署名の作成における制約

  1. 証明書は攻撃者が作成したCSRの情報を使って、CAが作成する
  2. 証明書の構造はX509v3仕様で決まる:攻撃者は構造を予測することが容易
  3. CSRから証明書にコピーされる部分は攻撃者が制御可能:特に、公開鍵はそのままコピーされる。ランダムに見える衝突ブロックを作りやすい
  4. CAが追加する情報の一部に攻撃者が影響を及ぼすことが可能:例、証明書の失効時刻などは予測しやすい

p.88 以上より、プレフィクス=公開鍵よりも前にある全てのフィールド、衝突ブロック=公開鍵
p.88 プレフィクスの大半は、同じCAから発行された別の証明書とCSRに記載の情報から入手可能
p.88 CAが制御できるプレフィクス(シリアル番号と期限切れとなる日付):これも予測は不可能ではない(後述)
p.88 攻撃のプロセスは以下のようになる

  1. CAで生成される証明書のプレフィクスを確認し、CSRのフィールドを決める
  2. 不正な証明書に必要となるプレフィクスを構成する
  3. 証明書のサフィックスを決める
  4. 1-3のデータで衝突ブロックを構成する
  5. CSRを組みてててCAに送り本物の証明書を入手する
  6. 偽造プレフィクス、2つ目の衝突ブロック、サフィックス、本物の証明書から取り出した署名から、不正な証明書を組み立てる

p.88 RapidSSLへの攻撃では、証明書の利用に支障がないように、衝突ブロックにComment拡張(処理の際に無視される)が利用された

KIDANI AkitoKIDANI Akito

4.5.3 プレフィクスの予測方法

p.89 シリアル番号と期限切れ日時をどのように予測したか?:運とCAからの手助け

  1. RapidSSLでは完全自動化された証明書発行処理が6秒で完了[1]:期限切れ日時を秒単位で予測しやすい
  2. RapidSSLではシリアル番号に乱数を使わず単純なカウンタを利用:2つの証明書を連続して取得すると2つ目のシリアル番号が予測できる

p.89 MD5署名の証明書を発行するCAは2008年当時6つ存在[2]
p.89 研究チームは200台のPlayStation 3クラスタで1日かけて衝突を生み出した
p.89 CAの処理が最も空いている日曜夕方に攻撃を実行:4週間かけて成功

4.5.4 後日談

p.89 被害を最小限にする対策

  1. 不正な証明書は期限が過去の日時となるように生成
  2. トラストストアを管理する団体(MSやMozilla)に発表前にブラックリストへの追加を依頼
  3. RapidSSLにも事前に警告:攻撃の発表から数時間でSHA1へ移行

p.91 各種対策を経て安全であると判断してから選択プレフィクス衝突技法が完全に公開された
p.91 攻撃費用:たった657ドル(PS3クラスタを除く。RapidSSLでは1通新規69ドル、更新45ドルだが、無料で20回まで証明書を再発行できた)
p.91 Amazon EC2だと2万ドル近くかかる。改良すれば2000ドル。

p.90 真正な証明書と衝突した証明書の構成(研究報告スライドより)

研究報告サイトより

脚注
  1. 研究報告スライドによれば、Acceptボタンを押してから6秒後に完了するとのこと。 ↩︎

  2. 研究報告スライドによれば、他にFreeSSL、TrustCenter、RSA Data Security、Thawte、verisign.co.jpがMD5で証明書を発行していた。 ↩︎

KIDANI AkitoKIDANI Akito

4.6 Comodo社のリセラーのセキュリティ侵害

p.91 2011年の一連の事件のうち、最初のもの。
p.91 3/15:ComodoのRAの一つがセキュリティを侵害され7つのサイトの証明書が発行された(addons.mozilla.org、google.com、login.live.comなど)が、数時間で全て失効された
p.91 このときOCSPレスポンダへのアクセスはlogin.yahoo.comの証明書について2回だけだった(が、MITM攻撃によりOCSPへのトラフィックが抑圧されていた可能性もあるので全容は不明)
p.91 3/16:Comodoから関連団体へ通知、パッチを当てる処理が開始(例:FirefoxなどMozillaのコアモジュールで証明書を明示的にブロックChromeもFirefoxとやや異なる証明書をブラックリストに追加
p.91 3/22:3/15に攻撃があったことが、Comodo、Mozilla、Microsoftなどにより公開された
p.92 3/26:Comodoがさらに2社のリセラーでセキュリティ侵害があったことを公表、不正な証明書は発行されず
p.92 3/26:ComodoHackerを名乗る攻撃者が、数ヶ月に及ぶ大規模な攻撃であると発表(このあと他の攻撃にも関与)

p.92 2008年のCertStar事件以降、証明書発行を自由に行えるパートナーは9%となっていたが、本件以後は0%となった
p.92 本件で判明した重大な問題:Comodo社が実態に即した脅威モデル(RAそのものを攻撃対象として侵害する)を検討していなかった

KIDANI AkitoKIDANI Akito

4.7 StartCom社のセキュリティ侵害(2011年)

p.92 6/15:おそらくComodoHackerによってStartComが狙われた
p.92 これをうけて、StartComは証明書発行を1週間停止:不正な証明書の発行やルート鍵の危殆化はなし
p.93 StartComからの詳細報告はなく、2011/9/9のEddy NiggのStartComのサイト上のブログ記事が詳しい[1]

4.8 DigiNotar社

p.93 オランダのCA、DigiNotar:オランダ政府の電子政府プログラムのPKI部分を担当
p.93 7/19:ComodoHackerによるMITM攻撃を受け、531通の不正証明書を発行[2]
p.93 8/29:問題が公になる
p.93 9/5:ComodoHackerが声明を発表
p.93 9/19:DigiNotarは廃業し、自己破産

4.8.1 発見の経緯

p.93 8/27:イランのGmailユーザーが日常的なサービスダウンを報告、背景にMITM攻撃があったことが判明
p.93 Chromeの公開鍵ピンニングの仕組みがMITMを検出し防いだ
p.93 その後、約30万のIPアドレス(イランの全IPアドレスに相当)が影響を受ける大規模なものであることが判明

4.8.2 CAの信用失墜

p.93 オランダ政府は外部セキュリティコンサルタントFox-IT社を投入
p.94 1週間後の9/5にFox-ITの報告

  • CAサーバがネットワーク越しにアクセス可能
  • 全CAサーバが単一のWindowsドメインに所属、パスワードルールがあまり強くない
  • パッチが当たっていないソフトウェアがインストールされていた
  • サーバにアンチウイルス対策がない
  • IPS(侵入防止システム)は導入されていたが攻撃をブロックできず
  • ネットワークの中央ロギングシステムはなし
    p.94 1年後の2012年8月全容のレポート
  • 2011/6/17:Webサーバ上のコンテンツ管理アプリが破られる
  • 2011/7/1:ルート鍵の素材が保存される最重要ネットワークセグメントへ侵入
  • 2011/7/10:128通の不正な証明書を手に入れるプログラムを実行、最終的に53組織531通に(ログの改竄もあり、正確な数は不明)
  • 2011/7/19:DigiNotarが侵入に気づき、外部コンサルタントと協力してシステムをクリーンアップ、何通かの証明書を失効させたが、外部へは報告せず

p.94 証明書に利用された名前:有名Webサイト、CA、政府機関など

  • CA:comodo, digicert, globalsign, thawte
  • 有名サイト:google, mozilla, microsoft, skype, twitter, wordpress, facebook
  • 政府機関:cia[3], mossad[4], sis[5]
    p.94 Webサイトを騙る目的ではなく、メッセージが目的の証明書も(どんな暗号でも解ける、Torも破る、名もなき兵士、など)

4.8.3 MITM攻撃

p.95 不正な証明書にはDigiNotarのOCSP情報が埋め込まれており、OCSPレスポンダのログにより証明書の追跡が可能(MITM攻撃でOCSPサーバへのトラフィックが妨害されていない場合)
p.96 2011/8/4:大規模な運用の兆候が見られた
p.96 2011/8/29:各ブラウザでDigiNotarのルート証明書が失効され、不正な証明書が一掃された
p.96 この間、恒常的に攻撃があったわけではなく局所的だった(DNSキャッシュポイズニングが利用された?)
p.96 攻撃者の目的はGmailのパスワード収集
p.96 Google社を騙る証明書のOCSPリクエストの95%はイラン国内から、残りは世界各地のTor出口ノード、プロキシ、VPN

4.8.4 ComodoHackerの犯行声明

p.96 2011/9/5:Pastebinで声明、問題の証明書で署名したバイナリファイルや、攻撃の詳細の一部(後の公式報告と一致)が含まれた
p.97 イランにおける攻撃への関与は不明:MITMについてはあまり触れず

脚注
  1. startcomのブログは現在は消えているが、Internet Archiveで閲覧できる。このとき狙われた証明書はGoogle、Twitter、Yahooのものとのこと。 ↩︎

  2. 詳細はWikipediaに詳しい ↩︎

  3. Central Intelligence Agency、中央情報局 ↩︎

  4. イスラエル諜報特務庁 ↩︎

  5. Secret Intelligence Service(秘密情報部、通称MI6) ↩︎

KIDANI AkitoKIDANI Akito

4.9 DigiCert Sdn. Bhd.

p.98 2011年11月:Entrustと契約するマレーシアの中間CA、DigiCert Sdn. Bhd.[1]が危険な弱い証明書22通を発行していると判明[2]

  • 512ビットの鍵:総当たりで因数分解可能(一般数体ふるい法(GNSF:General Number Field Sieve Method)を使えば、総当たり不要[3]
  • EKU拡張による用途制限がない:契約上、Webサイト証明書しか発行できなかったが、制限がないためコード署名などにも利用可能
  • 失効情報がない

p.98 総当たりで破られた公開鍵がマルウェアへの署名として利用されて問題が発覚
p.98 Entrustが中間CA証明書を失効させブラウザベンダーに通達
p.98 米国DigiCert社は本件と無関係であるプレスリリースを出した

脚注
  1. Sdn. Bhd.はSendirian Berhad(スンディリアン・ブルハド)の略で、非公開株式有限責任会社の意味。参考ページ ↩︎

  2. Bugzillaのチケットによると、マレーシアの政府機関や中央銀行などもこのCAを利用していたらしい。 ↩︎

  3. GNSFをサクッと説明してくれる資料は見つからなかったorz。「近年の素因数分解について」(2008)によると、1990年に提唱された方法で、1999年時点で512ビット(155桁)、2005年時点で663ビット(200桁)、2010年のNTTの発表によると768ビット(232桁)、Qiitaの記事によると2020年に829ビットの素因数分解に成功している。 ↩︎

KIDANI AkitoKIDANI Akito

4.10 Flame

p.99 Flame:Flamer、Skywiperとも。2012年5月に研究者による分析開始(攻撃は数年前に開始したとみられる)
p.99 当時最も高度なマルウェア:Lua+SQLiteで、ネットワークアナライザ、マイク有効化、ファイル検索などの20の攻撃モジュールからなる。
p.99 イラン、イスラエル、パレスチナ、スーダン、シリア、レバノン、サウジアラビア、エジプトなど中東の1000のシステムで発見された
p.99 発見後、作成者が全インスタンスを消去する自動消滅コマンドを発行:いくつかは捕捉され分析された

4.10.1 Windows Updateに対するFlameの攻撃

p.100 Windows Updateを攻撃し、ローカルネットワーク上のWindowsに拡大:過去に知られていない暗号技術を利用した攻撃
p.100 IEがWPAD(Web Proxy Auto-Discovery)を利用しており、FlameはプロキシとしてHTTPトラフィックを乗っ取り、Windows Updateサーバとして悪意あるコードをインストールさせた
p.100 Windows Updateは平文を使っていたが、コード署名で防御していた:FlameはMD5衝突を利用して、この署名を偽造

4.10.2 Windowsターミナルサービスに対するFlameの攻撃

p.100 Windowsターミナルサービス、現在の呼び名はリモートデスクトップサービス。
p.100 問題の1つは、証明書の入手が用意であったこと

  • サービスのCA証明書がWindows UpdateのCAと同じルート証明書を利用:サービスのCA証明書から、顧客ごとの下位CA証明書を発行
  • サービスのCAを、ライセンス処理以外に、なぜかコード署名に利用できた
  • 下位CA証明書には使用方法の制限がない=親の制限が継承される(コード署名に利用できる)

p.100 上記をまとめると、リモートデスクトップサーバの顧客ごとに無制限の下位CA証明書が与えられ、これを利用してコード署名が可能だった
p.100 ただし、下位CA証明書にはHydraというcriticalな独自拡張があり、Windows Vista(2007年リリース)以降では動作せず:Windows XPでのみ動作した(XPではcriticalな拡張を無視するため)

4.10.3 MD5を悪用するFlame

p.101 もう1つの問題:証明書の署名がMD5
p.101 ターミナルサービスの設計時点でMD5は安全でないことが知られていたにもかかわらず、ルート証明書の署名に利用された
p.101 RapidSSLへの選択プレフィクス衝突攻撃が利用された
p.101 RapidSSLのときとの違いは、シリアルナンバーが連番ではないものの、起動時からの経過時間(ミリ秒
)に固定の2バイトと連番が続く形式だった。
p.101 ミリ秒単位の正確さが要求されるので、強力なクラスタが必要だったはず
p.102 研究者Marc Stevensによれば、新しい差分パス構築アルゴリズムが使われたとされる

暗号解析への対策

p.102 MD5は言うまでもなく、SHA1も弱いことがわかっている(まだしばらくは使われそう)[1]
p.102 Marc Stevensが発明した対策:耐暗号分析(counter-cryptanalysis)[2][3]

  • 暗号分析による攻撃(例:選択プレフィクス攻撃)により不可避的に生じる異常を検出できる
  • (なので)MD5/SHA1によるハッシュ値が偽造でないことを検証できる
脚注
  1. 2017年のGoogleの記事によれば、SHA-1が初めて衝突した。この記事の著者はMarc Stevensら。Stevens自身はGoogleではなくアムステルダムにあるオランダ国立数学情報科学研究所に所属。Googleと同研究所が2年間かけて共同研究した。この記事によると、MD5はスマホで30秒で破れるらしい。SHA1は110台のGPUで1年かかるとのこと。なお、この発表の翌日、FirefoxはSHA1による証明書を無効化すると発表した(参考)。 ↩︎

  2. 論文の要約によれば、Stevensはこの技術を利用して、Flameが選択プレフィクス衝突攻撃を利用していることをつきとめたらしい。 ↩︎

  3. こちらのブログで日本語で解説されていたがよくわからなかったorz。このブログで、Marc StevensによるC++製OSS暗号分析ツールHashclashが紹介されている。 ↩︎

KIDANI AkitoKIDANI Akito

4.11 TURKTRUST社

p.102 2012年10月:Google Chromeの公開鍵ピンニングが問題を発見、ユーザーが問題の証明書チェーンをGoogleに送付、Googleが調査
p.102 証明書の出所はトルコのTURKTRUST社[1]:数日で証明書は失効
p.103 2011年8月のシステム移行時にSSL証明書ではなく、誤って中間CA証明書を発行していた:そのうちの1つEGO社で MITM機能を持つファイアウォールを導入し誤ってGoogle社の証明書のクローンが作成された
p.103 GoogleとOperaではTURKTRUST社のEV証明書を無効化[2]

脚注
  1. Googleのブログによると、*.google.comドメインの証明書が、中間CA証明書によって発行された。この中間証明書のルート証明書がTURKTRUSTのもの。 ↩︎

  2. Googleのブログによると、HTTPS接続はできるがEV証明書としての表示を無効化したということのよう。 ↩︎

KIDANI AkitoKIDANI Akito

4.12 ANSSI

p.103 ANSSI:Agence nationale de la sécurité des systèmes d’information(フランスの国家機関)
p.103 2013年12月同機関から発行された下位CA証明書をChromeのルートストアから削除、親CAについてはフランス国内のドメインの証明書のみとする制限を課した
p.103 同機関のネットワーク上でMITM機能が動作し、Googleに属する証明書が利用されていた:これもやはりChromeの公開鍵ピンニングで検出
p.103 ANSSIは人為的ミスであったと説明
p.103 MozillaとMicrosoftも問題があるCA証明書を無効化

p.104 ANSSIの問題点が明らかに

  • 多くの証明書に失効情報がない
  • 空だったCRLに数千の証明書が一気に登場
  • Baseline Requirements非対応:早くて2015年12月[1]
脚注
  1. その後の対応状況を調べてみたがよくわからず。FirefoxのトラストストアやmacOSのキーチェーンには含まれていない様子。2021年8月22日現在のANSSIのサイトはCertignaというフランスのCAの発行した証明書を利用していた。2021年8月9日時点でオランダのPKIoverheidが「EU最後の政府運用CA」と言われているので、フランスも2013年から2021年の間にCAをやめたのだろうか。 ↩︎

KIDANI AkitoKIDANI Akito

4.13 インド情報工学センター

p.104 NIC:National Informatics Centre of India
p.104 2014年7月、Google所有のドメインへの証明書が同センターの中間CAから発行された
p.104 発行元はインド政府の認証管理局(CCA:Controller of Certifying Authorities):のちに、NICのCAがセキュリティ侵害を受けたことを暴露
p.104 証明書は失効され、NICのCAは証明書発行を停止
p.104 ChromeはCCA発行の証明書についてインドのドメイン(.in)の7つのサブドメインに限定[1]

脚注
  1. Googleのブログによれば、もともとWindowsのルートトラストストアにCCAのルート証明書が含まれており、Windows上のChrome(とInternet Explorer)が影響を受けた。Firefoxは独自のトラストストアを利用するため影響をうけず、また、Windows以外のOS上で動作するChromeも影響をうけなかった。 ↩︎

KIDANI AkitoKIDANI Akito

4.14 広範囲に及ぶTLSの傍受

p.104 ローカルにインストールされたソフトや、ネットワークプロバイダによるTLSの傍受は日常的(2017年のDurumericらの研究)

4.14.1 Gogo社

p.104 Gogo社:航空機内インターネット接続サービスを手がける
p.104 2015年1月、ChromeのセキュリティチームのAdrienne Porter Feltにより、同社が暗号化されたトラフィックを傍受し不正な証明書を利用していることを指摘
p.105 不正な証明書に関する警告が出る状態
p.105 同社は機内の帯域制御に必要と釈明するも、後日傍受を完全停止

4.14.2 Superfishとその仲間

p.105 2015年2月、AdrienneがLenovo社のSuperfishプリインストール問題を指摘
p.105 Superfish:利用者の全トラフィックを傍受
p.105 OSのルート証明書ストアに不正なルート証明書を追加し、プロキシ経由でこれを利用しMITM
p.105 全てのユーザーで同じルート証明書を利用していたことが問題(ユーザーごとに異なる証明書なら良い):秘密鍵を抜き出したユーザーは他のユーザーを攻撃できてしまうため
p.105 SuperfishのプロキシはTLS1.1しかサポートしていなかった(当時の最新はすでにTLS1.2)
p.106 MITMにより、どんなサイトに接続しても証明書の警告がでない状態だった
p.106 Facebookの調査では、カザフスタンからのFacebookへの接続の4.5%がSuperfish経由
p.106 MicrosoftとLenovoが協力して、Superfishを25万台から数日で削除
p.106 その後、SuperfishでのKomodiaが開発したTLS傍受用SDK利用が判明:類似の製品としてComodo社のPrivDogなど、同様のものはたくさんある

KIDANI AkitoKIDANI Akito

4.15 CNNIC

p.107 CNNIC:China Internet Network Information Center(中国ネットワークインフォーメーションセンター)
p.107 2015年3月、MCS(Mideast Communication Systems)社がCNNICから試験的中間CA証明書を受領
p.107 誤ってGoogle社を騙る証明書が発行される
p.107 Google・MozillaはCNNICのルート証明書を失効:中間CA証明書を、杜撰な組織に発行した責任を問う形
p.107 失効以前の有効な証明書についてはホワイトリストを利用して許可し続けた

KIDANI AkitoKIDANI Akito

4.16 Symantec社によるテスト用証明書

p.107 2015年9月、Symantecがgoogle.comに対するEV証明書を権限なしに発行したとするGoogleのブログが公開
p.107 Symantecは2人の社員のミスを主張し彼らを解雇
p.107 EV証明書に必須であったCTのログを精査したところ、総数2645の証明書が誤発行されていたことが判明
p.108 GoogleはSymantecのインシデント報告の遅れを理由に、2016年6月以降同社の証明書全てをCTに登録することを要求

KIDANI AkitoKIDANI Akito

4.17 WoSign社とStartCom社の問題

p.108 2011年のDigiNotarが最初の信用失墜したCA:2016年のWoSignとStartComがそれに続く
p.108 WoSign:中国の大手CA、無料証明書発行でシェア拡大。イスラエルのStartComを買収
p.108 WoSignの運用について問題があるとしてMozillaが調査:2015年1月からルート証明書の不適切利用が明らかに[1]
p.108 決定的であったのはStartCom買収に伴う所有権移転を公表しなかったこと:Mozilla Root Store Policy
の8. CA Operational Changes
に違反
p.108 信頼に値しないとしてMozilla、Apple、Googleがルートストアから排除
p.108 StartComは2008年2011年にも問題をおこしていたが、WoSignとインフラの大部分を共有し、組織的上下関係があったことで同じく排除された
p.109 排除の手法:ある日以降に発行される証明書を拒否(Google、Mozillaは2016年10月21日に設定)
p.109 WoSign/StartComのその後:他のCAの再販業者として操業継続

脚注
  1. MozillaのWikiによると、シリアルナンバーの重複や、多数のBaseline Requirements違反があった。その中には、Baseline Requirementsで認められていない暗号アルゴリズムである中国のSM2を利用した証明書発行もあった。 ↩︎

KIDANI AkitoKIDANI Akito

4.18 Various Validation Incidents

StartEncryptでの検証失敗

p.109 2016年6月、StartCom社が新しいプロトコルStartEncryptを発表:Let's Encryptと同社のACMEプロトコルへの対抗策
p.109 Let's Encryptが非対応だったOV証明書EV証明書に対応
p.109 1ヶ月で致命的な欠陥が見つかる

  • 詐称した証明書が取得可能
  • リダイレクトが許可されたWebサイトの証明書を取得可能だった

p.109 StartComはStartEncryptを破棄してACMEの利用を発表

Comodo社のトップレベルドメイン証明書の誤発行

p.109 2016年9月、sbとwww.sbの両方に有効な証明書を発行:ホストの所有者が異なる
p.110 この前にもtbドメインで同じ問題があったが、こちらは所有者が同じだった

KIDANI AkitoKIDANI Akito

Comodo社が検証の過程でOCR利用

p.110 2016年10月、研究者がComodoの検証プロセスの問題を発見:OCRに脆弱性(1とl)
p.110 WHOISがスパム対策として画像でメールアドレスを提示するためOCRを利用
p.110 のちにComodoはOCR利用を中止

GoDaddy社が404レスポンスで所有権を認めた問題

p.110 2017年1月、GoDaddyが問題を公表:権限なしに8850の証明書が発行された
p.110 ドメイン検証の際に、GoDaddyが乱数を送付、ドメイン所有者がWebサイトに同じ乱数を出力していた
p.110 もともとHTTP(S)でリクエストを送ってサイトをチェックしていたが、検証のバグにより、404ステータスの際にも(URLに乱数が含まれたため)検証が通過するようになってしまった[1]
p.110 この検証方法はCAB Forumで問題視され、Ballot 169[2]で投票の結果、Baseline Requirementsが改善された。

脚注
  1. 詳細はmozillaのメーリングリストに。 ↩︎

  2. Ballotは投票の意味。 ↩︎

KIDANI AkitoKIDANI Akito

4.19 SHA1の終焉

p.111 2017年2月SHA1が破られた:以前見た通り]
p.111 SHA1の署名が同一となる2つのPDFが公開された:このPDFをSubversion/Gitに投入しようとするとVCS自体が壊れてしまった
p.111 発表者の1人、Marc Stevensは選択的プレフィクス攻撃の検出機能のあるSHA1ライブラリを公開

4.19.1 同一プレフィクス攻撃(identical-prefix attack)

p.112 研究者チームが使用した手法:Marc Stevensがこの数年前に理論上の手法として提示していた
p.112 SHA1:任意の長さの入力から、160ビットの出力を生成するハッシュ関数。内部的に512ビットのブロックに分割される
p.112 関数の内部状態を操作するために、近衝突ブロック(near-collision block)2つを生成する:2つ目で完全に衝突させる

KIDANI AkitoKIDANI Akito

第5章 HTTPおよびブラウザの問題

p.113 ブラウザベンダーが旧来のWebサイトの扱いに苦慮した結果多くの問題が発生

5.1 サイドジャッキング

p.113 セッションハイジャックの一種:暗号化されてないトラフィックからセッションIDを抜き出す攻撃
p.113 無線LANやローカルネットワーク上で簡単に実行できる
p.113 暗号化をしていてもつけ込まれる可能性
p.113 1. 設計上のセッション漏れ:パスワード認証時のみ暗号化しているケース
p.113 2. ミスによるセッション漏れ:HTTPのコンテンツが混在するケース(クッキーから漏洩:混在コンテンツについては本章後半で)
p.114 クッキー以外にも、リクエストパスやパラメータとしてセッションIDが埋め込まれる
p.114 2007年8月Robert GrahamとDavid MaynorがFerretとGamsterという攻撃を自動化するツールをリリースし、本攻撃が知られるようになった
p.114 2010年Eric ButlerがFirefoxアドオンFiresheepを公開:簡単にサイドジャッキングを実行可能[1]、有名なサイトの完全な暗号化を促進
p.114 対策・警告ツールとしてBlackSheep[2]、FireShepherd[3]、Idiocy[4]、CookieCadgerなどが登場

脚注
  1. この記事によると、「ローカルWiFiネットワークをスキャンして、Facebook、Twitter、Google、Amazon、(中略)といった、数多あるWebサービスにログインしているユーザーを洗い出し、そのユーザーに成りすますことをいとも容易く可能に」するとのこと。 ↩︎

  2. この記事によると「Blacksheepはこのクッキーを横取りし、Firesheepには偽のログイン・クッキーを渡すと同時に、ユーザーにFiresheepの存在を警告し、攻撃者が使用しているデバイスのIPアドレスを表示する」。 ↩︎

  3. 配布サイトの説明によると、これは小さなコンソールプログラムで、近くのワイヤレスネットワークにFireSheep停止のためのパケットを大量に送り込み、FireSheepを0.5秒ごとに停止させるらしい。一歩間違えると大惨事なような...と思ったらこちらの記事では使わない方がいいと書かれている。やはり。 ↩︎

  4. こちらの記事によると、「HTTPセッションハイジャックを実施してTwitterアカウントを取得し、そのユーザになりすまして自動的に警告文章をつぶやくツール」らしい。実際のツイートはたぶんこれ。IdiocyはPythonで実装されている。 ↩︎

KIDANI AkitoKIDANI Akito

5.2 クッキー窃取

p.115 Webサイトの完全TLS化だけではサイドジャッキングは防げない:クッキーの暗号化も必要
p.115 WebサイトのTLS化時:クッキーにSecure属性を設定すべき[1]
p.115 Secure属性がない場合のMITM攻撃

  • 犠牲者が平文のHTTPリクエストを送るのを待つ
  • リクエストに、標的のWebサイトのポート80へリダイレクトさせる
  • Webサイトからクッキーが発行される
  • クッキーからセッションIDを取得

p.115 ポート80を開いていなくても、「http://www.example.com:443」にリダイレクトさせ、そのリクエストで暗号化されずに送信されるクッキーを取得できる
p.116 この問題はMike Perryが提唱:DEFCONで発表しCookieMonsterという概念実証ツールを発表

脚注
  1. MDNの説明を引用:HTTPS プロトコル上の暗号化されたリクエストでのみサーバーに送信され、安全でない HTTP では決して送信されないため、中間者攻撃者が簡単にアクセスすることはできません。(中略)ただし、Secure によってクッキー内の機密情報へのアクセスをすべて防げると思ってはいけません。例えば、クライアントのハードディスクへアクセスすることで読み取られる可能性があります。 ↩︎

KIDANI AkitoKIDANI Akito

5.3 クッキーを書き換える攻撃

p.116 Secure属性がついて読み取れないクッキーは書き換えれば攻撃できる

5.3.1 HTTPクッキーの基礎

p.116 HTTPの拡張:小さなデータをブラウザで保持する
p.116 Set-Cookieレスポンスヘッダで指定:名前と値、存続期間などのメタデータ

Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<non-zero-digit>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None

// 以下の例のように、複数のディレクティブも利用することができます。
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

参考:MDN

p.116 ブラウザはクッキージャーにクッキーを格納:HTTPリクエストのたびに適用するクッキーを全てCookieリクエストヘッダで送信

Cookie: name=value
Cookie: name=value; name2=value2; name3=value3

p.117 クッキーの仕様はとても貧弱で悪用可能:2011年にようやくRFC6265
p.117 セキュリティの観点から大きく2つの問題:セキュリティを弱める振る舞いを許す、Same-Origin Policyと矛盾する

●ホスト名のスコープがゆるい

p.117 クッキーはプロトコル、ポートをまたいで共有され、サブドメインでもすべて有効になる
p.117 Domain属性を指定していない場合、親ドメインへも拡大可能[1]
p.117 つまり、悪質なサーバが同じドメイン名で別ホスト名を利用しているサイトにクッキーを注入可能
p.117 Same-Origin Policy(同一生成元ポリシー)はプロトコルとホスト名とポートが完全一致している文脈でセキュリティを規定するため、相容れない

●サーバがメタデータを見られない

p.117 クッキーの出所がわからない:自分が発行していないクッキーも拒否できない

●安全なクッキーにおける同一性の欠如

p.117 Secure属性があってもなくても同じドメイン名で格納され、同一視される
p.117 クッキーの名前、ドメイン、パスがマッチすると、Secure属性がないクッキーでSecure属性ありクッキーを上書きできる

p.117 以上のように、HTTPクッキーは完全性が保証されていないという問題がある

5.3.2 クッキー書き換え攻撃

p.118 クッキー書き換え=削除orクッキー注入(インジェクション)
p.118 インジェクション以外にも、クロスサイトクッキー、クッキー固定化Fixation、クッキー強制、クッキートスtossingなどと呼ばれる

■クッキー排除攻撃Cookie Eviction

p.118 ブラウザのクッキージャーへの攻撃:クッキージャーは個々のクッキーサイズ(通常4kb)やドメイン毎のクッキー数(通常数十個)、クッキーの総サイズが制限されている
p.118 攻撃者はダミーの巨大なクッキーを送信することで本物のクッキーを消し、攻撃に必要なものを残す

■クッキーを直接注入する攻撃

p.118 暗号化されていると読めないが、Secure属性の有無によらず名前空間が同じなので上書きは可能
p.119 リダイレクトなどでHTTPリクエストを犠牲者に強制し、レスポンスでクッキーを改竄する
p.119 これにはクッキーのメタデータの情報が必要:例)TomcatならPathが常にルート(/)など

■親戚関係にあるサブドメインからのクッキー注入

p.119 blog.example.comにXSS脆弱性があるとwww.example.comのクッキーも書き換え可能

document.cookie = 'JSESSIONID=FORCE_ID; domain=example.com';

p.119 このように別部門・組織がそれぞれサイトを運用する状況は危険

●先頭のクッキーになる

p.120 本物のクッキーと偽物のクッキーがある場合、以下のように送信される

Cookie: JSESSION_ID=REAL_ID; JSESSION_ID=FORCED_ID

p.120 とりうる攻撃は2つ:クッキージャーをあふれさせるorメタデータをごまかす
p.120 ブラウザはより特定的なクッキーを先頭におくので、以下のようにPath属性を使う

document.cookie = 'JSESSIONID=SECOND_FORCE_ID; domain=example.com; path=/admin';
↓
Cookie:  JSESSION_ID=SECOND_FORCED_ID; JSESSION_ID=REAL_ID; JSESSION_ID=FORCED_ID
●親戚関係にあるサブドメインを使ってクッキーを上書きする

p.120 ドメインが明示されていないクッキーはホストオンリーとなる
p.120 ホストオンリーのクッキーとドメインが明示されたクッキーは一致しないため、攻撃できない
p.121 blog.example.comからwww.blog.example.comやexample.comへのクッキーは発行できるが、兄弟レベルのサブドメイン(例:www.example.com)にはクッキーを発行できない
p.121 つまり、クッキーのドメインをわざわざルート(example.com)にしていると上書きされてしまう
p.121 IE11では暗黙のドメイン設定と明示的なドメイン設定が区別されないので上書きされうる

●親戚関係にあるサブドメインを捏造してクッキーを上書きする

p.121 MITM攻撃により、www.blog.example.comにリクエストを強制し、blog.example.comへのクッキーを発行できる

5.3.3 影響

p.121 XSS脆弱性、CSRF対策の回避、アプリの操作、セッション固定化[2]といった影響がある

5.3.4 緩和策

p.121 攻撃者に偽装させず、受け取ったクッキーの真正性を確認するための対策をとればよ

●サブドメインを網羅したHSTSを採用する

p.122 HSTS:HTTP Strict Transport Security、ホスト名に対し暗号化を強制する[3]
p.122 MITMによるクッキーインジェクションができなくなる
p.122 問題点1:まれにブラウザがサポートしていない[4]
p.122 問題点2:親戚関係のサブドメインが侵害されたり、信用できない組織が運用している場合は対処不可

●クッキーの名前にプレフィクスをつける

p.122 クッキープレフィクス:より安全なクッキーの階層。本書執筆時点では標準化されていないがFF, Chromeで利用可能[5]
p.122 例:__Secure-でSecure属性を強制、__Host-でホストオンリーを強制

●クッキーの完全性検証

p.122 クライアントから受け取ったクッキーが自サイトで発行したものか確認することが最大の防御
p.123 HMAC[6]や暗号化(JavaScriptで使わない場合)が有効
p.123 ユーザーごとに検証できるようにしないと、攻撃者が取得したクッキーを注入できてしまう
p.123 XSSでクッキーが盗まれる場合、HMACや暗号化では防げない:トークンバインディング(同一のブラウザでしかクッキーを使えないようにする)[7]などが必要

脚注
  1. これはおそらくIEなど特定のブラウザの話かと思われる。徳丸さんのブログ参照。 ↩︎

  2. IPAのサイトの解説がわかりやすかった。 ↩︎

  3. MDNの解説:includeSubDomainsを指定すると、サブドメインにもHTTPSを強制できる ↩︎

  4. MDNの解説:Android用のOperaがサポートしていないっぽい? ↩︎

  5. 2021年現在もまだドラフトの模様。https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis ↩︎

  6. 署名つきCookieについてはGoogleのCloud CDNのサイトが詳しい。https://cloud.google.com/cdn/docs/using-signed-cookies?hl=ja ↩︎

  7. こちらのブログが詳しい。簡単に言うと、ブラウザ側で鍵ペアを接続先ごとに生成し、接続先に公開鍵を送り、クッキーの送信時に秘密鍵で署名する、というイメージ。しかし、こちらのQiita記事によると、Financial-grade API(OAuth 2.0とOpenID Connectを基盤とした、金融業界向けのより高いセキュリティーのための技術要求事項)では、このようなProof-of-possession Tokenとしてはクライアント証明書によるmTLSのみが認められ、Token Bindingは最終版にて削除されたとのこと。 ↩︎

KIDANI AkitoKIDANI Akito

5.4 HTTPSストリッピング

p.123 URLのプロトコル部分を省略して入力するとブラウザは平文でまずアクセスする:これを悪用するとHTTPSストリッピング攻撃が可能
p.123 MITMをしかけると、HTTP通信を外部から読み取って、機微情報の観測や通信の書き換えも可能
p.124 攻撃の手口:標的サイトとよく似たアドレスを使う

p.124 sslstripというツールが公開されている

5.5 MITM証明書

p.125 中間者攻撃の方法3つ

●検証フローの裏をかく

p.125 TLSの検証フローにバグがあれば裏をかける

●不正な証明書

p.125 2008年のRapidSSLのように不正な証明書を偽造して入手する
p.125 1024ビットの弱い鍵を使う証明書を総当たりで破る、など
p.125 犠牲者のネットワークが制御下にある場合、不正な証明書を見破ることは事実上不可能:OCSP+MITMという攻撃もある、多くのブラウザがOCSP失敗を無視する

●自己署名証明書

p.125 ユーザーが警告を無視するのに期待する攻撃者

p.125 sslsniff:https://github.com/moxie0/sslsniff
p.125 SSLsplit:https://github.com/droe/sslsplit[1]

脚注
  1. まだTLS1.3はサポートしていなさそう。部分的なサポートのPRが出ている程度。 ↩︎

KIDANI AkitoKIDANI Akito

5.6 証明書の警告

p.125 TLSの認証は主に証明書による:接続先のホスト名を保証する証明書が返ってくることを期待する
p.125 不正な証明書を受け取ったら、接続を中止すべき
p.126 しかし、ブラウザは接続中止してくれない:証明書の警告を出し、ユーザーに問題を押し付ける

5.6.1

p.126 不正な証明書が使われる原因はいくつかある

●仮想ホストの設定ミス

p.126 同じIPで、平文のサイトと暗号化されたサイトを運用するミス:平文のサイトにhttpsでアクセスしようとすると異なる証明書
p.126 原因の一部:サイトから暗号化に対応しているかどうか表明する仕組みがない
p.126 平文のサイトをホストするIPアドレスのポート443を閉じるのがよい
p.126 2010年の筆者の調査:1億1900万ドメイン対象、2265万のサイトがHTTPS、72万のサイトのみが正しい証明書を持っていた
p.126 名前が一致する証明書を持っているものの、他の理由で信用できないサイトが3割(20万)

●名前が全て網羅されていない

p.126 証明書にホスト名が不足:www.example.comの他にexample.comも証明書に必要

●自己署名証明書とプライベートCA

p.126 これらはMITM攻撃で使われる証明書と区別がつけづらい
p.127 それでも利用される理由

  • 証明書の購入、設定、更新作業が大変
  • 2010年台前半まで証明書が高価だった
  • 証明書が無料であるべきと考えて購入を拒否する人がいる
●アプライアンス製品で使われている証明書

p.127 Webベースの管理インターフェースには安全な通信が必要:しかし、出荷時には利用するホストやIPアドレスは不明
p.127 エンドユーザーが証明書をインストールする必要があるが、利用頻度やUI不足で設定されない

●期限切れの証明書

p.127 筆者の調査では不正な証明書の57%が期限切れ:所有者の更新忘れ

●設定ミス

p.127 サーバは完全に有効なチェーンを用意する必要がある[1]
p.127 ブラウザは不完全なチェーンの再構成を試みるが、他のユーザーエージェントは実行しない

p.127 2013年の研究:39億のHTTPS接続を調査、1.54%で証明書の警告
p.127 イントラネットや社内アプリなどはもっと酷いはず

5.6.2 証明書の警告の効果

p.127 2008年に筆者がMozillaに提案:不正な証明書を迂回できなくしてはどうか→拒否された
p.128 MITM攻撃の最大の問題:ユーザーが気付かない、証明書の警告が「よくあること」になっている
p.128 今日の主要なブラウザは介在型interstitial/割り込み型interruptiveでブラウザウインドウ全体で警告を出す[2]
p.128 Firefoxのテレメトリによると、不正な証明書のサイトへ進んだユーザーはわずか33%
p.128 Chromeの場合ユーザーの70%が警告をやりすごしている:警告のデザイン変更(Firefoxの真似)により、56%まで定価

5.6.3 やりすごせる警告ではなく例外を挙げる

p.129 Firefoxは証明書の例外設定をさせているから成功している?[3]
p.129 自己署名証明書は必ずしも悪くない:自宅のサーバなど、個人利用や理解ある技術者の小規模な集団なら利用可
p.129 TOFU(Trust On First Use)=鍵継続管理(key continuity management):誰かが攻撃して証明書を入れ替えたら、例外に設定されていない証明書なので再び警告が表示されるようになる

5.6.4 緩和策

p.129 エコシステム全体についてはできることはほとんどない
p.129 HSTS(HTTP Strict Transport Security)に対応する:ブラウザに証明書の警告を抑制する機能もある[4]

脚注
  1. SSL PulseのMonthly Scan: August 04, 2021の結果によると、13万以上のサイトを調査したところ、1.6%にあたる2238サイトが不完全な証明書チェーンを提示した。 ↩︎

  2. 本書ではSafariがダイアログで警告を出すのみ、とされているが、2021年現在のバージョン14.1.2ではウインドウ全体で警告を出す方式になっていた。確認に利用したのは https://badssl.com/ ↩︎

  3. MacのFirefox92.0で確認したところ、Chromeの動作とさほどかわらず2クリックで問題のあるサイトを開くことができた...どこかのバージョンで動作が変わったのだろうか ↩︎

  4. RFC6797でHSTSが定められており、8.4で証明書に問題がある場合ユーザーエージェントは接続を終了すべし(MUST)とされている。 ↩︎

KIDANI AkitoKIDANI Akito

5.7 セキュリティインジケーター

p.129 ウェブページのセキュリティに関する付加的情報を提供するUI

  • このページは暗号化されている
  • このWebサイトを運営している法人が判明している[1]
  • このページでは不正な証明書が使われている
  • このページの暗号化に何らかの問題がある

p.130 ユーザーの大部分が無視しているとの調査結果
p.130 モバイルプラットフォームでは画面が小さいことから、セキュリティインジケーターも省略されがち:フィッシングに対して脆弱
p.132 インジケーターは無用ではない:2014-16のSHA256証明書への移行に有効な役割を果たした

脚注
  1. EV証明書はChromeでは2019年9月、Firefoxでは2019年10月以降もはや専用表示がなくなった。参考:https://ssl.sakura.ad.jp/column/ev-ssl2/ ↩︎

KIDANI AkitoKIDANI Akito

5.8 混在コンテンツ

p.132 TLS:単一の接続を保護し、ネットワークレベルでデータを安全にたもつ
p.132 FTPやHTTP:複数の接続が違いに関係する、安全かどうかはユーザーエージェントの実装にかかっている
p.132 HTTPS:HTML、画像、スタイルシート、JavaScriptなどが複数の接続で取得される、混在コンテンツと呼ばれる問題が発生する
p.132 混在コンテンツ:同一ページだけでなく、Webサイト全体でも起こる(平文のページと安全なページの混在 → HTTPSストリッピング攻撃、機微情報の未暗号化などの問題につながる)

5.8.1 根本的な原因

p.132 Webの猛烈な進化スピードに起因

●パフォーマンス

p.132 初期SSLの劣悪なパフォーマンス:平文が好まれていた
p.133 かつての解決策は高価なハードウェアアクセラレータのみ
p.133 現在の懸念は主にネットワークの遅延(パフォーマンスの詳細は9章で後述)

●マッシュアップ

p.133 自分のところだけで全てのコンテンツを提供するわけではない
p.133 特殊な例:Google Analyticsなどサードパーティのコードを利用
p.133 コストは劇的に下がるが、セキュリティにとっては悪夢:サイトの制御がほぼ完全にサードパーティの手に渡る
p.133 Webサイトのユーザーも、自分のデータがどこに格納されるかわかりにくくなる
p.133 サードパーティが暗号化されていないことも:Google AdSenseがHTTPSに対応したのが2013年9月[1]

●インフラのコスト

p.133 CDNの流行:1箇所からWebサイトを配信してもパフォーマンスが悪く競争力を維持できない
p.134 暗号化の負担:CPU、RAM、キャッシュ、証明書、鍵管理など
p.134 IPアドレスの問題:HTTPSを利用する仮想ホスティング(1つのIPで複数サイト)[2]は未対応のクライアントが一定数ある[3]ため、サイトごとにIPが必要だが、IPv4アドレスの欠乏問題もある。

p.134 上記の背景により、ブラウザが混在コンテンツの問題を許容してきた

5.8.2 影響

p.134 2種類のリソース:受動的混在コンテンツ(画像など:混在表示mixed displayとも)と能動的混在コンテンツ(HTMLやJS:混在スクリプティングmixed scriptingとも)
p.134 能動的混在コンテンツがより危険:HTML、CSS、Flash[4]、Java[5]など
p.134 受動的混在コンテンツもページの完全性を損ねる:偽の画像によるフィッシングや、ブラウザの脆弱性を利用してスクリプトとして処理させる(古いIEにおけるコンテンツスニッフィングの悪用)
p.135 同一ホストでの混在コンテンツの場合、受動的攻撃者はクッキーにもアクセス可能

5.8.3 ブラウザでの対処

p.135 当初のブラウザベンダー:サイトの開発者が正しく実装すると考えていた
p.135 2010年代になって、混在コンテンツを制限するようになったが妥協的:受動的混在コンテンツを許可し、能動的混在コンテンツは許可しない

  • Internet Explorer:95年のIE5から混在コンテンツを検出し警告、IE9で能動的混在コンテンツをブロック(2011年)
  • Firefox:混在コンテンツの検出と警告は可能だった、能動的混在コンテンツのブロックはバージョン23から(2013年)
  • Chrome:バージョン38から能動的混在コンテンツをブロック(2014年)
  • Safari:バージョン9から混在コンテンツをブロック(2015年)

p.136 ブラウザのプラグインは特に危険:好きなリクエストをなんでも発行できる
p.136 W3Cで混在コンテンツの扱いを標準化する動き:2021年現在まだドラフト版

5.8.4 混在コンテンツの広がり

p.136 2011年の筆者の調査:Alexa[6]上位100万サイト中、22.41%に安全でないコンテンツが利用されていた
p.136 2013年の研究:Alexa上位10万サイト中の約2万サイト中、43%が混在コンテンツを含む

5.8.5 緩和策

p.137 サイトを正しく実装することで対処できる
p.137 Webサーバーの設定による緩和策2つ:HSTSとCSP

HSTS(HTTP Strict Transport Security)

p.137 強制的に安全なリソースを取得させる仕組み
p.137 ユーザーのミス(ポート80でアクセス)やページの実装ミス(リンクがhttp)にも対応可能
p.137 リソースが自分の管理下にあるホストにある場合のみ有効

CSP(Content Security Policy)

p.137 安全でないリソースをブロックできるセキュリティポリシー
p.137 ブロック以外にも検出を報告する機能もある(report-onlyモード)
p.137 安全でないリンクを暗号化が有効なリンクに書き換えることもできる((upgrade-insecure-requests ディレクティブ)[https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests])

脚注
  1. WikipediaによればGoogle AdSenseのリリースは2003年。https://en.wikipedia.org/wiki/Google_AdSense ↩︎

  2. Server Name Indicationのこと。 ↩︎

  3. 例えば、JavaがSNIに対応したのはJava 7(2011年7月リリース)。 ↩︎

  4. 2019年のChromeをはじめとして、順次各ブラウザでFlashのサポートが打ち切られている。参考:https://www.itmedia.co.jp/pcuser/articles/2012/01/news043.html ↩︎

  5. Wikipediaによると、JavaアプレットについてはChromeが2015年、Firefoxが2017年にサポートを打ち切り、2017年にリリースされたJava 9では非推奨となった。 ↩︎

  6. Alexaはアマゾンの子会社でウェブサイトを順位づけするシステム。https://www.alexa.com/ ↩︎

KIDANI AkitoKIDANI Akito

5.9 Webの完全な暗号化を目指して

p.138 Webの暗号化は部分的、個々のサイト管理者が責任を持つ
p.138 大手ブラウザベンダーを中心にWebの完全な暗号化を目指す過渡期
p.138 2017年のGoogleとMozillaの報告:全体の50%がHTTPS
p.138 ブラウザベンダー:暗号化が有効な場合だけブラウザの先進的機能を提供し、サイト管理者に暗号化を促す

●セキュリティ警告のスコープを拡大

p.138 セキュリティインジケータの範囲拡大:HTTPが安全でないという警告
p.138 2017年1月、Chrome56とFirefox51からHTTPでパスワードやクレジットカード番号入力するページに警告表示
p.138 Googleは2017年中にHTTPでフォーム送信するページに対象拡大を宣言[1][2]

●暗号化だけで利用可能な強力な機能

p.139 利用者の地理データのような情報をHTTPで使えなくする[3]

脚注
  1. このサイトによると、2017年10月のChrome 62で対応が完了した模様。 ↩︎

  2. Googleのブログによると、2020年9月にはChrome 86で混在フォーム(HTTPSページ上のHTTPフォーム)についても同様の警告が表示されるようになった。この機能については問題があったらしく、直後のバージョンで無効化され、そのつぎのバージョンで再度有効化されたと言われている。参考サイト ↩︎

  3. 註に挙げられていたページによると、地理データ以外には、デバイスの向き、AppCache、通知、カメラやマイクの利用、Encrypted Media Extensions (EME:HTMLで動画などのコンテンツを保護するためのAPI標準化仕様)が挙げられている。 ↩︎

KIDANI AkitoKIDANI Akito

5.10 EV証明書

p.139 SSLの黎明期にはすべての証明書発行時に厳格な検証が要求された
p.139 現在そのような検証はEV証明書についてのみ必要:2007年にCA/B Forumが規定
p.139 EV証明書の利点

  • ドメイン所有者の本人性が厳密に確認されて、その識別子が証明書にエンコードされている
  • 検証手順が手動であり、証明書の捏造が困難[1]

p.139 これらの利点は現実的な恩恵となるかは疑問:セキュリティインジケータは気付かれていない

参考:最近のChromeだとグリーンのインジケータはなくなり、EV証明書を表示する前に法人名が表示される

p.140 問題点:ページ単位で検出されるので、スクリプトなどのリソースでもEV証明書が利用されているとは限らない(コストを理由に、サブドメインではDV証明書が使われるケースも多い)
p.140 これを利用した攻撃手法がある(詳細はこちらのスライド

  • 他のドメイン名のサイトからリソースを持ち込む:詐称したDV証明書でマルウェアを仕込む
  • クッキー泥棒:既存のクッキーを盗む、新しいクッキーを設定する
  • 永続的マルウェア注入:キャッシュの利用を強要し、マルウェアを稼働させ続ける
脚注
  1. 厳密には捏造ではないが、別の州に同名の会社を設立して証明書を取得する手法が紹介されていた。参考サイト ↩︎

KIDANI AkitoKIDANI Akito

5.11 証明書の失効

p.140 理想的には証明書の失効確認すべきだが、とても難しい問題

5.11.1 クライアントの対応が不十分

p.140 ブラウザがなにをどのタイミングで実行しているか理解するのは困難
p.140 メーリングリストやバグ報告、ソースコードを掘り起こす必要がある
p.140 OCSPステープリングのような新しい機能はなかなかブラウザに搭載されない[1]
p.141 コマンドラインツールでは失効はもちろん証明書検証もままならない:デフォルトでは失効確認をしない[2]
p.141 失効確認は設計どおりには機能していない:2011年の一連の事件で、確実な手段はブラックリストだった

5.11.2 失効確認の標準化に伴う主な問題

p.141 CRLとOCSPの設計上の欠陥3つ

●証明書と問い合わせの分断

p.141 CRLもOCSPもCAが割り当てたシリアル番号で問い合わせる=手元の証明書とCAが参照している証明書が同一か完全には確認できない

●ホワイトリストではなくブラックリスト

p.141 CRLはブラックリストそのもの。初期のOCSPはCRLから情報を取得していた。
p.141 OCSPレスポンスでは問い合わせられたシリアル番号について何も知らなくてもgood(not revoked)扱いにしていた:2013年8月以降CA/B Forumで禁止された[3]
p.141 2011年のDigiNotar事件で現実の問題に:OCSPレスポンダが全てを失効扱い+ルート証明書をブラウザから削除して対応

●プライバシー

p.142 自分がどんなWebサイトを閲覧しているか、という情報がCAに知られてしまう
p.142 CRLには大量の証明書が含まれるので侵害度合いはやや低め
p.142 OCSPレスポンダへのトラフィックモニタリングでWebサイト閲覧同行を監視できる
p.142 この問題への対策がOCSPステープリング

5.11.3 CRL

p.142 当初の失効確認の唯一の仕組み:スケールしづらいためOCSPが作られた

■CRLの長さに伴う問題

p.142 GoDaddy社によると、同社の失効情報は2007年に158Kバイト、2013年に41Mバイト。
p.142 近年は、複数のCRLを利用することでサイズを抑えている。
p.143 大量データのダウンロードはモバイルで問題:帯域やCPU
p.142 差分CRL(delta CRL):Windowsでサポートされているがあまり使われていない

■CRLの新鮮さ

p.143 Netcraftの調査によると、McAfeeのサイトの中間証明書が失効に気づかれないまま放置された
p.143 このときOCSPの情報はなく、CRLには失効情報があったが無視されていた
p.143 Baseline Requirementsの記述

  • CAは12ヶ月に一度CRLを再発行しなければならない
  • CAは下位CA証明書の失効から24時間以内にCRLを再発行しなければならない
  • nextUpdateフィールドの値をthisUpdateから12ヶ月より後にしてはいけない

参考:RFC5280

   CertificateList  ::=  SEQUENCE  {
        tbsCertList          TBSCertList,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }

   TBSCertList  ::=  SEQUENCE  {
        version                 Version OPTIONAL,
                                     -- if present, MUST be v2
        signature               AlgorithmIdentifier,
        issuer                  Name,
        thisUpdate              Time,
        nextUpdate              Time OPTIONAL,
        revokedCertificates     SEQUENCE OF SEQUENCE  {
             userCertificate         CertificateSerialNumber,
             revocationDate          Time,
             crlEntryExtensions      Extensions OPTIONAL
                                      -- if present, version MUST be v2
                                  }  OPTIONAL,
        crlExtensions           [0]  EXPLICIT Extensions OPTIONAL
                                      -- if present, version MUST be v2
                                  }

p.143 中間証明書のCRLは12ヶ月間新鮮とみなされる

  • 数百万サイトで利用されるので、長期間(12ヶ月)保持したい
  • CRLはオフライン保管のルート証明書の鍵で署名されるので、頻繁には利用できない

p.143 サーバー証明書のCRLの場合は、10日以内とされている

5.11.4 OCSP

■OCSPリプレイ攻撃

p.144 OCSPオリジナル設計はリプレイ攻撃に強い:ナンスが含まれる
p.144 オリジナル設計はスケールせず、軽量版OCSPプロファイルでバッチ処理とキャッシュが導入:キャッシュのため、リプレイ攻撃耐性は断念
p.144 現在、クライアントはナンスを使わないし、サーバーも無視する
p.144 唯一の防御は有効期限のみ(nextUpdate):数時間から数日、DV証明書の方が長くEV証明書が短い
p.144 Baseline Requirementsの規定では10日間(中間証明書は12ヶ月)

■OCSPレスポンスの隠蔽

p.144 OCSPレスポンスの失敗はブラウザでは無視される
p.144 これを利用して、全てのレスポンスを失敗させて失効確認を隠蔽できる
p.145 OCSPレスポンスは通常電子署名が付与されるが、失敗の場合署名がつかない:これを利用して攻撃が可能[4]

■クライアントにおけるOCSP対応

p.145 古いプラットフォームやブラウザはデフォルトではOCSPを利用しない:Windows XP、10.7以前のOS X
p.145 iOSはOCSPと(おそらくCRL)をEV証明書にしか使わない
p.145 Chromeは2012年にOCSPを打ち切り、CRLSetsと呼ばれる軽量な仕組みを採用(CA証明書ばかりなので、セキュリティ的には劣る)
p.145 MozillaはCRLSetsを参考にOneCRLを導入

■レスポンダの可用性とパフォーマンス

p.146 OCSPは初期の問題から、ブラウザ側でソフトフェイル(失敗しても無視)扱い
p.146 Netcraftのレポートでパフォーマンスがわかる:https://uptime.netcraft.com/perf/reports/performance/CRL

●可用性

p.146 ハードフェイルの場合にはレスポンダがダウンすると自サイトもダウン
p.146 ソフトフェイルの場合も、ネットワークパフォーマンスに影響
p.146 認証が必要なWiFIネットワーク(キャプティブポータル)でOCSPレスポンダに到達できないことが多い

●パフォーマンス

p.146 そもそもOCSPはパフォーマンスが悪い:OCSPが終わらないと本来のWebサイトへ進めない
p.147 OCSPレスポンダのパフォーマンスがCAの最大の差別化要因

●正確性

p.147 あるCAでは証明書の生成からOCSPレスポンダの更新まで40分かかる場合も(その間リクエストが失敗する)

■強制OCSPステープリング

p.147 パフォーマンスと可用性を満たすかもしれないOCSP Must-Staple
p.148 ステープリングを強制できれば、証明書の盗用(攻撃)にOCSPレスポンスも必要となる
p.148 2016年のFirefox 45から強制OCSPステープリングが利用可能[5]

■サーバ側でのOCSP対応

p.148 主要OSSでOCSPステープリングがデフォルト有効なWebサーバはない[6]
p.148 対照的に、MicrosoftのIISではデフォルトで有効になっている
p.148 実装が貧弱:レスポンスの取得が遅い
p.148 OCSPレスポンスが得られない場合にHTTPリクエストへの応答を停止するサーバーも。

脚注
  1. Wikipediaによると、OCSPステープリングにはIEが2012年、Firefoxが2013年、Chromeが2014年に対応した。 ↩︎

  2. curlの場合、OCSPステープリングの機能はデフォルトではオフになっている。参考サイト。この機能には2017年に脆弱性が見つかっている↩︎

  3. Baseline Requirements 1.8.0, 2021.08.25の57ページに該当の記述あり。同じページには、セキュリティ対応のため、そのようなシリアル番号についてのリクエストを監視すべしとの規定も。 ↩︎

  4. RFC6960によると、malformedRequest、internalError、tryLater、sigRequired、unauthorizedのステータス。 ↩︎

  5. メーリングリストのやりとりで、Chromeについては2016年時点では対応予定なしとされている。その後2019年にもやはり対応されていない様子。 ↩︎

  6. 参考:ApacheのOCSPステープリング設定方法 ↩︎

KIDANI AkitoKIDANI Akito

第6章 実装の問題

p.149 ソフトウェアは必然的に安全でない

  • 言語とライブラリがセキュリティを考慮して書かれていない
  • コストの問題:時間的にも金銭的にも最小コストが要求されセキュリティがないがしろにされがち

p.149 「暗号は破られるのではなく迂回される」

6.1 証明書の検証における欠陥

p.149 証明書に関して確認すべき2つの事項

  • 証明書が意図したホスト名に対して発行されているか
  • 証明書が有効で信頼できるか

p.150 証明書を確認するコードを開発する際、実在の証明書チェーンだけで開発すると重要な検証機能を作り損ねる
p.150 検証の細部に悪魔が潜んでいる

  1. サーバ証明書が意図したホスト名に対して有効か
  2. 証明書チェーンの全てが、期限切れになっておらず、かつ、署名が有効である
  3. 中間CA証明書は場合によって以下の要求を満たす必要がある
  • 他の証明書に対する署名に使えること
  • 他のCA証明書に対する署名に使えること[1]
  • 末端の証明書におけるホスト名の署名に使えること

参考:RFC5280


      id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
      KeyUsage ::= BIT STRING {
           digitalSignature        (0),
           nonRepudiation          (1), -- recent editions of X.509 have
                                -- renamed this bit to contentCommitment
           keyEncipherment         (2),
           dataEncipherment        (3),
           keyAgreement            (4),
           keyCertSign             (5), // 他の証明書に対する署名に使えるかどうかのビット
           cRLSign                 (6),
           encipherOnly            (7),
           decipherOnly            (8) }

   id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
   BasicConstraints ::= SEQUENCE {
        cA                      BOOLEAN DEFAULT FALSE, // 上記5が立っている場合、TRUE=本証明書はCA証明書
        pathLenConstraint       INTEGER (0..MAX) OPTIONAL } // 0の場合、他のCA証明書には署名できない

p.150 他にも、鍵が協力か、弱い署名アルゴリズム(MD5やSHA1)が利用されていないか、なども確認必要

脚注
  1. 註に、エンドエンティティ証明書を発行するCA証明書は下位CA証明書を発行できてはいけない、とされている。しかし、RFCを掲載しているIETFのサイトの中間証明書「Starfield Secure Certificate Authority - G2」はpathLenConstraintの値が設定されていない=CA証明書を発行できる、ように見える。これって良いのか?CA/B Forumの使ってるGo Daddyの中間証明書も同様にpathLenConstraintの値がない。Baseline Requirementsでは「MAY be present」だからいいのか? ↩︎

KIDANI AkitoKIDANI Akito

6.1.1 ライブラリとプラットフォームにおける検証の不備

p.150 ライブラリの証明書検証の欠陥は決して珍しくはない

・Microsoft社のCryptoAPIにおけるBasic Constraints確認に欠陥があった事例(2002年

p.150 ルート証明書が信頼できればどんな証明書でも信頼してしまうバグ:中間者攻撃が可能になる
p.150 Windows以外にも影響(Mac上のOfficeやIEにも影響:参考、KDEのデフォルトブラウザKonquerorにも影響(どうして?))
p.151 2002年にMoxie Marlinspikeが発見、同氏はsslsniffというMITMツールを公開

・GnuTLSにおける証明書チェーン検証の欠陥(2008年)

p.151 チェーンの末尾にルート証明書を追記すると不正な証明書が信頼されてしまうバグ:中間者攻撃ができる
p.151 本来はチェーンの一部でないので無効

・OpenSSLにおけるDSAおよびECDSA署名検証の欠陥(2009年)

p.151 Googleのセキュリティチームが発見
p.151 DSAとECDSA署名検証時の境界値チェックが不十分で、MITM攻撃の可能性あり

・iOSにおけるBasic Constraintsの確認に欠陥があった事例(2011年)

p.151 iOS4の一部のバージョンで、証明書を下位CA証明書として利用してよいかをチェックしていなかった:エンドエンティティ証明書で証明書が発行できてしまっていた

・iOSおよびOS Xにおける接続検証の欠陥(2014年)

p.151 iOS6とiOS7、OS X 10.9のTLS接続認証のバグ:DHEおよびECDHEの接続がMITMで乗っ取られる
p.151 この記事によれば、goto文が連続で出現する行があったため、以降の行がデッドコードとなったことが問題:同記事によれば、TLS1.2の場合は別の関数を利用するため影響なし
p.152 TLSハンドシェイク中の問題のため、脆弱性のあるクライアントだけに標的を絞ることが可能
p.152 独自のライブラリを利用するChromeやFirefoxなどのクロスプラットフォームなアプリは影響を受けず

・GnuTLSにおける証明書チェーン検証の欠陥(2014年)

p.152 2つの脆弱性が発見された
p.152 1つは、X509バージョン1(既に廃止されたバージョン)の証明書が任意の中間CA証明書として扱われるバグ
p.152 もう1つは、先のApple同様のバグ:参考例外が発生すると間違ったエラーコードが返るが、証明書検証が成功してしまう

・OpenSSLのChangeCipherSpecインジェクション攻撃(2014年)

p.152 能動的な攻撃者がChangeCipherSpecメッセージ(値が1だけのメッセージ)をインジェクションして、予測可能なマスターシークレットのネゴシエーションを強制できる
p.152 ChangeCipherSpecはハンドシェイクプロトコルの一部でないため認証されないのが原因(=他のハンドシェイクメッセージのように、ハッシュ化して擬似乱数生成関数にかけてverify_dataとして扱われない)
p.153 攻撃にはクライアントとサーバーがOpenSSLである必要があるが、クライアントとしてはあまり利用されていないので影響は限定的:例、Android 4.4
p.153 SSL Pulseによれば、影響のあったサーバーは全体の14%

・OpenSSLにおける証明書チェーン検証の欠陥(2015年)

p.153 ネットワーク上の攻撃者が末端の証明書を中間CA証明書として利用可能だった
p.153 Metasploit:Metasploit Frameworkは、ペネトレーションテストを行うためのフレームワーク。

フランケン証明書によるテスト

p.153 研究者らが特殊加工した「フランケン証明書」でライブラリをテスト:元の証明書にランダムにフィールドや拡張を追加・変更したもの
p.153 それほど使われていないライブラリ(GnuTLSなど)で深刻な問題が見つかる

KIDANI AkitoKIDANI Akito

6.1.2 アプリケーションの検証における欠陥

p.153 2012年の論文でSSL証明書の検証に欠陥状況が明らかに
p.154 MITM攻撃に対して安全でない:Amazon EC2のJava SDK、AmazonとPaypalの小売事業者向けSDK、osCommerceやZenCart、Ubercartなどの統合型ショッピングカート、Javaの各種ミドルウェア(Apache Axis, Axis2, Coudhaus XFire)など
p.154 ライブラリのAPIがそもそもまずい:例)OpeSSLでホスト名の検証は開発者が実装する必要あり
p.154 安全でないライブラリがある、それを使い続けているのが問題
p.154 正しい実装もある(JavaのJSSE)が、開発者は開発中は証明書検証を無効にしがちなので本番環境で有効に戻っているか心配

6.1.4 ホスト名の検証における問題

p.154 ホスト名に対し証明書が有効であるかを検証するのは困難
p.154 複数の脆弱性の事例:2009年のBlack Hat USAで2件報告あり
p.154 C/C++で文字列の終端を示すNullバイトが問題

Hello world!\0
(\0がNullバイト)

p.155 一方で証明書はASN.1の標準記法に従う=文字列の表現方法がC/C++と異なる

Nullバイト(\0)を含む不正なホスト名:
    www.paypal.com\0.thoughtcrime.org

p.155 Black Hat USA 2009でのMoxie Marlinspikeの攻撃報告

  1. 上記ホスト名の証明書(なりすまし対象ホスト+Nullバイト+攻撃者のドメイン)
  2. CAはthoughtcrime.orgを有効なドメインと確認し証明書発行(現在は対策済みのはず)
  3. 脆弱なクライアントへのMITM攻撃が可能

p.156 脆弱なクライアントの例:GnuTLS、NSSライブラリ[1]、MicrosoftのCryptoAPI
p.156 結果として、IEやFirefoxも影響あり

脚注
  1. Netscope社が始めたNetwork Security Servicesプロジェクト。現在はMozillaが管轄。参考:https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS ↩︎

KIDANI AkitoKIDANI Akito

6.2 乱数生成における欠陥

p.156 乱数生成は安全な通信にとって本質的な構成要素
p.156 鍵の生成には乱数が必要、鍵はTLS接続のたびに生成される
p.156 欠陥のある乱数生成器(RNG)では256ビットの鍵長でも32ビットの鍵空間しかない場合も:総当たり攻撃が可能になってしまう

6.2.1 Netscape NavigatorにおけるRNGの欠陥(1994年)

p.156 SSLの設計をしたネットスケープコミュニケーションズ社のフラッグシップ製品
p.156 ブラウザ起動時からの経過時間をマイクロ秒で表した値と、OSのプロセスID・親プロセスIDから単純なアルゴリズムで乱数生成
p.156 1995年リバースエンジニアリングにより問題が発覚
p.156 攻撃の条件は2つ:当時のマシンで25秒程度で破れる(プロセスIDが分からなくても総当たりできるレベル)

  • 犠牲者と同じUnixマシンにアカウントをもつ(プロセスIDを特定できる)
  • ネットワークパケットからブート後の秒単位の起動時間を特定できる

参考:先日のKasperskyの件

KIDANI AkitoKIDANI Akito

6.2.2 DebianにおけるRNGの欠陥(2006年)

p.157 2006年9月に混入、2007年リリース、2008年に発見された問題
p.157 影響範囲が広い:Debianは広く普及しているLinuxディストリビューション、かつ、他のベース(例:Ubuntu)
p.157 根本原因:RNGにエントロピーを供給する箇所から1行コメントアウトしてしまった → エントロピーがプロセスIDのみの16ビット、事実上暗号がない(秘密鍵が容易に推測できる)
p.157 OpenSSHの鍵にも影響:配置場所が固定なので問題の有無を容易に確認できた
p.157 TLSの鍵への対応が困難:筆者はリモートからサーバの公開鍵をテストするツールを公開(SSL Lab)、CA側でも証明書リクエストの公開鍵をテストして対策
p.157 わかったこと:暗号に不慣れなひともOSSの暗号関係コードを修正してしまっている

p.158 乱数生成については、Windows 2000でも2007年に問題が発見されている:これはWindows XPにも影響があった。2013年にはNetBDS6.0(前年リリース)でも同様の問題があった。

KIDANI AkitoKIDANI Akito

6.2.3 組み込みデバイスにおける不十分なエントロピー

p.158 2002年の研究:RSA鍵(SSL/TLS用)の0.5%は安全ではない、DSA鍵(SSH用)の1.03%は安全ではない
p.158 主な原因はRNG
p.158 判明した問題はすべて組み込みデバイスのもの、サーバーで利用されるものは安全だった

●デフォルトの鍵であった

p.159 製品メーカーがデフォルトの鍵で出荷:全員が同じ鍵を使うため、台無し

●エントロピーが低いので鍵が使いまわされた

p.159 デバイスが初回起動時に鍵を生成する:エントロピーが不足し、予測可能となる
p.159 画面なしデバイスのLinuxのブートをシミュレーションした研究で、起動後数秒はエントロピーが不足することが明らかに

●素因数分解可能な鍵

p.159 RSA鍵の多くで、2つの素数のうち1つが同じ値であった
p.159 原因はエントロピーが小さい場合のOpenSSLコード

p.159 暗号処理を伴うアプリはOSから十分なランダムさを得られると想定していたが、そうではない:かつ、ランダムさが不十分であることをアプリ側で知ることができない
p.160 自分で対処するアプリ開発者もいるかもしれないが、うまくいかないのでやめた方がよい

KIDANI AkitoKIDANI Akito

6.3 Heartbleed

p.160 2014年4月に公となったOpenSSLの脆弱性:TLSプロトコル拡張のHeartbeetプロトコルの実装の欠陥
p.160 暗号技術の問題ではなく、OSSの品質の問題(OpenSSLの資金難と低いコード品質)
p.160 Linux FoundationがCore Infrastructure Initiativeという計画で資金提供:OpenSSLでは 2 名のフルタイム開発者が資金提供を受けて開発
p.160 一方で、OpenBSDプロジェクトではLibreSSLをフォークして急ピッチで改修を進めた

KIDANI AkitoKIDANI Akito

6.3.1 影響

p.160 返信するデータの長さの確認を怠っている(複数箇所で)=攻撃者がデータを引き出しうる
p.160 1回のHearbeatリクエストでサーバーのメモリ64Kバイトを取得可能
p.160 サーバーのメモリ上のデータ、特に秘密鍵や、セッションチケットの鍵、SSL/TLSセッションの鍵、パスワードなどが攻撃対象
p.160 OpenSSL 1.0.1〜1.0.1fまでが影響を受ける:Netcraftの推定では全世界で17%(約50万台)

KIDANI AkitoKIDANI Akito

p.161 SSL/TLS史上まれな迅速さでパッチ適用:問題の深刻さ、無料診断ツール、メディアの注目
p.161 脆弱性公表から1ヶ月後には1.36%に減少:メジャーなサイトでは0.8%
p.161 脆弱性公表当初は、秘密鍵の抜き取り可能性は証明されていなかったが、のちに可能と判明
p.161 VPNサーバからTLSセッション鍵を抜き出し、多要素認証の迂回に成功した事例も
p.161 その他:社会保障番号(カナダの税務署)、パスワード(イギリスの育児サイト)
p.161 攻撃ツールも多数:数分で脆弱なサーバを攻撃可能、自動で秘密鍵を発見できるツールも
p.161 バグの詳細は12.14節で後述

6.3.2 緩和策

p.161 一番有効なのはセキュリティパッチ
p.162 Heartbeatプロトコルを無効にしてビルドする対策もある:その後依存するパッケージの再コンパイルが必要
p.162 OpenSSLを利用するアプライアンス製品はそれぞれパッチ適用が必要
p.162 次の対策として、流出した可能性のあるデータの対策
p.162 データ対策1:サーバの秘密鍵の入れ替え、新しい証明書取得、古い証明書の失効
p.162 Netcraftの調査では、上記3つの対策のいずれかが漏れているケースが86%
p.162 データ対策2:セッションチケットの鍵を入れ替える、ユーザーのパスワード変更
p.162 ほかにも、データベースのパスワードなども流出した可能性がある
p.162 PFS(前方秘匿性)に対応していると救いがある:過去の通信が復号されないので。
p.162 OpenSSLクライアントも脆弱なので、サーバーからクライアントプロセスのメモリを抜き出すこともできる[1]

Ticketbleed

p.163 2017年2月、F5社の製品でHeartbleedと類似の脆弱性発見
p.163 セッションIDが32バイトでハードコーディングされていた:1バイトのデータを送りつけると31バイト分のメモリを入手可能

脚注
  1. pacemakerのreadmeによると、wget 1.15、curl 7.36.0、git 1.9.1などが脆弱 ↩︎

KIDANI AkitoKIDANI Akito

6.4 FREAK

p.163 2015年1月、OpenSSLから深刻度LowのCVE-2015-0204が公開:最高強度のRSAでハンドシェイク中に輸出用の弱いRSA鍵を受け入れてしまう
p.163 3月、研究者らが上記を利用してMITM攻撃に成功、深刻度をHighへ変更
p.163 FREAK=Factoring RSA Export Keys(輸出用RSA鍵の素因数分解)

6.4.1 輸出用暗号

p.163 1998年9月まで、アメリカは強力な暗号技術の輸出を規制:暗号処理は40ビット、鍵交換については512ビットまでに制限
p.163 上記制限におさめるための特別設計が輸出用暗号スイート
p.163 RSAではパフォーマンスのため認証と鍵交換が組み合わさっている:認証については強力な暗号が許可されていたが、認証と鍵交換を切り離せない
p.163 解決策:意図的に弱いRSA鍵を用意するようSSL/TLSプロトコルを拡張した(認証は強力なRSA、鍵効果では常に弱い512ビット鍵を利用)
p.163 Server-Gated Cryptography(SGC):米国企業向け証明書に特別な識別情報を埋め込み、クライアントに再ネゴシエーションをさせる方式
p.164 2001年1月、アメリカが輸出制限を緩和し、輸出用暗号スイートは廃止された
p.164 廃止されたが、ライブラリのコードには残っており、これが動作してしまった

KIDANI AkitoKIDANI Akito

6.4.2 攻撃

p.164 RSA鍵交換:ランダムなプリマスターシークレットをサーバの公開鍵で暗号化して、クライアントが送信
p.164 クライアントが輸出用暗号スイートを要求した場合

  1. サーバが弱いRSA鍵を生成、サーバの強い鍵で署名
  2. 署名した鍵をServerKeyExchangeメッセージでクライアントに送信
  3. クライアントは弱い鍵でプリマスターシークレットを暗号化して送信

p.164 鍵が弱くとも、署名が強力なので、ネットワーク上の攻撃者は鍵を能動的攻撃に利用できない
p.164 受動的攻撃は容易:全てのメッセージを記録し、弱い鍵に総当たり攻撃をしてプリマスターシークレットを取得して、通信を復号可能(数時間以内)
p.164 FREAK攻撃は、クライアントが輸出用暗号スイートをサポートしている必要がない:脆弱なライブラリはRSA鍵交換中にServerKeyExchangeメッセージを受け入れてしまい(参考:通常RSAではこのメッセージは不要)、弱い鍵が使われてしまう
p.164 OpenSSLでは上記挙動が機能として実装されていた(SSL_OP_EPHEMERAL_RSAオプション):サーバのRSA鍵がプリマスターシークレットの保護に使われるので、PFSがない
p.164 攻撃者はサーバーからServerKeyExchangeメッセージが送られるようにしないといけないが、障害が2つある

  • ServerKeyExchangeメッセージに対する署名は攻撃対象サーバの強力なRSA鍵で暗号化されている(client_randomを暗号化する必要がある:参考
  • サーバーからの適切なFinishedメッセージを捏造しなければならない

p.165 攻撃者が中間者攻撃で、ClientHelloのランダム値をコピーし、輸出用暗号スイートを要求(=輸出用暗号に対応しているサーバのみ攻撃可能):参考
p.165 攻撃者はServerKeyExchangeをクライアントに再利用する:ClientHelloのランダム値をコピーしているのでクライアントで検証がパスする

p.166 Finishedメッセージの捏造:鍵交換で512ビットにダウングレードできているのでこれを利用して総当たり攻撃、プリマスターシークレットを取得して接続を制御可能
p.166 2017年現在では、512ビット鍵は決して弱すぎるわけではない:リアルタイムで破れる組織もあるが、誰もが心配する必要はないー>2021年には250ドルで破られた事例
p.166 ただし、パフォーマンス改善のために、鍵の使い回しをしているケースもあり、問題が深刻
p.166 今回の例では、研究者がAmazon EC2を利用し100ドル7時間で鍵を突破した

KIDANI AkitoKIDANI Akito

6.4.3 影響と緩和策

p.166 OpenSSLを使っているブラウザ:Android(数十億台)など
p.166 ブラウザ以外にもモバイルアプリにも影響[1]
p.166 他にも、AppleのSSLライブラリSecure Transport(OS X 10.8.x以降、iOS8.2以降で修正)、MicrosoftのSSLライブラリSchannelにも同様の脆弱性が発見された:これらのライブラリはデプロイ形態が多様なので、脆弱性有無の切り分けが困難、SSL Labsなどでのクライアント用のテスト実施が確実
p.166 Firefoxだけは影響なし
p.167 古い不要な機能は削除すべき好例:攻撃対象領域が狭まり、リスクも低減する
p.167 FREAK脆弱性の公開前は、インターネット上の安全なサーバのうち1/4が弱い暗号スイートを提供
p.167 そのうち、2/3が弱い鍵を接続のたびに使いまわしており、脆弱であった

FREAKを発見したmiTLS

p.167 miTLSはMicrosoft ResearchとInria Joint Centre[2]のプロジェクト
p.167 TLSの脆弱な実装を多数発見[3]

脚注
  1. 100万人以上ユーザーのいるAndroidアプリ1200以上が脆弱、iOSアプリの上位14000のうち771件が脆弱。参考 ↩︎

  2. INRIA:Institut National de Recherche en Informatique et en Automatique(フランス国立情報学自動制御研究所)。1979年設立、OCamlなどを開発。Wikipediaより ↩︎

  3. サイトによると、SKIP-TLSという攻撃がある(CVE-2014-6593)。通常、DH鍵交換ではServerKeyExchangeメッセージが必須だが、RSA鍵交換ではこれは不要となる。しかし、いくつかの実装では暗号スイートで必須となるメッセージが誤ってスキップされてしまう。これは、ライブラリが異なる暗号スイートのコードをコピペしているため発生する。JDKにデフォルトで付属するJSSEクライアントは、中間者攻撃に対して全く安全ではなかったことになる。Google、Paypal、AWSなどのJava SDKも影響を受けた。これはJava 8u25、7u72、6u85、5.0u75以前が影響を受ける。参考 ↩︎

KIDANI AkitoKIDANI Akito

6.5 Logjam

p.167 FREAKはRSA鍵交換に対する攻撃:DHE鍵交換への攻撃も時間の問題と考えられた(DHEでも輸出用暗号スイートは512ビットの鍵を利用)
p.167 2015年5月:Logjam攻撃発表
p.167 Log=DH鍵交換の原理「一方向関数の離散対数問題(Discrete Logsrithm Protocol)」に由来

6.5.1 安全ではないDHE鍵交換に対する能動的な攻撃

p.168 最初の手法:FREAKを模倣し、リアルタイムに破れる弱いDHE鍵交換を強制する中間者攻撃
p.168 FREAKとの違い3つ

  • サーバが安全ではないDHパラメータを使ってしまう
  • DHE鍵がサーバでキャッシュされている
  • クライアントが弱いDHパラメータを受け入れてしまう
サーバが安全ではないDHパラメータを使ってしまう

p.168 DHE鍵交換:サーバは一時的な鍵を生成し、認証のために自身の秘密鍵で署名する
p.168 Logjam攻撃:サーバが輸出用暗号スイートを使う場合に弱い一時的鍵を利用させる
p.168 安全でないDHパラメータが利用される場合、受動的攻撃(全記録し後日復号など)もありうる:サーバで通常より高速なECDHEやRSA鍵交換が選択され、DHEがネゴシエーションされる可能性は低い

DHE鍵がサーバでキャッシュされている

p.168 能動的攻撃の成功条件:モダンブラウザがハンドシェイクを諦めるまでのおよそ1分以内に、適切なFinishedメッセージを生成できる
p.168 1分以内に512ビットDHE鍵を破るのは、熟練した攻撃者でも困難
p.168 しかし、鍵がキャッシュされているサーバの場合は、事前に鍵を破ることでリアルタイム攻撃が可能
p.168 15%のサーバで鍵がキャッシュされていたが、512ビットのDHパラメータを利用しており脆弱だったのは0.1%
p.168 MicrosoftのIISは一時的な鍵を2時間キャッシュ

クライアントが弱いDHパラメータを受け入れてしまう

p.168 攻撃公開当初は、全てのメジャーなブラウザで512ビットの鍵交換が許可され、脆弱だった
p.168 輸出用暗号スイートに対応していないクライアントも攻撃可能:DHパラメータの強度指定はサーバが行うため

p.169 Logjamが明らかにしたTLSプロトコル自体(実装ではない)の欠陥:DHパラメータのサーバ署名が再送できてしまう(リプレイ攻撃)
p.169 攻撃者:クライアントの乱数を別のハンドシェイクで再利用し、本来選択されない暗号スイートをネゴシエーションさせる

6.5.2 安全ではないDHE鍵交換に対する事前計算攻撃

p.169 Logjam攻撃公表時、DHパラメータの大半は1024ビット、一部768ビットで十分強い:しかし、政府機関なら事前計算攻撃の余地あり
p.169 DH鍵交換:ドメインパラメータ(素数pと原始根g)はTLS1.2以下ではネットワーク越しに送信され攻撃者も閲覧可能
p.169 DH鍵交換を破るには、鍵交換で生成される一時的な秘密鍵2つのうち1つが必要
p.169 DH鍵交換への攻撃:NFS(Number Field Sieve、数体ふるい法)を2段階にわける。前半が素数pのみに依存する
p.169 512ビットの素数pへの事前計算は1週間、その後の鍵交換は60秒未満で可能

KIDANI AkitoKIDANI Akito

6.5.3 国家機関が弱いDH鍵交換に対する脅威となる場合

p.170 Logjam論文の共著者による推定

事前計算(1コア/年) 個々の攻撃(1コア)
DH-512 10 10分
DH-768 36,500 2日
DH-1024 45,000,000 30日

p.170 ただし、事前計算は並列化と更なる最適化が可能:768ビットDHパラメータは研究者レベルでも攻撃可能
p.170 1024ビットの場合、数億ドルかかるハードウェアでも攻撃完了に1年かかる計算
p.170 実際には、標準グループ[1]のDHパラメータが使いまわされる=同一の素数が多数のサーバで利用されるため、1回の事前計算で何万台ものサーバを攻撃可能
p.170 標準グループを使うべき理由:実装者がセキュリティプロトコルを実装するとミスが起こりやすい
p.170 Logjamの本質的な問題:利用されている標準グループが弱すぎた

6.5.4 影響

p.170 最悪のケース:DHEでネゴシエーションし安全でないDHパラメータを使うサーバ(受動的攻撃に弱い、後日復号される)
p.170 次点:安全でないDHパラメータを使うが通常RSA/ECDHE鍵交換が行われる
p.171 受動的攻撃の場合、1024ビットのDHグループを1つ破ると、HTTPSサーバの6.56%に影響:10グループだと約10%
p.171 能動的攻撃の場合、1グループで12.8%、10グループで23.8%

p.171 モダンブラウザのFalse Start機能:TLS完全性検証より前の段階でHTTPリクエストを送る(パフォーマンス重視)ため、そこから機微情報を得られる場合もある

p.171 TLS以外のプロトコルへの受動的攻撃もある:SSHやIPSecでは1024ビットのDHパラメータが使われることが多い
p.171 筆者の推定では、標準グループの1つを破ると、25.7%(36億台)のSSHトラフィックを、60%以上のIPSecとフラフィックを受動的に復号・傍受可能

NSAは1024ビットのDH鍵交換を破れるのか

p.171 Logjam論文の共著者らの考えでは可能:NSAの年間予算は100億ドルを超える
p.171 事実、NSAはVPNトラフィックを解読できるらしいとスノーデンのリーク文書に記載:復号のアーキテクチャについては言及なし

脚注
  1. RFC3526(2003年)RFC7919(2016年)で定められている ↩︎

KIDANI AkitoKIDANI Akito

6.5.5 緩和策

p.171 輸出用暗号スイートを無効にすれば十分
p.171 DHEを含む暗号スイートについては、2048ビットのDHパラメータを使う
p.172 Java 6のクライアントは1024ビットを超える強度に対応していない問題がある
p.172 1024ビットのパラメータを使う場合、標準グループを使用しない方が良い
p.172 あるいはDHEを無効化すべし:RSAやECDHEよりかなり遅い(パフォーマンスについては第9章参照、RSAはPFSがないので使うべきではない)
p.172 DHEを無効にすると、ごく一部の通信でPFSがうしなわれる程度の影響[1]
p.172 ブラウザベンダもDHパラメータの最低強度を768ビットまたは1024ビットに引き上げた:長期的にはDHのサポートはなくなりECDHEに移行するはず

脚注
  1. ECDHEに対応していないクライアントがRSAを利用するから、ということか? ↩︎

KIDANI AkitoKIDANI Akito

6.6 プロトコルダウングレード攻撃

p.172 TLSハンドシェイク時にパラメータに影響を与え、弱いプロトコルや暗号スイートを強制する能動的な攻撃
p.172 SSL2.0ではハンドシェイクの完全性が保証されず、このような攻撃に弱い
p.172 一方、ブラウザはプロトコルのバージョン間の相互運用のためにセキュリティ面で妥協することも

6.6.1 SSL3.0のプロトコルロールバック対策

p.172 SSL3.0((RFC6101)[https://datatracker.ietf.org/doc/html/rfc6101#section-5.6.9])では、ClientHelloのフォーマットが変更され[1]、Finishedメッセージにおけるハンドシェイクメッセージの完全性検証が導入された。

SSL2.0のCLIENT-HELLO
uint8 V2CipherSpec[3];
struct {
    uint8 msg_type;
    Version version;
    uint16 cipher_spec_length;
    uint16 session_id_length;
    uint16 challenge_length;
    V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
    opaque session_id[V2ClientHello.session_id_length];
    Random challenge;
} V2ClientHello;

参考:RFC2246

SSL3.0のClientHello
struct {
    ProtocolVersion client_version;
    Random random; // CHALLENGEから名称・位置変更
    SessionID session_id;
    CipherSuite cipher_suites<2..2^16-1>;
    CompressionMethod compression_methods<1..2^8-1>; // 追加
} ClientHello;

p.173 SSL3.0に対応したサーバは互換性のあるクライアントとの通信時に自動的にSSL3.0にアップグレードすることになっていた:3つの問題点

  1. 多くのサーバでSSL2.0しか解釈されずSSL3.0のフォーマットが使えない
  2. サーバがSSL3.0に対応していてもMITM攻撃の場合はSSL2.0のみのサーバに見せかけられる
  3. SSL2.0を使う場合ハンドシェイク完全性が保証されずMITM攻撃が容易

p.173 上記の問題点をふさぐためのプロトコルロールバック対策:双方がSSL3.0を解釈する場合に、攻撃を検知できる仕組み
p.173 SSL3.0クライアントがSSL2.0にフォールバックする際、RSA鍵交換[2]のPKCS#1ブロック末尾を8バイトの0x03でパディング(SSL2.0ではランダムな8バイト、無視される):SSL3.0を解釈するサーバはこれを検知してハンドシェイクを中断できる
p.173 抜け穴が1つ:SSL2.0では最悪の場合40ビットのRSA鍵しかないため、現在の計算機なら簡単に突破可能

脚注
  1. SSL2.0の仕様を見ると、見慣れたTLS1.2のハンドシェイクとかなり異なるのが分かる。 ↩︎

  2. SSL2.0では認証と鍵交換のための仕組みはRSAのみだったので、ロールバック対策としてRSAのみカバーすれば十分だった。SSL3.0ではDH、DHEやFORTEZZAが追加された ↩︎

KIDANI AkitoKIDANI Akito

6.5.3 相互運用性の問題

■バージョンに対する不寛容

p.174 SSL2.0では進化が想定されておらず、未知のプロトコルバージョンが扱えなかった:Netscapeのリファレンス実装SSLREFでは大きいバージョンの接続を拒否
p.174 SSL3.0でのクライアントのバージョンの扱い: ServerHelloメッセージのserver_versionフィールドにクライアントで提案された値とサーバでサポートされる最大値のいずれか小さい方が入る

SSL3.0のServerHelloメッセージ
struct {
      ProtocolVersion server_version;
      Random random;
      SessionID session_id;
      CipherSuite cipher_suite;
      CompressionMethod compression_method;
} ServerHello;

p.174 TLS1.0から後方互換性に関する記述が増えたが、明確な指針はTLS1.2になってから示された:TLS1.2をサポートしないサーバは、TLS1.2のリクエストに対して古いバージョン番号で応答し、クライアントが同意すれば古いバージョンのプロトコルでネゴシエーション継続
p.174 ただし、仕様が曖昧だったので、多くのサーバではTLS1.2以下の場合接続を拒否した結果、ブラウザでTLS1.2対応が進んだ時に相互運用性の問題が生じた
p.174 このため、最初にTLS1.2に対応したIE[1]では、TLS1.1/1.2を初期設定では無効化してリリースされた
p.174 この問題の解決のための拡張がRenegotiation Indication(TLS1.2のリリースから2年後の2010年):RFC5246(TLS1.2)の要件を改めて規定
p.175 レコードプロトコルのTLSバージョンにも不寛容の問題:ライブラリによってTLS1.0だったり最良バージョン(TLS1.2)だったり
p.175 TLS1.3にとって深刻な問題:レコードプロトコルで新しいバージョンを利用すると、TLS1.3だと10%以上、TLS2.0だと70%のサーバがハンドシェイクを拒否する試算
p.175 TLS1.3ではレコードプロトコルでのバージョンはTLS1.2に固定し[2]、拡張を利用。

■拡張についての不寛容

p.175 SSL3.0/TLS1.0にはプロトコルを改訂せずに新機能を追加する仕組み(拡張)がなかった:ClientHelloの末尾に付加的データを追加できる(ただしSSL3.0/TLS1.0のサーバの大半は付加的データを指定するクライアントの接続を拒否)[3]
p.175 これは、SSL3.0から8年後の2003年にRFC3546でTLS拡張となり、2008年のTLS1.2で統合された

■相互運用性に関する他の問題

●長いハンドシェイクメッセージに対する不寛容
p.176 ClientHelloメッセージには長さの上限がないが、初期のクライアントは対応する暗号スイートが少ないためClientHelloが短かった
p.176 OpenSSL1.0.1でTLS1.1/1.2をサポートするようになり、拡張への対応からClientHelloの長さが著しく増加
p.176 F5社のBIG IPロードバランサでは255バイト以上512バイト未満のハンドシェイクメッセージを処理できず、TLS1.2普及の足枷となった

●任意の拡張に対する不寛容
p.176 SNI拡張及びStatus Request拡張(OCSPステープリング)で、ネゴシエーションに失敗することがある(明確な理由はない)

●フラグメンテーションの適切な処理の失敗
p.176 フラグメンテーション:分割され、レコードプロトコルの複数のメッセージで配送される
p.176 大半の実装ではアプリケーションデータ・サブプロトコルの分割には対応しているが、それ以外のメッセージのフラグメンテーションについては処理に失敗する
p.176 同様に長さゼロのレコードの処理に失敗する実装もある:このため予測可能なIV(初期化ベクター)問題への対策が頓挫

脚注
  1. バージョンはおそらくIE8(Windows 7以降)。 ↩︎

  2. 本文中では1.0となっているが、RFC8446を読むと0x0303なのでTLS1.2が正しい。ClientHelloでは互換性のため0x0301(TLS1.0)をバージョンとして利用してもよいとされている。 ↩︎

  3. SSL3.0のRFC6106を見ると、確かに「5.6.1.2. Client Hello」の節の最後にForward compatibility noteとして構造体として記載された以外のextra dataを追加して良いと記載がある。 ↩︎

KIDANI AkitoKIDANI Akito

6.6.3 プロトコルの自発的なダウングレード

p.176 ブラウザは自発的なダウングレードで相互運用性の問題に対応:徐々にバージョンを引き下げて成功するまで試す
p.176 サーバが不寛容でなくても、プロキシやファイアウォール、アンチウイルスソフトなどにより接続がフィルタリングされることもある
p.177 筆者による2014年6月時点での調査:全ての主要なブラウザでSSL3.0へのダウングレード可能
p.177 IE6ではSSL2.0までダウングレード可能
p.177 TLS1.2より古いバージョンのプロトコルの問題点

  • SSL3.0はPOODLE攻撃で暗号化された小さなデータ(クッキーなど)を抜き出される
  • GCM, SHA256, SHA384の暗号スイートに未対応
  • 楕円曲線暗号に対応していないため、PFSがない
  • TLS1.0以前はBEAST攻撃や脆弱なRC4ストリーム暗号[1]を使える(それぞれ詳細は7章)
  • Microsoft社のSSL3.0スタックではAESに未対応で、RC4と3DES[2]の暗号スイートのみ

p.178 モダンブラウザはPOODLE攻撃の発見を受けてSSL3.0へのダウングレードをやめ、SSL3.0を無効化
p.178 大きな流れとして、フォールバックを完全になくす方向にあるため、ダウングレードは解消されつつある過去の問題

脚注
  1. RC4を禁止するRFC7465は2015年に規定された。 ↩︎

  2. 3DESはDESを強化して1998年に登場したが、2018年に米国立標準技術研究所(NIST)が2023年以降の利用を禁止した。参考CRYPTREC暗号リストでも、運用監視暗号リストに入れられ、互換性維持のためのみ利用を許可されている。 ↩︎

KIDANI AkitoKIDANI Akito

6.6.4 TLS1.0以降のロールバック対策

p.178 SSL3.0以降はマスターシークレットが384ビット(48バイト)となったため、総当たり攻撃不可(SSL2.0では輸出規制のため40ビットの場合があった)
p.178 TLS1.0以降のRSA鍵交換のロールバック保護の仕組み:PreMasterSecret内のバージョン番号をClientHello.client_versionとする

RFC5246(TLS1.2)のClientKeyExchangeメッセージ
      struct {
          select (KeyExchangeAlgorithm) {
              case rsa:
                  EncryptedPreMasterSecret;
              case dhe_dss:
              case dhe_rsa:
              case dh_dss:
              case dh_rsa:
              case dh_anon:
                  ClientDiffieHellmanPublic;
          } exchange_keys;
      } ClientKeyExchange;
RFC5246(TLS1.2)のEncryptedPreMasterSecret
      struct {
          ProtocolVersion client_version;
          // The latest (newest) version supported by the client.  This is
          // used to detect version rollback attacks.
          opaque random[46];
          // 46 securely-generated random bytes. 
      } PreMasterSecret;

      struct {
          public-key-encrypted PreMasterSecret pre_master_secret;
      } EncryptedPreMasterSecret;

p.178 DH鍵交換の場合は以下の通りバージョン番号がカバーされていない

RFC5246(TLS1.2)のClientDiffieHellmanPublic
      enum { implicit, explicit } PublicValueEncoding;

      implicit
         If the client has sent a certificate which contains a suitable
         Diffie-Hellman key (for fixed_dh client authentication), then
         Yc is implicit and does not need to be sent again.  In this
         case, the client key exchange message will be sent, but it MUST
         be empty.

      explicit
         Yc needs to be sent.

      struct {
          select (PublicValueEncoding) {
              case implicit: struct { };
              case explicit: opaque dh_Yc<1..2^16-1>;
          } dh_public;
      } ClientDiffieHellmanPublic;

      dh_Yc
         The client's Diffie-Hellman public value (Yc).

p.178 プロトコルの実装を行う開発者たちがバージョン番号を適切に使えていない問題
p.178 Opera開発者Yngve Pettersenの発言「多くのクライアントとサーバは正しく実装されていない」
p.179 TLS1.2の仕様でも明言「古い実装ではネゴシエーションされたバージョンを代わりに使っている」[1]
p.179 ロールバック防御の仕組みがあるが、結局は自発的ダウングレードを利用して攻撃可能

6.6.5 プロトコルの自発的なダウングレードを悪用した攻撃

p.179 MITM攻撃でデータを変更せずに、SSL3.0以上の接続をブロックすれば十分:別の対策が必要

脚注
  1. RFC5246 7.4.7.1 RSA-Encrypted Premaster Secret Message "Unfortunately, some old implementations use the negotiated version instead, and therefore checking the version number may lead to failure to interoperate with such incorrect client implementations." ↩︎

KIDANI AkitoKIDANI Akito

6.6.6 現代的なロールバック攻撃への防御

p.179 能動的な攻撃者によってダウングレードさせられてしまう

p.179 2011年提案のSCSV(Signaling Cipher Suite Value)[1]

追加されたCipherSuite
        TLS_FALLBACK_SCSV          {0x56, 0x00}

p.179 SCSVでクライアントの最良プロトコルを伝達できる:ClientHello.client_versionで最良でないプロトコルを指定する時に、ClientHello.cipher_suitesに以下を追加することで達成する[2]
p.180 サーバー側がバージョンのずれを検知した場合、以下のアラートで接続を終了させる

追加されたアラート
        enum {
          /* ... */
          inappropriate_fallback(86),
          /* ... */
          (255)
        } AlertDescription;

p.180 SSL3.0では拡張に対応していないため、このような暗号スイートによるシグナリングが利用された
p.180 2012年には同様のシグナリングが提案された

Adam Langley氏の提案した暗号スイート
 TLS_CAPABLE_SCSV (0x00fe)

p.180 サーバーではなくクライアントで検知すべしという議論も:更新が必要なのは一部のユーザーエージェントなので、デプロイが楽という理由
p.180 RFC5764(再ネゴシエーション)をベースにした提案:RFC5764では将来のバージョン番号への不寛容が禁止されている(0.14%がこれに違反していた)、提案者がOperaに実装
p.180 2013年4月から9月にかけての議論がRFC7507として結実:Chrome 33が最初に実装
p.181 SCSV方式の場合サイト(サーバー)の対応が必要なので、普及に時間がかかる

6.6.7 将来の相互運用性の問題を防ぐGREASE

p.181 開発者が仕様を十分に読まず、自分達に都合のいいように実装してしまうことが原因:問題のあるコードを強制的に更新できず、何の対処もできないこともある
p.181 Chromium開発者David BenjaminはTLSプロトコルに対して不正な値をランダムに混入させ続けるクライアントGREASEを実装(Chrome 55から利用):不寛容なサーバは問題を起こす

脚注
  1. 2015年にRFC7507 TLS Fallback Signaling Cipher Suite Value (SCSV) for Preventing Protocol Downgrade Attacksとなったが、2021年3月のRFC8996 Deprecating TLS 1.0 and TLS 1.1で廃止された(TLS1.3では ServerHello.Randomを用いた別の仕組みでカバーしているため) ↩︎

  2. 以下の場合は、cipher_suitesにSCSVを含めてはいけない:セッション再開時に最良でないプロトコルを選択する場合、または、クライアントが最良のバージョンをClientHello.client_version で指定する場合。 ↩︎

KIDANI AkitoKIDANI Akito

6.7 強制切断攻撃

p.181 攻撃者によるメッセージ配送妨害
p.181 SSL2.0は強制切断攻撃に対して脆弱:SSL3.0でclose_notifyが追加され解消
p.181 RFC5246(TLS1.2):双方がclose_notify警告を送り、これを受け取ったら接続を閉じ書きこみ待ちの情報を破棄すべし
p.182 close_notifyはalertサブプロトコルなので暗号化されており完全性検証が可能
p.182 ただし、接続終了の手続きに違反している例は多い:Internet Explorerなど[1]
p.182 上記の違反により、正しく実装されたアプリで強制切断攻撃と誤検知されてしまっている
p.182 過去の経緯から、強制切断攻撃に対する防御は事実上ない

  • SSL3.0:最初に接続を終了する側は相手のclose_notifyを待つ必要なし
  • TLS1.1:接続が適切に終了されなかった場合に、セッションを破棄しなくなった

6.7.1 強制切断攻撃の歴史

p.182 2007年、BerbecaruとLioy:ブラウザはページの一部を表示したあとの強制切断時に、ページが不完全であることを明示せず
p.182 2013年、SmythとPironti:電子投票システムやWebメール(GoogleやMicrosoft)への攻撃(利用者に気づかれず、ログアウトに失敗させ、利用者がログインしたままにできてしまう)
p.183 HTTPのメッセージに送信データ長が含まれているにもかかわらず、Webをとにかく動くものにしているため、TLS層でこのような攻撃が可能

6.7.2 クッキーカッター攻撃

p.183 2014年に効果的な強制切断攻撃手法が判明
p.183 HTTPリクエスト/レスポンスに任意の長さのデータを挿入し、TLSレコード長を制御(BEAST攻撃の応用、詳細は7.2節)、レコードの分割点を変えHTTPリクエストヘッダやレスポンスヘッダの一部を削り取る
p.183 レスポンスヘッダ

[サーバからのレスポンス]
Set-Cookie: JSESSIONID=XXXXXX; Path=/; Secure; HttpOnly(改行コード、CRLF)

[強制切断攻撃後のレスポンス]
Set-Cookie: JSESSIONID=XXXXXX; Path=/;

p.183 改行コードがなくなっている不完全な状態でも、ブラウザが無視して処理を継続してしまう場合も(Android Chrome 27Safari Mobile 7.0.2など:2013年ごろのバージョン)
p.184 攻撃は手が混んでいるが、自動化すれば現実的

  • 攻撃対象のWebサイトとセッションを確立していない(=古いクッキーがない)利用者を攻撃する
  • HTTPレスポンスに任意のデータを挿入できるエントリーポイントを探す(できればリダイレクトされるログインAPIなど、画面表示のないもの)
  • レスポンスヘッダを2つのTLSレコードに分割するパディングを送信する(16384バイトを超えるようにする)
  • 1つめのTLSレコードの後でHTTPS通信を閉じる(TCPのRSTシグナルを送る)
  • Secure属性のないクッキーを抜き出す(クッキー窃取攻撃)

p.185 HSTSのレスポンスヘッダも攻撃対象:max-ageパラメータを切り詰めて最大9秒にしたり、includeSubDomainsパラメータを無効化し、HTTPSストリッピング攻撃などが可能
p.185 クッキーカッターはブラウザの対応で対処可能:修正しているベンダもいるが、大半のブラウザの実情ははっきりしない

脚注
  1. あるサイトでは、「MS-IE/OEのTLS/TCP処理では、「close_notify アラート」を送信せずに、TCPクローズを行う。しかも、そのTCPクローズでも、FIN/ACK送信ではなく、RST(リセット)送信でクローズすることもある。」と書かれていた。参考 ↩︎

KIDANI AkitoKIDANI Akito

6.8 デプロイにおける弱点

p.185 サーバでの実装に明確な指針がないため、一般的な慣習が悪用可能な弱点につながってしまう

6.8.1 仮想ホスト混同(Virtual Host Confusion)

p.185 仮想ホストで証明書を共有=秘密鍵も共有:セキュリティは一番弱いサイトと同じレベル
p.185 サイトが別のポートやIPアドレスにあっても、攻撃される可能性
p.185 弱いサイトをジャックした攻撃者は、他のサイトへの接続を弱いサイトに向けることで能動的攻撃が可能
p.185 攻撃者は弱いサイトのWebサーバでHTTPのHostヘッダを無視できる
p.186 この問題は2010年にRobert Hansenが最初に指摘[1]:実現の可能性はかなり低いとされている
p.186 2014年にDelignat-LavaudとBhargavanが論文にまとめた:現実的な悪用方法や、有名サイトになりすます方法を発見[2]
p.186 HTTP以外のプロトコル、例えばSMTPにも適用可能[3]

6.8.2 TLSセッションキャッシュの共有

p.186 Delignat-LavaudとBhargavanが見つけたもう一つの問題:関係ない2つのサーバ/サイト間でのセッションキャッシュ共有を悪用した、証明書認証のバイパス
p.186 本来のサーバ以外ともセッションを再開できる(正しい証明書を持っていない場合でも)
p.186 どれか1つのサイトを乗っ取ると他のサイトも攻撃できる(仮想ホスト混同と同じようにリダイレクトを使う)
p.186 サーバーアプリケーションがセッションとホストのチェックをしていないのが問題
p.186 ホストごとにチケット鍵を変えることでセッションチケットは対策可能

脚注
  1. ワイルドカード証明書を使っている2つのサイトのDNSを乗っ取り、XSS脆弱性のないサイトへのリクエストを脆弱性のあるサイトに送信させ ↩︎

  2. SPDYでTLSセッションが使いまわされる点が影響しているらしい。論文中ではFacebook、LinkedIn、Dropboxが取り上げられていた。 ↩︎

  3. ワイルドカード証明書を利用しているサイトへの攻撃、という意味では2021年に発見されたALPACA攻撃と類似するが、DNSを乗っ取り自前のサーバへ誘導する点でこちらの攻撃の方が手間がかかりそう。 ↩︎

KIDANI AkitoKIDANI Akito

第7章 プロトコルに対する攻撃

p.187 1994年、SSL1は安全でないとみなされ、Netscapeはバージョン2をリリース:Eコマースの台頭の火付け役
p.187 1996年、セキュリティ上の問題を解決すべくバージョン3リリース
p.187 1999年、ほぼ変わらないTLS1.0リリース:2008年のTLS1.2リリースも1.0が多く使われ続ける
p.187 TLS1.3:これまでの問題を全て回避できるよう設計
p.187 本章で取り上げる問題:2009年の安全でない再ネゴシエーション、2011年のBEAST、2012年のCRIME、2013年のLucky 13、RC4、TIME、BREACH、2014年のトリプルハンドシェイク問題とPOODLE、2016年のSLOTH、DROWN、Sweet32

KIDANI AkitoKIDANI Akito

7.1 安全でない再ネゴシエーション(TLS Authentication Gap)

p.187 2009年8月にMarsh Rayが発見、修正と公表に向け調整開始:11月、Martin Rexが発見し未調整のまま公表[1]

7.1.1 なぜ再ネゴシエーションが安全でなかったのか

p.188 同じTCPコネクション上で新旧TLSストリームに継続性がない:再ネゴシエーションの度に別のクライアントがサーバとやり取りしても検証されない
p.188 アプリは通常暗号化層とやり取りしない:HTTPリクエストで再ネゴシエーションが起きても気がつかない
p.188 再ネゴシエーション前のデータが渡されたり、前後でクライアント証明書や接続パラメータが変わったりすることも:悪用してMITM攻撃が可能
p.188 悪用の3つのステップ

  1. 犠牲者からサーバへのTCPコネクションに介入してリクエストを一時停止
  2. 攻撃者がサーバと新しいTLSセッション開始+攻撃データをサーバに送信
  3. 攻撃者は透過的プロキシとして1のリクエストを再開:サーバは再ネゴシエーションと解釈し攻撃者のリクエストしたレスポンスを返す

p.188 本来TLSで守られるべきアプリケーションデータの完全性が破られている(リクエストが改竄されている)

7.1.2 再ネゴシエーションを引き起こす方法

p.189 この脆弱性が発見されるまで、多くのサーバはクライアントによる再ネゴシエーション開始を許容
p.189 例外的にMicrosoftのIISはバージョン6[2]以降再ネゴシエーションを許容せず
p.189 クライアントが開始できなくても、クライアント証明書またはSGC[3]に対応しているサイトは攻撃できた

脚注
  1. 公開に至る経緯は2021年12月のLog4Shellと似てる気がする。 ↩︎

  2. Wikipediaによると「Windows Server 2003 と Windows XP Professional x64 Edition に付属するバージョン」とのこと。 ↩︎

  3. 米国企業向け証明書に特別な識別情報を埋め込み、クライアントに再ネゴシエーションさせ強い暗号を選択する方式。2000年の規制緩和以降衰退。 ↩︎

KIDANI AkitoKIDANI Akito

7.1.3 HTTPに対する攻撃

p.189 当初議論されていた攻撃は1種類だったが他の可能性がわかった
p.190 Thierry Zollerが攻撃ベクターの追跡・文書化、概念実証のための攻撃設計に尽力

■任意のGETリクエストの実行

p.190 攻撃ペイロード+犠牲者のクレデンシャルを含むリクエスト(X-Ignore:までが攻撃ペイロード)

GET /path/to/resource.jsp HTTP/1.0
X-Ignore: GET /index.jsp HTTP/1.0
Cookie: JSESSIONID=....

p.190 攻撃者はこのように部分的なヘッダ行を含む攻撃ペイロードを用意:末尾に改行がないので犠牲者が発効するリクエストヘッダ先頭行を無効化
p.190 攻撃者はリクエスト対象を選べるが、HTTPレスポンスは犠牲者のところに返る
p.190 これだけだとCSRF(XSRF)と類似しており、安全でない再ネゴシエーションの重要性を見過ごす結果に

■クレデンシャル泥棒

p.190 問題の公開から数日で改良版の攻撃が登場:さらに2、3日で暗号化されたデータ取得が可能に
p.191 Anil Kurmusの概念実証ではTwitterが攻撃対象となった:status=までが攻撃ペイロード

POST /status/update.xml HTTP/1.0
Authorization: Basic [攻撃者自身のクレデンシャル]
Content-Type: application/x-www-form-urlencoded
Content-Length: [推測される長さ]

status=POST /status/update.xml HTTP/1.1
Authorization: Basic [犠牲者のクレデンシャル]

p.191 これにより自身のツイートとして犠牲者のクレデンシャルを入手可能
p.191 Content-Lengthは機微情報を含むのに十分な長さにすればよい:残りのデータは他のHTTPリクエストとして処理される(おそらく不正なフォーマットのリクエストとして無視される)

■ユーザのリダイレクト

p.191 リダイレクトに応答するリソースがある場合、以下の攻撃が成立する可能性がある

  • 悪意あるWebサイトへと送る:オープンリダイレクトをフィッシングに利用(元のデザインを模倣+ドメイン名を似せる)
  • 平文HTTPへと接続をダウングレードする
  • リダイレクトされたPOSTによるクレデンシャルの奪取:307ステータスは同じリクエストメソッドを利用=POSTのボディもリダイレクトされるため、標的サイトのアカウントがなくても攻撃可能(銀行などが攻撃対象になり得る)
■XSS

p.192 Windowsのマイナなブラウザ[1]ではTRACEメソッドに対するmessage/httpタイプのレスポンスをHTMLとして扱うものがある
p.192 TRACEメソッドはリクエストをレスポンスに含めるため、攻撃ペイロードを利用してXSSが可能

脚注
  1. Thierry Zollerによれば、TRIDENTエンジンを利用しているサードパーティのブラウザ、とのこと。昔使ってたLunascapeはTRIDENT/Gecko/WebKitを切り替えることができたのでもしかしたら影響があったかも? ↩︎

KIDANI AkitoKIDANI Akito

7.1.4 他のプロトコルに対する攻撃

p.193 再ネゴシエーションの前後で状態をリセットしないプロトコルはHTTP以外も脆弱

●SMTP

p.193 SMTP:安全でない再ネゴシエーションに対して脆弱、ただしトランザクションが複数のコマンド・レスポンスで構成される[1]ため悪用は困難
p.193 メールサーバPostfix:再ネゴシエーションに対する脆弱性なし
p.193 SMTPの場合多くのサーバが有効な証明書を使っておらず、クライアントもこれを検証していないため、再ネゴシエーション以前にMITMが用意であったという事情がある

●FTP

p.193 FTPサーバによっては、ファイル転送方法に問題があり、暗号化が無効化される可能性あり

7.1.5 アーキテクチャに起因する攻撃

p.193 SSLオフロード[2]:暗号化対応の方法がないサービスを暗号化したり、中核サービスからTLS処理を切り離して[3]パフォーマンス改善を図る手法
p.193 実際のWebサーバに問題がなくとも、オフロード処理を行うサーバに問題があればシステム全体が脆弱となる[4]

7.1.6 影響

p.194 CSRFからクレデンシャル盗難までさまざまな攻撃が可能
p.194 エンドユーザのブラウザを直接攻撃するよりも、サーバを狙う方が遥かに容易
p.194 完全性を損なう(データが改竄される)ことの副作用:犠牲者がサーバを攻撃しているように見せかけるという攻撃ベクターが生まれる
p.194 エンドユーザ側での対応(ブラウザの設定変更など)も必要[5]

脚注
  1. Wikipediaによると、6往復程度必要。 ↩︎

  2. SSLアクセラレーションとも。 ↩︎

  3. TLS処理を行うハードウェアをSSLアクセラレータと呼ぶ。ClientHelloのサイズ問題でTLS1.2普及の妨げとなったとされるF5社のBIG IPなどがそう。 ↩︎

  4. 実際に、SSLオフロードをサポートするFortiOSには問題があったらしい。 ↩︎

  5. 手元のFirefox 92.0.1で確認したところ、security.ssl.require_safe_negotiationはfalseのままだった。SSL Pulseによると、まだ一部の安全でない再ネゴシエーションを許可するサイトが存在するので自衛のためにも設定した方がよさそう。 ↩︎

KIDANI AkitoKIDANI Akito

7.1.7 緩和策

●安全な再ネゴシエーションにアップグレードする

p.194 2010年初頭にRenegotiation Indication拡張が公開された:RFC5746[1]
p.194 ネットワークセキュリティ業界では再ネゴシエーションに価値なしと判断
p.194 TLS1.3では再ネゴシエーションが廃止されている

●再ネゴシエーションを無効にする

p.194 Renegotiation Indication拡張登場までの半年ほどは無効にするのが唯一の対策だった
p.195 クライアント証明書認証を利用する場合は無効にできない

7.1.8 問題の発見と修正を時間軸に見る

p.195 TLSのような複雑なエコシステムでは問題の修正に徹底的な協力と時間が必要
p.195 プロトコルの修正には6ヶ月かかった
p.195 ライブラリとOSにパッチを当てるのにさらに12ヶ月:大勢がパッチを適用するのにさらに24ヶ月
p.195 Opera社の調査:サーバの50%でRFC登場から1年以内に安全な再ネゴシエーションのパッチ適用、さらに3年かけて83.3%
p.196 プロトコルの欠陥解消には約4年かかる
p.196 SSL Pulse2014年6月の調査では88.4%が安全な再ネゴシエーションに対応、6.1%が安全でない、6.8%が再ネゴシエーションに非対応[2]
p.196

脚注
  1. 詳細は本書2.12.6参照。 ↩︎

  2. 2021年12月の調査では99.3%が安全な再ネゴシエーションに対応、0.2%が安全でない。非対応は0.7% https://www.ssllabs.com/ssl-pulse/ ↩︎

KIDANI AkitoKIDANI Akito

7.2 BEAST

p.196 2011年夏、TLS1.0以前で暗号化されたデータの一部を抜き出す攻撃手法BEASTが発表
p.196 TLS1.0の予測可能な初期化ベクター(IV)が利用された:TLS1.1では修正ずみだが、発見当時TLS1.1対応ブラウザが事実上存在しなかった[1]
p.196 IVの問題は10年間知られていたおり悪用が現実的でないと考えられていたが、DuongとRizzoが実用案を公開
p.196 BEASTによってブラウザベンダーがTLSプロトコルにほとんど注意を払っていないことが明らかに

7.2.1 攻撃の方法

p.196 攻撃対象はTLS1.0以前のCBC(Cipher Block Chaining)モードの暗号:予測可能なIVの場合、安全でないECB(Electronic Code Book)モードと同じになる

■ECBオラクル[2]

p.197 ブロック暗号ゆえ、決定論的性質を回避できない:同じデータが同じ形に暗号化されてしまう
p.197 攻撃者が好きなデータで暗号化を試し、過去のデータを推測可能

  1. ブロックを観察する:アルゴリズムによるが、AES-128なら16バイト(=128ビット)
  2. 16バイトの平文を暗号化し、観察対象と比較(これを繰り返す)

p.197 平均して2^127回推測が必要

■予測可能なIVのCBC

p.197 CBCでは暗号化前のメッセージをマスクするためにIVを使い、平文を隠すことでECBの脆弱性を回避
p.197 効果的なIVはメッセージに対して予測不可能である必要がある
p.197 SSL3.0/TLS1.0のCBCでは最初のブロックにのみ予測不可能なデータを使う
p.197 TLS1.0以前ではTLSレコードが、攻撃者が観察可能な前の暗号化ブロックをIVとして利用するため問題
p.198 TLS1.1/1.2では、レコードごとにIVが変わるので問題なし
p.198 TLS1.0はブロック単位での選択平文攻撃に脆弱(blockwise chosen-plaintext attack):CBCが事実上ECBに引き下げられる

脚注
  1. Windows 7(2009年リリース)のIE7ではTLS1.1がデフォルトでは無効になっていた。参考:Wikipedia ↩︎

  2. ここでいうOracleは神託、転じてブラックボックスな仕組みのこと。つまり暗号アルゴリズム。 ↩︎

KIDANI AkitoKIDANI Akito

p.199 C2 = E(M2 (+) IV2):(+)は排他的論理和によるマスク、M2に秘密情報が含まれる
p.199 攻撃者が作るメッセージ3は次のように書ける:M3 = Mg (+) C1 (+) C2
p.199 上記より、C3 = E(M3 (+) C2) = E(Mg (+) C1 (+) C2 (+) C2)となる
p.199 排他的論理和を2回当てると消えるので:C3 = E(M3 (+) C2) = E(Mg (+) C1)となる
p.199 MgがM2と同じであれば、暗号化した結果C3がC2と一致

KIDANI AkitoKIDANI Akito
■実際の攻撃

p.199 ブロック全体(典型的には16バイト)を推測可能にするHTTPの特性

  • 機微データのサイズが小さい(パスワード、セッションID)
  • 機微データの文字種類が限定されている(セッションIDは16進数でエンコードされがち)
  • クッキーの前には必ず「Cookie: 」の文字列がある

p.199 DuongとRizzoの発見:リクエスト中の機微データの位置を変更しやすい+暗号化・送信タイミングの制御
p.199 データ位置変更はURLに文字を追加することで達成可能
p.199 送信タイミングの制御にはJavaScriptではなくJava appletが利用できた(別のSameOrigin制約を回避するための脆弱性を悪用)
p.200 HTTPリクエストを操作して単一ブロックに15バイトの既知情報と1バイトの機微情報が含まれるようにする:平均2^7回で推測可能、16進数の数字であれば平均8回で推測可能

7.2.2 クライアントサイドの緩和策

p.200 問題が最初に発見され(脅威と見做されていなかっ)た2004年のOpenSSLの対策:TLSレコードの前に空のTLSレコードを挿入
p.200 予測可能なIVを空のレコードで消費する作戦
p.201 しかし、IEが長さ0のTLSレコードをうまく扱えないと判明し、断念
p.201 2011年、ブラウザベンダは1/n-1分割によりBEAST対策を実施
p.201 アプリケーションデータの1バイトを最初のTLSレコードに、残りを2つ目のTLSレコードに配置する
p.201 1バイトのみが予測可能なIVの犠牲になる
p.201 Chromeが最初に(2011年)1/n-1分割を適用したが、多くの大手サイトと通信できず一度は断念した
p.202 Chrome/Operaが2011年末、FF/IEが2012年初め、Safariが2013年に1/n-1分割に対応
p.202 任意の平文を挿入できなければ攻撃が困難なため、多くのクライアントサイトのツールでは1/n-1分割に非対応

7.2.3 サーバサイドの緩和策

p.202 膨大な数のクライアントの更新サイクルをコントロールするのは不可能:多くのユーザが脆弱なブラウザを利用
p.202 Chromeの自動アップデートに他のブラウザが追随し事態はある程度改善された
p.202 2013年までサーバサイドでのBEAST対策としてはストリーム暗号のRC4の利用:2013年にはRC4の脆弱性が知られ、サーバサイドのBEAST対策がなくなる[1]

7.2.4 歴史

p.203 予測可能なIVの問題点は1995年から知られていた
p.203 しかし、広く認識されておらずSSL3.0(1996年)で導入されてしまった
p.203 2002年にSSHプロトコルで再発見され、前述の空レコードによる対策が提案されたが互換性がなく無効化された
p.203 2004年にはTLSで予測可能なIVを悪用する方法が提示された
p.204 TLS1.1(2006年)では各TLSレコードに無作為なIVが使われることで問題を解消:しかし、これに対応するブラウザが少なかった
p.204 2011年BEASTが問題となり、1/n-1分割で対策された
p.204 主要なブラウザがTLS1.2をデフォルトにしたのは2013年後半になってからのこと

7.2.5 影響

p.204 プロトコル起因の問題のため、脆弱性発見当時は全てのクライアントが脆弱だった
p.204 攻撃者はサーバが送るデータを制御できる訳ではないので、サーバからのデータストリームに対して攻撃することは不可能
p.205 攻撃に必要なサーバの条件:CBCを含む暗号スイートが優先されること、TLS圧縮が無効であること
p.205 圧縮されるとBEAST攻撃はより困難になる(圧縮自体に別の問題があり対応するサーバは半数程度と推測)
p.205 BEAST発見時の攻撃可能条件:犠牲者の近くからのMITM攻撃+犠牲者がJavaプラグインを利用+(犠牲者が平文サイトを閲覧or攻撃者のサイトを閲覧)+対象サーバがCBC利用・圧縮非利用
p.205 現在では状況が変化:Java自体に対策が実施済み(Oracle, 2011年10月)、かつJava appletが無効化(Chromeでは2015年)、TLS1.2がデフォルトになりつつある

脚注
  1. ストリーム暗号として2016年にはChacha20がTLSで利用可能となった。RFC7905↩︎

KIDANI AkitoKIDANI Akito

7.3 圧縮サイドチャネル攻撃

p.206 圧縮結果のメッセージ長を観測するサイドチャネル攻撃
p.206 攻撃者が自分のデータを送信して、秘密情報と一緒に圧縮できる場合に効果的
p.206 この推測材料を圧縮オラクルと呼ぶ

7.3.1 圧縮オラクルの仕組み

p.206 攻撃者は、送りつけるデータを変化させ、一緒に圧縮される秘密データについての情報を得る
p.206 一般的な圧縮アルゴリズム[1]:繰り返される文字列を除去する(例:LZ77[2]
p.207 オラクルが存在する=秘密情報と一緒に任意のデータを圧縮できる
p.207 圧縮が効けば、出力の長さが短くなり、推測が正しいことがわかる

[コラム]情報が漏れるのはTLSプロトコルの欠陥なのか

p.207 文書化されているプロトコルの限界:TLS1.2の仕様でも、レコードの長さが保護されない点に注意すべしと書かれている
p.207 ブラウザベースの攻撃:攻撃者のリクエストが本物のユーザのセッションで送信される点を利用
p.208 送信元の環境を分離しようとするとWebの大半は機能しなくなる:選択的な分離(セキュリティ空間をサイトが宣言する形(CORSとか?))
p.208 メッセージ長の隠蔽は効果に疑問が残る

7.3.2 攻撃の歴史

p.208 2002年にJohn Kelseyが論文で初めて言及:ただし機微情報への攻撃は困難
p.208 2007年、(TLSではないが)暗号化されたIP電話の会話を特定するアルゴリズムが開発[3]:最終的には90%の正確さで英文を識別可能[4]
p.208 2011年のSPDYメーリスでの議論:imgタグのsrc属性で標的サイト を指定することで、攻撃可能(URLがクッキー文字列にマッチして、圧縮結果が変わるまで試す)

脚注
  1. 本文中では「不可逆圧縮アルゴリズム」と書かれているが内容的に「可逆〜」の誤りか。 ↩︎

  2. 1977年に、Abraham LempelとJacob Zivによって開発されたアルゴリズム。改良版のLZSSを改良したDeflateがgzipなどに利用されている。(Wikipediaより) ↩︎

  3. 論文によると、帯域幅を節約するVBR(Variable Bit Rate)によってエンコードされた通話では十分に保護されない。たとえば、英語かスペイン語か?という問題は86%程度の正解率になる(そもそも通話の両端がどこか、ということを観測すれば言語はある程度推定できる)。これを可能にしているのは、たとえばSpeexコーデックでは母音や強い音は、sやfなどの摩擦音よりも高いビットレートが必要になり、簡単な音は少ないビットで、エンコードしにくい音は多くのビットでエンコードされる。VBRエンコーダは最適なビットレートを選択するので、暗号化されたパケットサイズからビットレートを予測することができる。NISTはVoIPに追加のセキュリティとしてAESなどによる暗号化を推奨している。 ↩︎

  4. 論文によると、フレーズによって正確さが変わるらしい。 ↩︎

KIDANI AkitoKIDANI Akito

7.3.3 CRIME

p.209 2012年、BEASTの発見者でもあるDuongとRizzoがCRIMEを発見・命名
p.209 クッキーの1文字を6回のリクエストで暴けたとされている
p.209 仕組みはBEASTと同じ(むしろ簡単):複数のリクエストを犠牲者のブラウザから送信させ、ネットワーク上でパケットを観察(=推測)

■TIME

p.209 2013年3月改良されたTIMEが発表される:ローカルネットワークへのアクセスが不要に
p.209 imgタグとonLoad/onReadyStateChangeイベントハンドラを利用(JavaScriptマルウェア)
p.210 TCPの輻輳ウィンドウを利用して圧縮された出力における差分を観察

  • 輻輳ウィンドウに収まるデータは一度に送信される(初期値はクライアントにより異なる:初期値5Kバイトなら3パケットまとめて送信可)
  • 残りのデータは最初に送ったパケットのACKが帰ってから次のパケットとして送信される=RTTが1回多くなる
  • リクエストの送信データを大きくすることで輻輳ウィンドウ初期値を特定可能
  • RTTが1回多くなることをJavaScriptマルウェアで計測する
  • 1バイト圧縮できれば、RTTが少なくなり、秘密情報の推測が正しいことがわかる

p.211 HTTPリクエストは上記のように比較的簡単に攻撃できる:HTTPレスポンスは難しい

  • レスポンスの圧縮はサーバ側で行われるので、サーバ側の輻輳ウィンドウ初期値の特定が困難
  • オラクルの存在が必要:レスポンスに含まれる秘密情報の横に、任意のデータを挿入できるか
  • クライアントとサーバ双方の輻輳ウィンドウが関係するため遅延の原因を知るのが困難

p.211 とはいえTLSと違いHTTPレベルのレスポンス圧縮は普通に利用されており同様の攻撃は有効
p.211 TIMEは概念実証の域を出ていない:乗り越えるべき障壁が多い

  • 輻輳ウィンドウの境界はコネクションの時間がたつにつれ大きくなる
  • サーバはコネクションを再利用する上、ブラウザ(JavaScript)側からは制御できない
  • よって、コネクションが閉じられるのを待って何度も輻輳ウィンドウの値の確認を試す必要がある
BREACH

p.211 2013年8月、HTTPレスポンスを標的とする別のサイドチャネル攻撃BREACHが発表
p.212 攻撃例として、Outlook Web AccessのCSRF対策トークンを30秒未満で95%精度で取得

■攻撃の詳細

p.212 前提条件:犠牲者のネットワークトラフィックへのアクセス+犠牲者のブラウザでのJS実行
p.212 リクエストに攻撃ペイロード(秘密情報と同じ文字列になるよう推測された任意のデータ)を含め、それがレスポンスに含まれれば攻撃可能
p.212 いくつか追加で対処が必要:Huffmanエンコーディング、ブロック暗号、コンテンツの多様性

●Huffmanエンコーディング

p.212 HTTPの圧縮に使われるDEFLATE=LZ77(攻撃対象)+Huffmanエンコーディング
p.213 Huffmanエンコーディング:文字種類によって登場頻度が異なることを利用した可変長エンコード方式
p.213 通常1文字1バイトだが、頻繁に登場する文字は短い記号(1バイト未満)を使うようにする(参考:Wikipedia
p.213 Huffmanエンコーディングにより推測の成否に関係なく得られる長さが変わる[1]

●ブロック暗号化方式

p.213 BREACHはストリーム暗号を想定(データの長さが暗号文にそのまま反映される)
p.213 ブロック暗号が使われるとパディングが必要になるためリクエストが複数回必要になる

●レスポンスのコンテンツの多様性

p.213 HTTPレスポンスへの攻撃はマークアップやエンコーディングの多様性から攻撃が難しい
p.213 攻撃がない場合でもレスポンスの大きさが様々に異なり推測が困難

脚注
  1. 対策として1回の推測で2回のリクエストを投げれば良いらしいが、理屈がよくわからない...orz ↩︎

KIDANI AkitoKIDANI Akito
CRIMEとTLSレコードサイズ

p.213 TLSレコードは16Kバイト(16384バイト)=圧縮後の最大サイズ
p.213 攻撃者は無作為な文字列をURLにすることで、先頭16Kバイトを完全に制御可能
p.214 現実には圧縮の設定やライブラリのバージョンを考慮する必要があるが、比較的簡単な手法

■さらなる攻撃の進化

p.214 2016年BREACHを容易にするRuptureフレームワークが公開
p.214 2016年HEIST攻撃が発表[1]

■TLSの圧縮とSPDYに対する影響

p.214 TLS/SPDYともにCRIMEの攻撃対象はヘッダの圧縮=クッキー用
p.214 CRIMEには能動的なMITM攻撃(ネットワークトラフィックへのアクセス)が必須
p.214 クライアント側での制御も必須:imgタグを使うと簡単(ソーシャルエンジニアリング、平文サイトHTML改竄)
p.214 圧縮は至るところで行われている:詳細が出たのがTLSとSPDYだけ
p.215 CRIME発表当時SSL Pulseの結果で、TLS圧縮対応は42%、SPDY対応は2%(Google, Twitter等大手サイト含む)
p.215 ブラウザとしてはChromeだけが圧縮に対応していた:FFは実装のみでリリースなし
p.215 SSL Pulseの閲覧者基準で、圧縮対応クライアントは7%
p.215 多くのベンダーがTLS圧縮を無効にするパッチを当てた
p.215 影響範囲:Basic認証のパスワードやセッション用クッキーが取得可能

■HTTPレスポンスの圧縮に対する影響

p.215 HTTP圧縮は影響が全く別

  1. 攻撃対象領域がかなり広い
  2. 攻撃者の事前準備が多く、得られる成果も少ない

p.216 HTTP圧縮の攻撃対象領域:多くのサイトが有効にしており、無効にした場合のコスト面が大変
p.216 標的Webサイトの内情を知らないといけない(秘密情報がどこにあるのか)
p.216 結果的に、CSRF対策トークンが狙われやすい[2]

脚注
  1. 資料によると、JavaScriptのperformance.getEntries()メソッドを利用して通信のタイミングを観測できるらしい。 ↩︎

  2. リクエストを見たら大体わかるから、か? ↩︎

KIDANI AkitoKIDANI Akito

7.3.4 TLSおよびSPDYへの攻撃に対する緩和策

p.216 攻撃発表前は30%程度のユーザ(≒Chromeユーザ)が圧縮に対応していた:自動アップデートで圧縮は無効に
p.216 OpenSSLも圧縮に対応していたがブラウザではなくマルウェアが挿入されるとは考えづらい
p.216 2014年7月時点のSSL Pulseによると、10%程度のサーバが圧縮に対応(古いApacheか)
p.216 長さを隠すTLS拡張の実装が検討された:RFC Draft(正式なRFCにはなっていない模様)

※TLS1.3ではTLSレコードにパディングが追加されレコード長を隠すことが可能

struct {
  opaque content[TLSPlaintext.length];
  ContentType type;
  uint8 zeros[length_of_padding];
} TLSInnerPlaintext;

p.216 SPDYの圧縮についてもChrome/Firefoxで無効化済み

7.3.5 HTTPの圧縮への攻撃に対する緩和策

p.217 HTTPの圧縮への攻撃は簡単ではないし、解決が難しい

  1. HTTPの圧縮を無効にできる余地がない
  2. アプリケーションの変更が必要だがコストに見合わない

p.217 可能性がある対策は以下5つ

●リクエストのレートを制御する

p.217 TIME/BREACHの発見者は大量リクエストが必要で何回か逮捕された
p.217 ユーザーのセッションにおけるリクエストレート制限は有効:コスト的にもOK

●長さを隠す

p.217 レスポンスの本当の長さを隠す(HTMLなら空白は無視されるのでパディングを挿入しても問題ない)
p.217 BREACHの発見者によるとリクエスト回数を増やすと無作為なパディングも統計解析で無効化可能
p.217 Webサーバレベルで適用可能な点で優れている

●CSRF対策用トークンのマスキング

p.217 CSRFトークンの各バイトに対応するランダムバイトを作り、排他的論理和をとった結果とランダムバイトをトークンとして埋め込む[1](毎回レスポンスに含まれるトークンが変わるので、圧縮を何度も試すことができない)

●部分的に圧縮を無効にする

p.218 標的サイトと異なるドメインで実行されるJavaScriptによって攻撃が行われる=リファラ情報が標的サイトのドメインではない
p.218 よって、このようなリクエストへのレスポンスの圧縮を無効にすれば対策可能(パフォーマンスは若干低下

●文脈を隠す

p.218 機密性の高いデータと攻撃者のデータを同じ文脈で圧縮しない(実現は難しい, 特に後付けは。)
p.218 Black Hat Europe 2016でデータをマスキングするツールCTXが発表された[2]

脚注
  1. この対策はBREACHのサイトで緩和策として挙げられている、と著者がtwitterで述べていた:https://twitter.com/ivanristic/status/1248184646833246210 ↩︎

  2. 資料p.34によると、圧縮無効化するとレスポンスサイズが11倍で数秒の遅れが生じるが、機密データをマスキングすると20%程度サイズが増加、CTXを使うと5%程度のサイズ増加で済む。 ↩︎

KIDANI AkitoKIDANI Akito

7.4 Lucky 13

p.218 CBCを含む暗号スイートに対し、平文の小さな一部(要するにクッキーやBasic認証)を解読できる攻撃が2013年2月に発表
p.218 HTTP以外でもパスワードによる認証を使っている場合影響がある可能性あり
p.218 根本原因は、CBCのパディング(というかCBCの暗号文が?)がTLSの完全性検証の対象外である点:パディングを攻撃者がいじれる
p.218 攻撃者はJavaScriptマルウェアで平文から1バイトを見つけ出すのに8192回のリクエストが必要

7.4.1 パディングオラクルとは

参考:https://rintaro.hateblo.jp/entry/2017/12/31/174327
m3=Dec(c3)⊕c2
平文(n番目) = 暗号文(n番目)を復号し、暗号文(n-1番目)と排他的論理和をとる

p.219 ブロック暗号のパディングが合っているかどうかの情報(サイドチャネル)を攻撃者が取得して情報を解読する攻撃
※PKCS#7パディングでは平文がブロックに対し1バイト足りなければ0x01を1個、2バイト足りなければ0x02を2個...と足す

p.219 攻撃者は暗号文(n-1番目)の末尾のバイトを書き換えて送信
p.219 上記によって計算された結果の平文(n番目)の末尾のパディングが正しく0x01になるまで繰り返す
-> m3'=Dec(c3)⊕c2' となるm3'(0x01)とc2'(書き換えた値)が判明したことになる
-> Dec(c3)=m3'⊕c2'となるから、m3=Dec(c3)⊕c2と合わせると:m3=(m3'⊕c2')⊕c2
-> 暗号文を復号できなくても=Dec(c3)が分からなくても、暗号文(c2)とオラクル(m3', c2')から平文(m3)が判明する
p.219 これを末尾が0x02 0x02、0x03 0x03 0x03、...となるように増やしていくと全体を明らかにできる
p.219 たくさん推測する+推測が成功したかどうか知る:プロトコルによってはパディングのエラーが丸見え
p.219 サーバの挙動(レスポンスタイミング)からパディングの成否を観察するタイミングオラクル攻撃が必要なケースもある
p.219 パディングオラクルを回避するには:データの完全性を検証すればよい(例:認証つき暗号、GCMとか)

7.4.2 TLSに対する攻撃

p.219 2001年のSerge Vaudenay論文でTLSなどへのパディングオラクル攻撃を発表
p.219 TLS1.0ではパディングのエラーはdecryption_failed(TLSアラートプロトコル、21)、MACエラーはbad_record_mac(同20):TLSアラートプロトコルなので暗号化されて通知される=攻撃者が区別できない、悪用困難

p.219 2003年Canvelらによるタイミングオラクル攻撃の改良:OpenSSL攻撃に成功(パディングが正しくない場合OpenSSLがMAC計算をスキップするのでレスポンスが少し早まるのを利用)
p.219 IMAPサーバを攻撃し、1時間でパスワードを取得
p.220 TLSに対するパディングオラクル攻撃は、推測に失敗しエラーになると、アラートプロトコルの仕様によりTLSセッションが破棄されるため、同じ暗号化ブロックに対する書き換えを連続で実行できない
p.220 Outlook + IMAPの場合、デフォルトで5分に1回、アカウントのフォルダ(inbox, outbox, ..)ごとにリクエストを投げる:全てにパスワード(攻撃対象の機微データ)が含まれている

p.220 OpenSSLなどはCBCモードのセキュリティを改善し、漏洩を最小となるよう修正(パディングが正しくなくてもMAC計算をスキップしないように)
p.220 また、TLS1.1でdecryption_failedアラートは非推奨に

https://datatracker.ietf.org/doc/html/rfc4346

RFC4346
   Note: Differentiating between bad_record_mac and decryption_failed
         alerts may permit certain attacks against CBC mode as used in
         TLS [CBCATT].  It is preferable to uniformly use the
         bad_record_mac alert to hide the specific type of the error.

p.220 ただし、MACのパフォーマンスはデータサイズにある程度依存するので、タイミングの差はサイドチャネルとして残ってしまう
p.220 これが2013年にLucky 13と名付けられた攻撃

7.4.3 影響

p.220 極めて些細なタイミング差の検出のため、標的サーバの近くに攻撃者がいる必要がある
p.220 研究者の実験では攻撃者と標的サーバが同一ローカルネットワークに存在
p.220 DTLSに対してはタイミング差を増幅する技術が効果的(TLSには効かない)

KIDANI AkitoKIDANI Akito
●自律的なシステムに対する攻撃

p.221 自律的なシステム:サーバとのやりとりが頻繁、多くは接続失敗時の再試行機構をもつ(ので攻撃しやすい)
p.221 格好の標的IMAP:機微データ(パスワード)が毎回同じ場所に格納[1]
p.221 16バイトの推測に840万回の接続が必要
p.221 オラクルの推測失敗=TLSエラー、セッション切断:毎回フルハンドシェイクなので時間かかる

●一部の平文が判明している場合の攻撃

p.221 あるブロックの最後の1バイトが判明している場合、残りの各バイトがおよそ65536回(2^16)で解読可能

●JavaScriptマルウェアを使ったブラウザに対する攻撃

p.221 HTTPクッキーが標的:リクエスト中のクッキー位置を操作して、暗号ブロックのうち1バイトのみ不明であるよう並べ替える
p.221 1バイト復元するのに8192回(2^13)必要

7.4.4 緩和策

p.221 AlFardann/Patersonは各ライブラリ修正をまってから公表:パッチ当てればOK
p.221 CBCを含む暗号スイートが弱い:とはいえCBCを使わないのは簡単ではない
p.221 CBC(ブロック暗号)がダメならストリーム暗号を使えばよい:しかしRC4には別の問題(7.5節参照)
p.221 対策1:他のストリーム暗号(ChaCha20)が追加される予定:2016年追加済み(RFC7905
p.221 対策2:TLS1.2の認証付き暗号(GCM)を使う
p.222 Encrypt-then-MACを使うプロトコル拡張もあるが普及度不明(RFC7366[2]

脚注
  1. RFC 3501によると、loginコマンドのパラメータがユーザー名とパスワードになっている。 ↩︎

  2. encrypt_then_mac 22 (0x16)のTLS拡張。extension_dataは空でよい。 ↩︎

KIDANI AkitoKIDANI Akito

7.5 RC4[1]の弱点

p.222 RC4:1987年にRon Rivestが1987年に設計した暗号[2]
p.222 数多くの欠陥にもかかわらず最も普及した暗号の1つ:簡潔に実装でき、ソフトウェアハードウェア双方で高速に実行できるため
p.222 破られたとはいえ、実用的と言えるほど攻撃が改良されておらず、いまだに使われている(惰性や無知もその理由)
p.222 ただし、TLS1.2では代替策(ChaCha20)があるのでRC4を使うべきではない

7.5.1 鍵スケジューリングの弱点

p.222 鍵スケジューリングのアルゴリズムの弱点(2001年のFluhrer, Mantin and Shamir attack):一部分が分かれば初期出力の多くを決定できる
p.222 2001年、WEPプロトコル[3]はこの弱点により破られた
p.222 WEPはマスター鍵と類似したセッション鍵を利用していたため、解読された
p.222 TLSでは毎回異なる鍵を利用するため、同じ問題は発生しない:結果として広く利用され続けた
p.222 筆者の2010年の調査では98%のサーバがRC4に対応、他のスイートより高優先度
p.223 2011年のBEAST攻撃の結果、ブロック暗号が安全でなくなり、2013年3月(RC4脆弱性発表時点)ではトラフィックの50%、2014年6月には26%をRC4が占めた

7.5.2 初期に発見された単一バイトの偏り

p.223 鍵ストリームに他の値より頻出する値があることは2001年から知られていた
p.223 特に、2つ目のバイトは128分の1の確率で0になる(期待値は256分の1)
p.223 0への偏りは危険:排他的論理和をとっても元の値が変わらないため
p.223 複数のTLS接続を攻撃し、2つめのバイトで最も頻出するものが平文と同じ、と推測できる
p.224 TLSのFinishedメッセージなどは接続のたびに変化するので攻撃対象として不適切
p.224 一方、HTTPクッキーやパスワードは毎回同じ場所に格納されるので攻撃しやすい

脚注
  1. 概要はp.7: https://zenn.dev/link/comments/2f223c3504bd38 ↩︎

  2. 正式名称はRivest Cipher 4。彼は1992年にMD5も設計している。他にもRC2, RC5, RC6, MD2, MD4, MD6など。 ↩︎

  3. 1997年に登場した無線ネットワークのセキュリティのためのプロトコル。 ↩︎

KIDANI AkitoKIDANI Akito

7.5.3 先頭256バイトにおける偏り

p.224 2013年3月のAlFardanらの論文で新たな弱点と2つの攻撃発表(先頭256バイトの偏りと二重バイトの偏り)
p.224 2^44通りの鍵ストリームを分析:先頭256バイトのあるバイトは10, 23になりやすい
p.224 2^32件のデータサンプルがあれば先頭256バイトをほぼ解読できる:パスワードやクッキーなどデータの文字種類が少ない場合、2^28で十分
p.225 RC4は元々2^128のセキュリティを保証していたが先頭256バイトはこの限りではない
p.225 先頭256バイトの攻撃は深刻だが、下記制約のため理論上の攻撃でしかない

●接続の数

p.225 2^28のサンプルを手に入れるには時間がかかる
p.225 論文で引用された実験では能動的な攻撃で500接続/秒以上で16時間かけて2^25接続
p.225 受動的な攻撃の場合、1接続/秒だと2^28接続に8年以上かかる
p.225 MITM攻撃で接続頻度を上げても、新しい接続が必要なので接続のたびにフルハンドシェイクが必要なので時間がかかる

●攻撃位置

p.225 上述の通りMITM攻撃が必須

●攻撃の範囲

p.225 先頭256バイトのみが対象:価値のあるデータが出ることは稀
p.226 主要ブラウザではクッキーが220バイトより後に配置されるためほぼ攻撃対象外(TLSの先頭36バイトは意味がない[1]
p.226 Basic認証もChromeのみ先頭100バイトの位置にくるだけ

7.5.4 二重バイト攻撃

p.226 RC4の暗号化ストリームに一定間隔で連続して、連続したバイトの偏りが現れる
p.226 複数サンプルを取得するのに同じ鍵を利用できる=同一の接続上で複数サンプルを取得できる
p.226 同じ平文を何度も暗号化する必要があるため受動的攻撃は不可能
p.226 512バイトのPOSTリクエストを13*2^30回暗号化すると16バイトの平文を解読できる:3.25テラバイトのデータを送受信する必要がある(10万リクエスト/分でも83日かかる)ため、現実的ではない

7.5.5 その後の改良された攻撃

p.226 2015年3月のGarmanらの攻撃:セッションクッキー摂取に2^26回で十分
p.226 2015年3月のImperva社の攻撃:RC4で不適切鍵が生成されTLS先頭64バイトが危殆化する可能性
p.227 ->受動的こうげきにより2^24回に1回の頻度でTLS接続が破られうる
p.227 2015年7月VanhoefとPiessensの句げき:16種類の文字からなるクッキー摂取に75時間(BEAST同様、JavaScriptマルウェアにより攻撃を高速化:ただし秒間4450リクエスト、やや非現実的)

7.5.6 緩和策:RC4か、BEASTか、Lucky 13か、POODLEか

p.227 RC4への攻撃は深刻だが実世界で起こる可能性は低い:とはいえ安全マージンが小さく、使用中止すべき
p.227 問題は(2013年当時は)安全な代替手段がないこと

●相互運用性

p.227 RC4はかなり普及しており、それ以外をサポートしていないクライアントもごく僅かだが存在[2]
p.227 これらのクライアントをサポートするため、最下位の暗号スイートとしてRC4を残すのはあり

●安全性

p.227 RC4を無効化した場合TLS1.0以前のバージョンでCBCモードとなる:BEAST, POODLE, Lucky 13の可能性(TLS1.2にすべき(認証暗号GCMが使える))
p.227 BEAST POODLE RC4どれも実行は困難
p.228 弱い暗号スイートを全て避けるのが今のところベストな方法
p.228 Facebookは2017年6月時点でRC4を許可していた[3]
p.228 2015年MicrosoftはWindows 8.1でRC4を非推奨に、Firefoxも同様の方針を採用(一部のサイトのみ許可)
p.228 SSL Pulseの2015年のデータでは、全体の0.6%のサイトがRC4にしか対応していない
p.228 2015年2月、RFC7465が発行:TLSにおけるRC4利用を禁止
p.228 2016年中にモダンブラウザはRC4を完全廃止:RC4の攻撃は過去のものとなった

脚注
  1. と書かれているが正直よくわかっていない...このサイトによると Since the first 36 bytes of plaintext are formed from an unpredictable Finished message when SHA-1 is the selected hashing algorithm in the TLS Record Protocol, these first 36 bytes cannot be recovered. ということなので、暗号化して送られるのはFinishedハンドシェイクメッセージ以降であり、Finishedのサイズが36バイト、という話か?SSL3.0では36バイトだったがTLS1.2では12バイトだったはず...謎。 ↩︎

  2. Cloudflareのブログによると、2007年頃にリリースされた古い携帯電話やアプリが該当する。それ以外にも、アメリカで多くのVPNなどのプロキシがRC4を利用していた。 ↩︎

  3. 2022年3月現在、SSLLabsで確認したところ、www.facebook.comはTLS1.0, 1.1をサポートしているものの、RC4のサポートは廃止されているようだった。SSL Pulseの過去データを参照すると2017年には30%近くのサイトがRC4をサポートしていたが、2022年現在では6%まで減少している。 ↩︎

KIDANI AkitoKIDANI Akito

7.6 トリプルハンドシェイク攻撃

p.229 2009年の再ネゴシエーション脆弱性->プロトコル修正(拡張"renegotiation_info" (0xff01)):安全な再ネゴシエーション(7.1節)
p.229 2014年にトリプルハンドシェイク攻撃で破られる(結果として2018年のTLS1.3では再ネゴシエーション廃止)

7.6.1 攻撃

p.229 再ネゴシエーションの安全性確保:クライアントが以前の接続のverify_data提示(クライアントしか知らない、暗号化されて転送される)
p.229 TLSの弱点2つを組み合わせ3ステップで攻撃

■ステップ1:未知の鍵が共有される弱点

p.229 RSA鍵交換の弱点:未知の鍵共有(Unknown Key-Share)
p.229 マスターシークレットの生成過程

  1. クライアントがプリマスターシークレットと、乱数生成し送信
  2. サーバーが乱数生成し送信
  3. 3つの値からマスターシークレット計算
    p.229 乱数は平文で送信、プリマスターシークレットはサーバー公開鍵で暗号化
    p.230 最初のハンドシェイク:悪意あるサーバーでクライアントのPMSと乱数を奪い、同じ値で攻撃対象サーバーに接続し、マスターシークレットを共有する[1]
    p.230 この時点では何も悪さができない

p.231 DHE鍵交換に対する攻撃もある:TLSの主な実装では素数でないDHパラメータが許容されていた[2]
p.231 ECDHE鍵交換であれば任意のパラメータが使えずnamed curveのみ利用可能[3]

脚注
  1. マスターシークレットの共有が問題となるので、RFC 7627では、仕様を変更してハンドシェイクメッセージを含めてマスターシークレットを計算し、接続ごとにユニークなマスターシークレットを得られればこの問題は発生しない、と書かれている。 ↩︎

  2. https://mitls.org/pages/attacks/3SHAKE の説明によれば、問題のDHパラメータが素数かどうかを計算するのは計算コストが高すぎるためそのような実装になっていた。 ↩︎

  3. ステップ1のRSA/DHEの未知の鍵共有は、RFC 7627のIntroductionの説明によると、攻撃対象のサーバがRSA/DHE以外をサポートしていても、自身のClientHelloで送る暗号スイートをRSA/DHEに限定することで回避可能。かつ、ECDHEであっても、脆弱なケースがあるとのこと。 ↩︎

KIDANI AkitoKIDANI Akito
■ステップ2:完全同期

p.231 ステップ1の2つの接続はサーバの証明書が異なる:Certificateメッセージを含むハンドシェイクメッセージをハッシュ化したverify_dataの値が異なる
p.231 verify_dataをextension dataとして利用するrenegotiation_info拡張の仕様のため、再ネゴシエーションを攻撃できない
p.231 しかし、セッションリザンプションのハンドシェイクを利用し、クライアントのセッションリザンプションのリクエストを標的サーバに転送するとCertificateメッセージが省略されるためverify_dataが同一となり攻撃が可能になる[1]
p.231 攻撃者はクライアントにもサーバにもデータを送信できる

■ステップ3:なりすまし

p.232 クライアント証明書を要求するサーバのリソースへリクエストし、なりすますことが可能
p.232 再ネゴシエーション後はトラフィックが改めて暗号化されるため、攻撃者は中身を見れなくなる

7.6.2 影響

p.233 最も簡単な悪用方法:犠牲者の認証情報で標的サーバにリクエストを送る
p.233 しかし、攻撃はそれほど簡単ではない

  • エントリーポイントの探索
  • ペイロードの設計
  • 再ネゴシエーション後の攻撃結果確認不可・同一接続上での連続攻撃不可

p.233 再ネゴシエーション前の双方にデータ送信可能な状況の方が危険(事実上のフィッシング):JavaScriptコードを挿入可能

7.6.3 要件

p.233 1つ目の要件:クライアント証明書を使っているサイトにのみ攻撃可能
p.233 2つ目の要件:普段使ってない怪しいサイトでクライアント証明書を利用させる必要性
p.233 クライアント証明書を使っているサイトが少ないのでとトリプルハンドシェイク攻撃を適用できるケースはそれほど多くないは、狙えるのは機微情報

7.6.4 緩和策

p.234 プロトコルの問題:2015年9月発行のRFC 7627 Transport Layer Security (TLS) Session Hash and Extended Master Secret Extensionで対処
p.234 当初は再ネゴシエーションの強化も検討されたが頓挫
p.234 ブラウザベンダーの短期的解決策

  • 再ネゴシエーション後の証明書変更を検出して接続切断
  • 安全でないDHパラメータを拒否
    p.234 IEではライブラリも修正されたので古いバージョンでも安全なはず
    p.234 ただし、SASL[2]、PEAP[3]、Channel ID[4]を利用している場合に危険が残る
    p.234 対策は以下の3点
  • すべてのアクセスにクライアント証明書を要求する:最初の接続を実行しにくくする
  • 再ネゴシエーションを無効にする
  • ECDHE暗号スイートのみを有効にする(RSA/DHEを無効にする):Android 2.X/IE9onWindowsXPあたりでは使えないが...
脚注
  1. RFC 7627によると、verify_dataが同一となることで、renegotiation_info拡張だけでなく、RFC5929で定義されているTLSチャネルバインディングも影響を受ける。同じくFinishedメッセージの唯一性に依拠している中間者攻撃を防ぐ仕組みのため。 ↩︎

  2. Wikipediaより:Simple Authentication and Security Layer(SASL)は、インターネットプロトコルにおける認証とデータセキュリティのためのフレームワーク。RFC 4422など。LDAPやXMPPのほか、POP、IMAP、および SMTP ユーザーアクセスプロトコルの追加認証メカニズムとして機能する(参考)。 ↩︎

  3. Protected Extensible Authentication Protocol。WiFiネットワークのセキュリティを強化するために使用されるセキュリティプロトコルで、EAP(拡張認証プロトコル)の速度とトランスポート層セキュリティ(TLS)トンネルを組み合わせたもの(参考)。MSのものとCISCOのもので仕様が微妙に異なるらしい(参考)。 ↩︎

  4. インターネットドラフトで定義されている(リンク)。クライアント証明書が暗号化開始前に送られることを問題視して、別のクライアント認証の手法を提案している。 ↩︎

KIDANI AkitoKIDANI Akito
RFC 7627 Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension
  • 過去のハンドシェイクメッセージを利用して新しい拡張マスターシークレット(extended master secret)を計算
RFC7627 拡張マスターシークレットの計算
   master_secret = PRF(pre_master_secret, "extended master secret", session_hash)[0..47];
  • 以下の点で通常のマスターシークレットの計算と異なる
    • ラベルがmaster secretではなくextended master secret
    • ClientHello.random + ServerHello.randomではなくsession_hashを利用
  • session_hash = Hash(handshake_messages):Finishedメッセージのverify_data計算時に計算されるものと同一。セッション再開の場合は新規セッションが作られないので、session_hashも存在しない。
  • session_hashにはClientHello.random + ServerHello.randomに加えて、利用可能な暗号スイートや鍵交換情報、利用された証明書などのハンドシェイク時のログが含まれる
  • 新しいTLS拡張extended_master_secret(0x0017)を利用する:extension_dataは空なので16進数表記で00 17 00 00となる
  • このRFCに対応済みのクライアントは全てのClientHelloでTLS拡張extended_master_secretを送信する
  • それを受け取った対応済みのサーバもServerHelloで同じ拡張を送信する
  • 双方が利用に合意した場合、新しいセッションでは拡張マスターシークレットを利用する
  • クライアントは拡張マスターシークレットを利用していないセッションを再開する場合は、セッションリザンプションのハンドシェイクではなくフルハンドシェイクを実施せよ
  • セッションリザンプションを実施する場合はTLS拡張extended_master_secretが必須:新旧セッションで同拡張がない場合や同拡張の有無に差異がある場合[1]は、handshake_failureアラートプロトコルを送信
  • SSL3.0はTLS拡張が使えないのでサポート対象外
脚注
  1. 例外的に、オリジナルセッションでextended_master_secret拡張を使わず、再開セッションでextended_master_secretを利用する場合は、handshake_failureアラートを送信せず、代わりにフルハンドシェイクを実施する。 ↩︎

KIDANI AkitoKIDANI Akito

7.7 POODLE

Padding Oracle On Downgraded Legacy Encryptionの略。

p.235 2014年10月、Googleのセキュリティチームが発見したSSL3.0の脆弱性
p.235 CBCモードでパディングが保護されないのが根本原因:パディングオラクル攻撃が可能
p.235 SSL3.0ではパディング構成と検証の規則がゆるい:パディング部分に何を入れても良いことになっていた=改竄検知不可
p.235 TLS1.0ではパディング長を示す値が入るよう修正済
p.236 最後のブロックが全てパディングの場合、末尾のバイトがAES(16バイトずつのブロック)なら15、3DES(8バイトずつのブロック)なら7となることを利用する
p.236 最後のブロックが全てパディングの場合、MAC検証対象外なので、暗号文を書き換えてもSSL3.0では検出されない
p.236 最後のブロックの暗号文を書き換えて復号時エラーがでない=正しいパディング値(15or7)が得られたことになる(256分の1の確率で成功する)
p.236 CBCにおける暗号化:暗号化 ( 平文n ⊕ 暗号文n-1 ) = 暗号文n
p.236 CBCにおける復号:復号(暗号文n) ⊕ 暗号文n-1 = 平文n
p.237 攻撃対象のブロックをiとし、その末尾のバイトのみ考える:暗号化(平文i[15] ⊕ 暗号文i-1[15]) = 暗号文i[15] ...(A)
p.237 AESの場合末尾のバイトが15となる:攻撃対象のブロックをパディングブロック(暗号文の末尾)に配置(参考:SSL v3.0の脆弱性「POODLE」ってかわいい名前だけど何?? | BLOG - DeNA Engineering

  • 復号(暗号文i[15]) ⊕ 暗号文n-1[15] = 15
  • すなわち:復号(暗号文i[15]) = 15 ⊕ 暗号文n-1[15] ...(B)
    p.237 (A)の左辺と(B)の右辺より
  • 平文i[15] ⊕ 暗号文i-1[15] = 15 ⊕ 暗号文n-1[15]
  • すなわち:平文i[15] = 15 ⊕ 暗号文n-1[15] ⊕ 暗号文i-1[15]
  • 2回の排他的論理和をとるだけで1バイトが推測できる

7.7.1 実用的な攻撃

p.237 他の脆弱性同様、POODLE悪用には複雑な準備が必要

  1. 犠牲者のブラウザから標的サーバへ任意のリクエストを送信できる
  2. 犠牲者のブラウザからネットワークを制御する(BEAST攻撃同様)
    p.237 具体的にはPOSTリクエストで送信先URLとリクエストボディを制御し、任意データを埋め込んで最後尾暗号ブロックがパディングのみとなるようにする
    p.238 Cookieを攻撃する例
  • HTTPリクエストのうち..Cook「ie: JSESSIONID=B」3DF..の部分が暗号ブロックとなる
  • 不明なのはクッキーの最初の1文字:これが16バイト目に来ている
    p.238 送信データを1バイトずつ減らしていき、暗号ブロックが1つ減る(16バイト減る)タイミングでパディングオンリーのブロックの存在が確定する
    p.238 送信先URL(クッキーの前)とリクエストボディ(クッキーの後ろ)を調整して、残りのクッキーを推測できる
    p.238 1文字256回で成功する:200文字推定しても5万回以下のリクエスト数でクッキーがわかる、本章の他のどの攻撃より効率的!

7.7.2 影響

p.238 当時の主要なブラウザはTLSハンドシェイク失敗時にセルフダウングレードする設計:ほぼ全てのサーバがTLS1.0に対応しており、TLS1.0以降にダウングレード攻撃対策があっても意味がない(詳細は6.6節 プロトコルダウングレード攻撃
p.239 クッキーの値やパスワードなどの小さくて価値ある情報が攻撃対象

p.239 2014年12月、TLS実装上の問題でPOODLEの影響があることが明らかに:パディング検証の実装漏れ
p.239 ハードウェアアクセラレーションカードなどで発見
p.239 2014年12月のSSL Pulseの結果では10%のサーバがPOODLEに脆弱[1]