0-RTT とは
0-RTT : 0-Round Trip Time はTLS 1.3 で新しく導入されたプロトコルの機能で、暗号文による通信を平文のTCPと同じ遅延で可能にするものです。
TLS 1.2以前は暗号化通信開始時時に2RTT(2往復)の通信が必要でしたが、TLS 1.3の標準は1RTT, オプションで0RTTで通信が開始できパフォーマンスが向上しています。
一方、0-RTTはセキュリティ面ではマイナス面も考えられます。過去の経験上は脆弱性が予想される機能が真っ先に攻撃対象になってきた、という事からも0-RTTの利用は慎重に検討する必要があります。0-RTTはオプションなので使用しなくてもかまわないものです。
0-RTTの概要
端折り気味だと思いますが原文を図式化すると以下の様になると思います。

上記処理の前提として、前の通信でサーバーはハンドシェイク完遂後に0-RTTを受け入れする際、チケットにearly_data拡張を付与します。(0-RTTで転送許可するデータ長も指定します。)
クライアントが通信再開時、ClientHelloにearly_data拡張を付与して通信を開始します。
サーバーは受け取ったearly_data拡張をアプリケーション層で処理させて通信再開の可否を判断させるのが原則ですが、このプロセスはオプション扱いになるので省略も出来てしまいます。原書では直接的な書き方になっていないと理解しましたが、このような脆弱性が許容されうる点が0-RTTの脆弱性だと指摘していると思います。
また、以下2つの脆弱性についての指摘が続きます。
0-RTTの脆弱性:前方秘匿性の欠如
TLS 1.3で使用可能な事前共有鍵を用いる方式2種のうち、鍵交換方式 psk_dhe_ke は異なる鍵で暗号化されるので、前方秘匿性を確保できます。0-RTTでもpsk_dhe_keを使用して再開された接続であれば前方秘匿性を確保できます。
一方、psk_ke 鍵交換方式を使用する場合、0-RTTでは前方秘匿性は確保できません。
前方秘匿性を有効にするためには、データの暗号化に利用される鍵(またはその鍵から導出された鍵)を長期間にわたって使用しないことが有効です。この点でDH鍵交換方式は認証から切り離された暗号鍵をセッションごとに切替するので前方秘匿性の観点では非常に適しています。ですが、 0-RTTではDH鍵交換を使えません。理由はクライアントがデータを暗号化して即座に送信するので、サーバー側での入力がないからです。
0-RTTを使用して前方秘匿性を確保するにはsession resumptionにおいて適切な設計が必要になります。その代表例を以下に紹介します。
0-RTTで前方秘匿性を有効にするための考慮点1:事前共有鍵の寿命
0-RTTでは事前共有鍵を用いた方式で導出された鍵を early_dataの暗号化に使用します。ここでの問題点は同じ鍵を使って複数のデータの暗号化が可能になっている点です。(1つのチケットを再利用できるので、不正に利用される可能性がある)。
この弱点を補完する方法としては、
・サーバーが寿命が短いチケットだけを許可する
・サーバーはハンドシェイクに成功するたびクライアントに対して新しいチケットを提示する
・クライアントは常に新しいチケットを優先して使用する
0-RTTで前方秘匿性を有効にするための考慮点1:チケットの暗号化
session resumptionの実装方法の典型として以下の2種があります。
方法①サーバーのローカルにセッション情報を保持する
この方式の利点は、セッションに関するデータをネットワーク経由でやり取りしない点です。クライアントからセッションを特定するために使う一意な識別子を送信し、サーバーは自身のストレージからセッションを取り出します。
デメリットはサーバーのローカルに情報を保存するのでクラスター構成等の場合、処理をスケールさせることができない点です。(複数サーバー間でセッション情報を共有して管理するのは難しい)
方法②HTTPクッキーに似た方式で暗号化する
この方式ではサーバーのローカルにセッション情報を保存しません。その代りにセッションに関するデータを特別なチケット鍵で暗号化してクライアントに送り返します。この方法のメリットはクラスター化されたサーバー環境でもサーバーが同一のチケット鍵を共有するだけなので実装が容易な点です。
TLS 1.3ではDH鍵交換方式対応により(0-RTT以外ならば)前方秘匿性を確保する事ができます。が0-RTTではDH鍵交換方式が使えない為難しくなります。0-RTTにおいてチケット鍵のセキュリティは従来軽視されてきたようですが、チケット鍵の前方秘匿性を有効にするためにはチケット鍵が短期間で交換させる実装が必須です。
0-RTTの脆弱性:リプレイ攻撃の可能性
0-RTTの大きな問題はリプレイ攻撃 replay attack に弱い点です。
0-RTTを使用しない場合、TLSによる毎回のハンドシェイクは必ず一意になります。(クライアント、サーバー両サイドで暗号学的に強力な乱数を使用するから)
ですが、0-RTTの場合この方式が使用できないので攻撃の余地が生まれます。
クライアントからサーバーに最初に送信したデータを能動的ネットワーク攻撃者が補足し、それをサーバーに複数回送信できてしまいます。サーバー側攻撃者の接続リクエストが全て正しいものと解釈してしまう事が起こりえます。
TLS 1.3ではリプレイ攻撃に対抗する機能がいくつか提示されています。例として、
・事前共有鍵の認証における obfuscated_ticket_ageフィールドを使ってサーバーがチケットの新鮮さを規定する事で能動的ネットワーク攻撃者が無制限に同じデータを再利用できないようにする
たとえば既に処理したearly_dateを追跡して起き、再利用された場合は拒否する、という方法です。しかしこの方法はサーバーが1つの場合は簡単かもしれませんが複数台のサーバーから構成されている場合は複雑になってしまいます。
0-RTTのまとめ
0-RTTの利用は通信パフォーマンスと脆弱性とのトレードオフになります。厳重なセキュリティが無用な通信においてはリスクは低いと言えます。
0-RTTの主な利用シーンはブラウザーからのリクエストです。HTTPにおける0-RTT利用についての詳細なRFCもあります(RFC8470)。
ブラウザー利用はパフォーマンスを優先したい場合も多いのでその際はセキュリティリスクを許容して0-RTTを利用するのは妥当な方法かもしれません。
また、ブラウザーからのGETリクエストのみ0-RTTを使用する、POST,PUT,DELETEなどでは0-RTTを使用しない、という方法も有効と思われます。
ブラウザーHTTPでの課題としては
①アプリケーション層の実装が悪い場合、副作用を伴うリクエストをGETで発行しる場合があり得る事です。例えばGETリクエストをリプレイ攻撃を受けて、自分の口座から別口座に現金振替を無限に実行されてしまう危険性ができるかもしれません。
②HTTPリクエストではセッションクッキーやHTTPのベーシック認証などの認証情報がやり取り可能な点です。実装によっては前方井徳江氏が無い状態で暗号化されて送信されるかも知れません。この場合関連するユーザーアカウントが乗っ取られ、被害が大きくなる可能性もありえます。