タグ: TLS 1.3

  • TLS 1.3の0-RTTとHTTP 425、速さと再実行の危険をどう分けるか

    TLS 1.3の0-RTTとHTTP 425、速さと再実行の危険をどう分けるか

    同じサービスへもう一度接続するとき、暗号通信の準備が終わるのを待たずに、最初の要求を送る。TLS 1.3の0-RTTは、こうして通信の往復待ちを減らす仕組みです。ところが、早く送った要求が暗号化されていることと、その要求が一度しか実行されないことは、同じ保証ではありません。[1]

    HTTPでこの違いを扱うために用意された応答が、425 Too Earlyです。何を早く処理してよく、何を待たせるべきなのか。0-RTTの時間短縮と、同じ要求が繰り返されるリプレイの危険をつなげて考えます。

    簡単にまとめると?

    • 0-RTTは、共有済みの鍵を使って、TLSの最初の送信にアプリケーションのデータを載せます。通信時間がゼロになる意味ではありません。
    • early dataは暗号化されますが、別の接続で再利用されない保証は通常のTLSデータと異なります。読み取り用に見える要求でも、再実行の副作用を確認します。
    • HTTP 425は、リプレイされ得る要求をそのまま処理しないための応答です。再試行ではearly dataを使わず、プロキシを通る場合も前段の情報を引き継いで判断します。

    0-RTTが省くのは、要求を送る前の往復待ち

    TLSは、通信相手や暗号の条件を確かめ、データを守るための鍵を整えるハンドシェイクを行います。RTTはRound-Trip Timeの略で、通信が相手へ届いて戻るまでの往復時間です。TLS 1.3の通常の1-RTTハンドシェイクでは、クライアントはサーバーからの応答を受け取ってから、通常のアプリケーションデータを送れます。[1]

    0-RTTでは、クライアントとサーバーがPSK(事前共有鍵)を共有していることを利用します。代表的なのは、前回の接続で得た情報を使って接続を再開する場合です。仕様上は外部で共有されたPSKも対象ですが、どちらも、初対面の相手へ何の準備もなく早期送信できる仕組みではありません。クライアントは最初のClientHelloに続けて、PSKから導いた鍵で守ったearly data(早期データ)を送ります。サーバーが受け入れるとは限らず、その後のハンドシェイクも必要です。[1]

    RFC 8446のFigure 4。クライアントからの最初の送信にearly dataのApplication Dataがあり、その後もServerHelloやFinishedなどのハンドシェイクが続く。
    IETF, E. Rescorla, RFC 8446 Figure 4(2018年8月)。左がクライアント、右がサーバー。最初の矢印にある丸括弧のApplication Dataがearly dataで、その後の角括弧のデータとは保護に使う鍵が異なります。原図の文字・配置・凡例を保ってPNG化。狭い画面では左右にスクロールでき、画像を開くと拡大できます。Copyright (c) 2018 IETF Trust and the persons identified as the document authors. All rights reserved. 原典/利用条件。

    図で確認したいのは、0-RTTでもハンドシェイクが消えていないことです。省けるのは、最初の要求を送るまでに待つ一往復です。サーバーが要求を受け取った直後に処理できるかは、さらに別の判断になります。

    たとえばRTTを80ミリ秒、片道を40ミリ秒と仮定します。TLSの送信開始を0ミリ秒とし、ハンドシェイクの追加往復、通信損失、処理時間を考えない場合、要求がサーバーへ届く時点は次のようになります。TCP接続やDNSの時間は、この比較に含めません。

    最初の要求が届く時点の計算例。測定結果ではない
    送り方 クライアントが要求を送る時点 サーバーへの到着
    通常の1-RTT サーバーの応答を受け取る80ミリ秒後 120ミリ秒後
    受け入れられる0-RTT 最初の送信と同時の0ミリ秒 40ミリ秒後

    この条件では、到着を一往復分の80ミリ秒早められます。ただし、画面全体の表示が必ず80ミリ秒速くなるとは言えません。early dataの拒否、要求処理の保留、サーバーの計算時間などが結果に関わります。0-RTTは、特定の待ちを減らす手段として見る必要があります。

    暗号化された要求も、別の接続で繰り返され得る

    リプレイは、攻撃者が通信を記録して再び送り、同じ要求を処理させようとすることです。利用者がボタンを押し直すことや、クライアント自身の再試行とは区別します。また、パケットを失った際のTCPの再送を、そのままアプリケーションの二重実行と同一視するものでもありません。[2]

    通常のTLS 1.3のデータは、その接続でサーバーから受け取った乱数などに結び付いた鍵で保護されます。一方、early dataはServerHelloを受け取る前に送るので、まだその値に依存できません。攻撃者が内容を解読しなくても、暗号化された最初の送信を別の接続へ持ち込む危険が残ります。RFC 8446は、0-RTTについて接続間の非リプレイ性を保証しないと明示しています。同じ接続内で同じデータを二重に処理するという説明ではありません。[1]

    サーバーには、セッションチケットを一度だけ使えるようにしたり、最近のClientHelloを記録して重複を退けたりする対策があります。ただし、複数のサーバーで状態をどこまで共有するかが効いてきます。TLSでの重複排除と、拒否を受けたクライアントが別の接続で再試行して生じる重複は、同じ問題ではありません。後者には、アプリケーション側の扱いも必要です。[1]

    もう一つの違いは前方秘匿性です。これは、後から鍵が漏れても、過去の通信内容が守られる性質を指します。early dataはPSKだけから導いた鍵で暗号化されるため、通常の後続データと同じ前方秘匿性を持つとは扱えません。「TLS 1.3で暗号化した」という一言で、早期データの性質まで一括りにしないことが大切です。[1]

    GETかどうかだけでなく、繰り返されたときの作用を見る

    たとえば、同じ操作が二度届くと数量を二度加算する処理なら、早期送信を受け入れる前に二重実行の扱いを決める必要があります。一方、状態を変えない情報の取得は候補になり得ますが、それだけで無条件に問題がないわけではありません。取得のたびに別の処理を起動する、利用枠を消費する、といった副作用も確認対象です。これは個別サービスの実装を調査した例ではなく、判断のための仮定です。

    RFC 8470は、ほかに情報がないクライアントに対し、安全なHTTPメソッドの要求はearly dataで送ってよい一方、安全でない、または安全性の分からないメソッドは送ってはならないとしています。ただし、GETなど安全なメソッドを名乗るリソースでも副作用を生むことがあるため、メソッド名だけには依存できないとも述べています。何が実行されるかを知るオリジンサーバー、つまり最終的に要求を扱うサーバーの判断が必要です。[2]

    サーバー側で考えられる選択は、TLSの段階でearly data全体を拒否する、ハンドシェイクが終わるまでHTTPの処理を待つ、個別の要求へ425を返す、の三つです。TLSの受入れはearly data全体に対する判断であり、その層で要求ごとに一部だけ拒否するものではありません。HTTPの段階では、リソースごとの扱いを決められます。[2]

    HTTP 425は、early dataを使わない再試行へ戻す

    425 Too Earlyは、リプレイされ得る要求を処理する危険を、サーバーが受け入れないという応答です。early dataで要求を送ったクライアントは425を受けたら再試行し、その再試行をearly dataで送ってはいけません。仕様は自動再試行を推奨していますが、重要なのは、同じ早期送信を繰り返すのではなく、通常の保護が使える段階へ戻すことです。[2]

    したがって、425は要求の内容が永久に禁止されたという意味でも、二重実行済みの処理を取り消す命令でもありません。早く処理してよいか判断できない段階で処理を進めず、クライアントとサーバーが次の送り方を合わせるための仕組みです。early dataでもなく、後述のEarly-Dataヘッダーもない要求へ、一般的な待ち時間の応答として425を流用することは、RFCが想定する使い方ではありません。[2]

    プロキシを挟むと、後段の接続が終わっていても判断は残る

    要求が、クライアントからゲートウェイやリバースプロキシを経て、オリジンサーバーへ届く場合を考えます。前段でearly dataを受け取り、クライアントとのハンドシェイク完了前に後段へ転送するなら、中継するサーバーはEarly-Data: 1を付けます。このヘッダーは、前の区間でearly dataとして運ばれたことと、425を扱えることを伝えます。既に付いているものを中継で取り除いてはいけません。[2]

    ここで、オリジンサーバーとプロキシの間のTLS接続が終わっていても、前段のearly dataの履歴は消えません。オリジンサーバーが自分側のハンドシェイク完了だけを待っても、その要求を安全に処理できるものへ変えたことにはならないのです。Early-Dataが付いた要求を安全に処理できなければ、425で拒否します。[2]

    また、早期に処理してはいけない要求を、一台だけ実行してしまう不整合も避ける必要があります。同じ要求を受け得るサーバー群で、処理を始めてよい条件をそろえます。TLSでの拒否、HTTPでの保留、425の使い分けまで同じにする必要はなく、危険な要求を早期に実行しない点で一貫していることが重要です。0-RTTを採用する判断では、短くできる往復待ちに加えて、リソースの副作用、再試行、中継経路、複数サーバーの一貫性までを一緒に確認します。それが難しい要求を待たせることは、速さを優先しない場面を具体的に決めることです。[2]

    参考資料

    1. E. Rescorla, IETF/RFC Editor, RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3、2018年8月。§2.3とFigure 4、§8、Appendix E.5。PSKとearly data、接続間リプレイ、対策と限界を参照。
    2. M. Thomson, M. Nottingham, W. Tarreau, IETF/RFC Editor, RFC 8470: Using Early Data in HTTP、2018年9月。§§1〜6。HTTPの処理保留、メソッド、Early-Dataヘッダー、425と再試行条件を参照。