HTTP Signatures
#仕様
https://datatracker.ietf.org/doc/rfc9421/
https://httpsig.org
HTTPリクエストを認証する仕組み。あるActorへのメッセージングの出所が正しいことを証明するために必要。
例:
@foo@ap1.example.comのinboxに@bar@ap2.example.comからのメッセージを示すActivityがやってきたとする
本当に@bar@ap2.example.comからのリクエストかどうかは、一般的なServer Side HTTPS単独では証明不能
Actorごとに鍵を持ち、HTTPリクエストに電子署名することでリクエストの出所を証明する
簡単なしくみの解説
サーバーへリクエストを送る際にActorの秘密鍵を利用して、リクエストヘッダーを署名する
ソートしたり、正規化したり、特定のリクエストヘッダーのみに絞ることで、HTTPリクエストを中継するサーバーによるリクエストヘッダーの加工耐性がある
リクエストボディを署名する際は Digest: ヘッダーを含めて署名することで間接的に署名することができる
署名に公開鍵についての情報(KeyId)を記載して、リクエスト先のサーバーはその公開鍵を用いて検証する
ハマりどころ
他のインスタンスのINBOXにPOSTするときなどはDigest:ヘッダを付けて内容の証明もする必要がある
マストドンでは必須
マストドンの場合Digest: SHA-256=123456deadbeefという表現になる
文献によってsha-256だったりSHA-256だったりする・・・
いくつかの実装を見る限り、大文字で送信しているものが多い (受信する場合はどちらでも OK にしておくのが無難)
cat json.json | sha256sum | xxd -r -p | base64するとbase64形式でsha256確認できるのでデバッグにおすすめ
リクエストボディをファイルに保存する場合、末尾に改行があることで異なる結果が出るケースに注意。エディタによっては自動的にファイル末尾に改行を付加する
echoを使う場合は -n フラグで改行を無くせる
echo -n '{"hello":"world"}' | sha256sum | xxd -r -p | base64
このとき、Digest:ヘッダはdigestとして署名対象になることに注意
署名に使う(request-target)において、メソッドに続くものはURLでもパス単体でもなく$path$queryの形になる
良い例 /alice/inbox, /foo?bar=1, /
悪い例 https://example.com/alice/inbox (authority部分は不要!)
署名の検証の際は、最低限 (request-target)、host、date、digest、content-type の各ヘッダを署名対象の文字列に埋め込めるようにしておく必要がある
digest は上述の通り
content-type に言及しているところは少ないので、手抜きをしているとハマる (ちゃんと HTTP ヘッダ見ましょう)
genya0407.icon mastodon は host なくても動くけど misskey は host 必須ぽい
対 Misskey (あるいは HTTP Signature 準拠の実装?) の場合、Authorization: ヘッダも必要
ヘッダの値は Signature keyId=... のように、Signature: ヘッダの値の前に Signature + 半角スペースとする
hr.icon
話題
ふぁぼん.iconなんか新しい仕様提案があるらしい
最新のdraftはHTTP WGのやつ?
unasuke.icon ですね、 draft-cavage-http-signatures は draft-ietf-httpbis-message-signatures によってreplaceされています
HTTPメッセージに署名をするSignatureヘッダの標準化 - ASnoKaze blog
このRFCのステータスはよく分からない
unasuke.icon IESG Evaluationの段階なのでまあそう遠くないうちにRFCになる、のかも?
see also https://datatracker.ietf.org/help/state/draft/iesg
2024年2月にRFC 9421になった🎉
https://datatracker.ietf.org/doc/rfc9421/
windymelt.icon こいついっつもドラフトしてんな(早く完成させてくれ!!!)
Mastodonのissue: https://github.com/mastodon/mastodon/issues/21429
Tatamo.icon httpbis版の最新ドラフトと cavage版の Signature ヘッダーに互換性がなさそう。現状では Mastodon のドキュメントに書かれている cavage版に合わせて実装するほうが無難? https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures
GoToSocial でも現状 cavage版に従うと書かれているようです https://github.com/superseriousbusiness/gotosocial/blob/6dbb8ba7aaa91bd865a408d8a9a87c70ad0bac84/docs/federation/federating_with_gotosocial.md
基本的に手作りせずライブラリを使うのが定番
ライブラリでうまく行ったら言語ごとにここに報告して!!
Ruby
unasuke.icon 乱立してる上に、どれも古いdraftを参照していてメンテされているかどうか不安
https://github.com/99designs/http-signatures-ruby
https://github.com/bolmaster2/http-signature
https://github.com/krainboltgreene/net-http-signature.gem archived
https://github.com/nomadium/linzer
httpsig.orgからリンクされており、かつ An implementation of HTTP Messages Signatures (RFC9421) と謳っているのでRFCに準拠していそう?
JavaScript/TypeScript
Tatamo.icon あまりいいライブラリがなかった。みんな crypto か crypto.subtle で手作りしてそう
https://github.com/dhensby/node-http-message-signatures
httpbis, cavage 両方の署名に対応しているが verify が未実装
activitypub-http-signatures
https://github.com/misskey-dev/node-http-message-signatures
unasuke.icon Misskey側で実装が進められているやつ
Go
nyarla.icon go だと GoToSocial が使っているこのライブラリが有力かもしれない(?)
https://github.com/go-fed/httpsig
中身がめちゃめちゃシンプルなので他の言語で実装する際の参考になるかもしれない (個人の感想です)
https://github.com/superseriousbusiness/httpsig
今だとGoToSocialは上記ライブラリのcommunity forkを使ってるみたいです
https://github.com/yaronf/httpsign/
Java / Scala
windymelt.icon tomitribe/http-signatures-java: Java Client Library for HTTP Signatures
uriって書いてあるところにURIを渡すとハマる。実際はpath+queryを渡さなければならない
https://github.com/bblfish/httpSig/
https://github.com/bspk/httpsig-java/
PHP
おさ.iconforkだけどメンテは続いている。
https://github.com/vend/http-signatures-php
Tatamo.icon https://docs.joinmastodon.org/spec/security/#digest に記載されている Digest ヘッダーは、リクエストボディを JSON.stringify() にかけた結果で、かつ末尾に改行のない文字列をハッシュ化することで値が一致しました
ActivityPubの実装についてのメモ
Security - Mastodon documentation
hr.icon
windymelt.icon 実装が難しくてぜんぜん上手くいかない!!!
mushus.icon 簡単なしくみの解説を書いてみましたが、ゆるふわな認識なので間違いがあったら訂正してください><
HTTP SignaturesのkeyIdはActivityPubの文脈ではURLになる?
公開鍵の配布しているエンドポイントにはHTTP Signaturesによる検証はできない
一部のサーバーはActorのURL(?)に#main-keyみたいなフラグメントをつけているが、そのような実装だと該当のページにHTTP Signaturesを利用できなくなる
GoToSocial の場合はActorのURLと公開鍵を配布しているURLを別にすることでActorのURLにもHTTP Signaturesを使えるようにしている?
署名するヘッダーはhostとdateと(request-target)は最低限必要っぽい。
lacolaco.icon 新しい仕様の提案の中にはレスポンスに署名することを要求する Accept-Signature なるコンテンツネゴシエーションがあるらしい?
https://httpwg.org/http-extensions/draft-ietf-httpbis-message-signatures.html
unarist.icon SocialCGでもActivityPubで使うHTTPSignatureの整理をはじめたっぽい https://github.com/swicg/activitypub-http-signature/issues/26
unasuke.icon 検証できるツールができてる? https://httpsig.org
いくつかの言語の実装もここにリストされている