atprotoではrepositoryに対して署名を行うが、これによって何が嬉しいのかを考える。
【結論】 大事なrecordを提示する時は署名も示す文化が根付けばメリットはあるが、周知されなければ署名し損 [1]
とりあえず以下の2つの仮定をおく。これはかなり強い仮定なのでその影響は別途検討する必要がある。
-
repository全体を持っていれば常に検証可能である
-
recordを取得する際には常にrepository全体を取得している
署名はMST rootに対して行われ、commitにrootのCIDとともに保持される。rootにはMSTの他にDIDと前commitのCIDが含まれる。auth_tokenはもう無い。
署名鍵はPDSが持つもので、同じPDSに所属するユーザーは同じ鍵を共有することが想定されている。それはそれで気になるが、コスト面の理由とのこと。
commitに含まれる情報を考えれば、署名によって検証可能なのは以下の2点となる。
-
あるcommitについて、含まれる全てのrecordがPDSに認められていること
-
ある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と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をクライアントに保持されても無駄にストレージ消費するだけで普通は困るので、その判断自体は妥当だとは思うが、そもそもユーザは署名の存在すら意識することはなさそう。
以上を踏まえると、署名を活かせそうなところは以下。
-
「この投稿の魚拓をとる」機能をつけて、特定のrecordに対して明示的に署名を保存
-
投稿者がrecordを無かったことにしても証拠として突きつける用途
-
似たような感じで特定のrepositoryに対する監査システムも作れる
-
この用途だと鍵変更に弱いので注意
-
-
自分のPDSが嘘ついてないか確認
-
定期的にクライアントがこれまで取得した投稿の署名とりにいくとか
-
投稿PDSに真偽を問い合わせることに対する利点は取得PDSでキャッシュが効くくらい?
-
ただし、DIDの解決もそのPDSを通すならrepository丸ごとすり替えは可能
-
1が実現できてちゃんと周知できれば捏造に強い文化が作れて嬉しいが、それを実現するにはまず公式クライアントに頑張ってもらわないと厳しそう。
現状PDS移行実装はrepositoryを作り直していて、なんならDIDも引き継がず作り直してるっぽい。今後対応するつもりではあるようなので待ちか。
bluesky-social/atproto#736