## HTTP Message Signatures ― HTTPクライアントの身の証を立てる  白方 健太郎 (@argrath) --- ## Me * 白方 健太郎 (@argrath) * Wandering Programmer * お仕事募集中 --- ## おしながき * Structured Field Values for HTTP (RFC 9651) * HTTP Message Signatures (RFC 9421) ---
Strucured Field Values for HTTP
---
Strucured Field Values for HTTP
HTTPヘッダに構造化データを書く仕様
--- ### 基本データ型 (bare item) ```text * integer * decimal * string * token * byte sequence * boolean * date * display string ``` --- ### 基本データ型 (bare item) ```text * integer 123456789012345 * decimal 123456789012.123 * string "ASCII Only" * token text/html * byte sequence :WUFQQwo=: * boolean ?0 ?1 * date @1763081100 * display string %"UTF-8 %e7%a6%8f" ``` --- ### データ構造 ```text * item "YAPC" * list "Hiroshima", "Hakodate", "Fukuoka" * dictionary a=1, b="XYZ" ``` --- ほぼ
ネストはできない
---
内部リスト
--- ### 内部リスト(inner list) `key1=(1 "bar" 5.4)` * 内部リストのネストはできない ---
パラメータ
--- ### パラメータ (parameter) * アイテムに追加情報を付けられる * `"foo";a=1;b="x"` * XMLの属性のイメージ * `
foo
` --- ### 練習問題 ```text Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8 ``` ---
第一部完
---
HTTP Message Signatures (RFC 9421)
---
課題
--- ### 課題 不特定多数がアクセスするサーバに対して、 クライアントが身の証を立てる、つまり 「自分が何者か」を証明するのは難しい。 --- ### 課題 不特定多数がアクセスするサーバに対して、 クライアントが身の証を立てる、つまり 「自分が何者か」を証明するのは難しい。 * IPアドレス? * User-Agentフィールド? --- ### 例: ボットの識別 * 好ましいボットにだけアクセスさせたい --- ### 例: 通知を受ける * ActivityPub のフォローリクエスト * 本当に本人から? ---
解決法
--- ### 解決法 HTTPメッセージに電子署名する --- ### 考慮点 1. ヘッダの内容は変わることがある 2. 一部のヘッダだけを署名する 3. どのヘッダに署名したかの情報が必要 署名にどのフィールドが必要かは「決め」の問題。 ---
例: ActivityPub(Mastodon)の場合
--- ### 最終形 ```text Signature-Input: sig1=("@method" "@target-uri" "content-digest") ;created=1763081100 ;keyid="https://src.example.com/foo#main-key" Signature: sig1=:Y2FiYW...IxNGRiZDk4ZA==: ``` * Signature-Input: 何に対して署名したかの情報 * Signature: 署名本体 * `sig1`は識別子。複数の署名を使うことも可能。 --- ### Signature-Input ```text Signature-Input: sig1=("@method" "@target-uri" "content-digest") ;created=1763081100 ;keyid="https://src.example.com/foo#main-key" ``` * `("@method" ...)`: 署名するフィールド(後述) * `created`: 作成時刻 * `keyid`: 公開鍵情報(後述) --- ## 派生要素(Derived Components) フィールドに現れない情報を扱う疑似要素 ```text @method: POST @target-uri: http://dest.example.com/bar/inbox ``` --- ### Content-Digest (RFC9530) content-body のダイジェスト値を表現するためのフィールド: ```text Content-Digest: sha-256=:d435Qo+nKZ+gLcUHn7GQtQ72hiBVAgqoLsZnZPiTGPk=: ``` --- ### keyid * 公開鍵を取得するための情報 * 詳細は定義されていない --- ### keyid ActivityPubの場合はURIを指定する。 ``` ;keyid="https://src.example.com/foo#main-key" ``` `https://src.example.com/foo`にアクセスするとJSONが得られる: ```json { ... "id": "https://src.example.com/foo", "publicKey": { "id": "https://src.example.com/foo#main-key", "owner": "https://src.example.com/users/foo", "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIB...\n-----END PUBLIC KEY-----\n" }, ... } ``` ---
署名の手順
--- ### 署名対象データ(signature base)を作る ```text sig1=("@method" "@target-uri" "content-digest") ;created=1763081100 ;keyid="https://src.example.com/foo#main-key" ``` * 内部リストに示された順番にフィールドの内容を書く。 * 最後に`"@signature-params"`フィールドとしてSignature-Input自身を1行で書く。 --- ### 署名対象データ(signature base) ```text sig1=("@method" "@target-uri" "content-digest") ;created=1763081100 ;keyid="https://src.example.com/foo#main-key" ``` ↓ ```text "@method": POST "@target-uri": http://dest.example.com/actor/inbox "content-digest": sha-256=:d435Qo+nKZ+gLcUHn7GQtQ72hiBVAgqoLsZnZPiTGPk=: "@signature-params": ("@method" "@target-uri" "content-digest")(折り返し) ;created=1763081100;keyid="https://src.example.com/foo#main-key" ``` --- ### 署名 * 署名する * ハッシュ化する * ActivityPubの場合 RSASSA-PKCS1-v1_5 / SHA-256 * base64変換する ↓ ```text Y2FiYW...IxNGRiZDk4ZA== ``` --- ### ヘッダに追加 ```text Signature-Input: sig1=("@method" "@target-uri" "content-digest") ;created=1763081100 ;keyid="https://src.example.com/foo#main-key" Signature: sig1=:Y2FiYW...IxNGRiZDk4ZA==: ``` ---
検証の手順
--- ### 検証 ```text Signature-Input: sig1=("@method" "@target-uri" "content-digest") ;created=1763081100 ;keyid="https://src.example.com/foo#main-key" Signature: sig1=:Y2FiYW...IxNGRiZDk4ZA==: ``` * 署名ベースを作る * keyidから公開鍵を取得する * 検証する --- ## 終わり * 資料予定地: https://argrath.ub32.org/slide/2025/1114/index.html 