Skip to content

Instantly share code, notes, and snippets.

@yamarten
Created March 26, 2023 05:18
Show Gist options
  • Save yamarten/36bad160bdcb07f257bffeb729520a11 to your computer and use it in GitHub Desktop.
Save yamarten/36bad160bdcb07f257bffeb729520a11 to your computer and use it in GitHub Desktop.
ATPの署名の話

atprotoの署名は何を保証するか

atprotoではrepositoryに対して署名を行うが、これによって何が嬉しいのかを考える。

【結論】 大事なrecordを提示する時は署名も示す文化が根付けばメリットはあるが、周知されなければ署名し損 [1]

おさらい

とりあえず以下の2つの仮定をおく。これはかなり強い仮定なのでその影響は別途検討する必要がある。

  • repository全体を持っていれば常に検証可能である

  • recordを取得する際には常にrepository全体を取得している

署名はMST rootに対して行われ、commitにrootのCIDとともに保持される。rootにはMSTの他にDIDと前commitのCIDが含まれる。auth_tokenはもう無い。

署名鍵はPDSが持つもので、同じPDSに所属するユーザーは同じ鍵を共有することが想定されている。それはそれで気になるが、コスト面の理由とのこと。

署名からわかること

commitに含まれる情報を考えれば、署名によって検証可能なのは以下の2点となる。

  1. あるcommitについて、含まれる全てのrecordがPDSに認められていること

  2. ある2つのcommitについて、その順序関係

これによって何が証明できるかと言うと、大体以下のような感じ。

  • recordが投稿者のPDSで生成されたものであること

  • 投稿者のPDSから取得者までの経路で改竄が生じていないこと

  • 取得後に投稿者のPDSで編集・削除されたrecordが存在していたこと

  • 取得後に投稿者PDSで歴史改変が行われたこと

署名しないとどんな悪さができるか

  • 取得者PDS等が取得者に対して捏造recordを示すこと

    • Nostrの署名はこれが主目的な気がするが、ATPはあまり直接鍵を見ない&PDSはある程度信用する前提なので話が違う [2]

  • 投稿者が都合の悪い投稿を改変or無かったことにすること

    • 誰かが当時のcommitを持っていれば署名で検証可能

  • 第三者が「無かったことにされた」体で投稿を捏造すること

    • 署名を提示されずスクショだけでも信じてしまう人はいるだろうが……

  • 投稿者があるreocordが昔から存在していたように歴史改竄すること

    • 改竄時点以降の(改変前の)commitを持っていれば検証可能

  • 第三者が過去のあるrecordを「投稿者が捏造した」と嘘をつくこと

    • 現実的には「当時の証拠なんてもう持ってないよ」と言われたら厳しいが

一方で、例えば以下のことは防止できない。

  • 嘘タイムスタンプ(TIDやrecordが持つ時刻値)

    • PDSの実装によっては投稿(record作成)〜repository更新(TID作成)〜公開に間が空くかもしれない

    • commit間のタイムスタンプ逆転や、検証時刻以降のタイムスタンプなら検証可能

  • 投稿者PDSによる投稿者の意に沿わないcommit

    • 署名するのがPDSである以上、それ以前の検証は当然できない

    • 投稿者PDSに悪意/脆弱性があるならば改変は容易

repositoryとユーザの対応確認

repositoryは常に検証可能なのか、という話。repositoryとDIDの対応関係は以下のようにして確認できる。

  • repository→pubkey: 署名から導出できる

  • repository→DID: rootに含まれている

  • DID→pubkey: DIDドキュメントから得られる

これで2つのpubkeyが一致すれば、対象のDIDの所有者によって認められたrepositoryであることが確認できる……わけだが、最後のステップはDID resolverへの問い合わせを伴う動的な手順であることに注意する必要がある。

何が問題かというと、署名鍵を変更した場合に追える保証が無い。did:plcならDIDの枠外で過去の公開鍵も差し出してくれることが期待できるが [3]、他のDID method(つまりdid:web)はそうとは限らない。PDS変更時には必ず署名鍵が変わるので、基本的には検証時点のPDSによる署名しか検証できない。

とはいえこれは実際にはあまり問題にならないと思われる。古いrepositoryについて検証する場合には、新PDSのrepositoryを引っ張ってきてprevを辿っていけば、旧PDSによる署名に行き着くはず。旧PDSによるcommit全体が置換されていると検証できないので、投稿側に悪意があれば検証させないことはできそう、という程度か。

署名はどこまで届くか

recordを検証するには、少なくともrootと、そのrecordまでのMST上のpathを取得する必要がある。これは常に com.atproto.sync.* を使うことを要請しているわけで、現実的にはそんなクライアントは考え難い。さらに言えば、順序関係の検証等を考えるならcommit列は全て取得する必要がある。つまりgetRepoとsubscribeReposくらいしか許さない。

一方、例えばBlueskyクライアントであれば、普通は app.bsky.feed.getTimeline 等で取得するわけで、メタデータの類はクライアントには届かない。つまり署名は取得側のPDSまでにとどまる。PDS間に関しては実装によるが、repost等で得た投稿についてはgetRecordすら使わず、getBlocksでrecordだけ得る程度でMSTは一切取得しないかもしれない。

全postに対してMSTをクライアントに保持されても無駄にストレージ消費するだけで普通は困るので、その判断自体は妥当だとは思うが、そもそもユーザは署名の存在すら意識することはなさそう。

署名の活用法

以上を踏まえると、署名を活かせそうなところは以下。

  1. 「この投稿の魚拓をとる」機能をつけて、特定のrecordに対して明示的に署名を保存

    • 投稿者がrecordを無かったことにしても証拠として突きつける用途

    • 似たような感じで特定のrepositoryに対する監査システムも作れる

    • この用途だと鍵変更に弱いので注意

  2. 自分のPDSが嘘ついてないか確認

    • 定期的にクライアントがこれまで取得した投稿の署名とりにいくとか

    • 投稿PDSに真偽を問い合わせることに対する利点は取得PDSでキャッシュが効くくらい?

    • ただし、DIDの解決もそのPDSを通すならrepository丸ごとすり替えは可能

1が実現できてちゃんと周知できれば捏造に強い文化が作れて嬉しいが、それを実現するにはまず公式クライアントに頑張ってもらわないと厳しそう。


1. 当然のことを言っているだけのような気もする……
2. そもそもこの検討の出発点はここで、署名して本当に嬉しいか疑問に思った
3. PLCサーバが嘘をついていないことを示すためには、全てのlogのprevとsigが正しく、かつ最初のlogからDIDが導出できることを確認する必要がある
@yamarten
Copy link
Author

違うか。FAQ見るとアカウント可搬性のために署名しているようなことが書いてある。このFAQ書いた時点ではUCAの存在が生きていたんじゃないかと思うけど、その辺は特に触れられていない。

https://atproto.com/guides/faq#why-not-use-activitypub

アカウントの認証自体はPDSでやるので普通は署名なんて要らなくて、PDS移行しようとした時にだけ本当にそのrepositoryが本物なのか確認する必要があって、そこで署名を使うという話か。

でも正しいrepositoryを持っていることは別に本人である保証にならなくて、結局そのためには秘密鍵を使うわけだから、repositoryに対する検証は必要ないのでは?

@yamarten
Copy link
Author

yamarten commented Apr 6, 2023

現状PDS移行実装はrepositoryを作り直していて、なんならDIDも引き継がず作り直してるっぽい。今後対応するつもりではあるようなので待ちか。

bluesky-social/atproto#736

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment