同意鍵、Client IDの取得について #34
Labels
No Label
bug
discussion
documentation
duplicate
enhancement
feature
help wanted
invalid
Priority
High
Priority
Low
Priority
Medium
question
wontfix
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: stat2/delightly-v2fork#34
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
delightlyでは忍法帖に代わるユーザー管理の手段として、フィンガープリントを元に生成した同意鍵を使用しているようです。認証時に複数ID取得の難易度が上がることや、クライアントからcookieで同意鍵を送信しており管理上のメリットがあります。
しかし、フィンガープリントベースなため特定環境下では多数の人の同意鍵が被ってしまい、同意鍵でユーザーを識別する機能や規制は問題がありそうです。
delightly-v2ではClientIDが指すものがいくつかありややこしいので整理してみます。
認証時に生成される
ClientID
(詳しくは/static/client.js
の解読が必要。32桁の文字列だと思われる)↓(md5hash化等)
$WrtAgreementKey (in /test/auth.php)
(いわゆる鍵。メール欄に#付きで入力する8桁の数値)↓(md5hash化,sha256hash化等)
$clientid (in /test/auth.php)
(/HAP/
以下に生成される同意鍵ファイルのファイル名。64桁の文字列)↓(同値)
$clientid (in /test/bbs-main.php)
(同意鍵ファイルの
range
,provider
,CH_UA
,ACCEPT
からmd5hash化等)$WrtAgreementKey (in /test/bbs-main.php)
(投稿ログや掲示板内でClientIDと呼称される英数字7桁)規制に使用されるClientIDは
/test/bbs-main.php
にある7桁の$WrtAgreementKey
となります。こちらは生成に使用される要素が利用者の8桁IDと同じなため、被りやすさも同等と考えられます。
同意鍵ファイルの被りやすさについては
/static/client.js
が解読できていないので何とも言えません。規制のみについて考えるなら、同意鍵ファイルから使用する要素を増やして生成した
$strictClientID
のような新たなIDを定義して使用したほうが巻き添え規制は防げるかもしれません。first
(認証時のエポック秒)などを混ぜればかなり被りにくくなると思います。おそらく問題になっているのは次の行でしょう。
8833f2971a/test/auth.php (L195)
これは「
$WrtAgreementKey
を取得したことがあるIPアドレスの場合、3日以内であれば同じ$WrtAgreementKey
を返す」という処理になっています。たぶん自演防止が目的だと思うんですが、IPアドレスが被りやすいプロバイダの利用者からすれば迷惑極まりない仕様になっているような。
確かにalice2chさんのご指摘の通り、IPアドレスが被っている複数の利用者が一定期間内に続けて認証すると同じ鍵を返す処理になっていますね。同意鍵自体が被るケースも十分ありえるようです。
static/client.js は https://github.com/fingerprintjs/fingerprintjs をビルドしたものだと思いますよ。
FingerprintJS は BSL 1.0 (2023/07以前なら MIT) なので、ファイル中に Copyright とライセンスの表記を行っておかないとライセンス違反になってしまう、、、というのはひとまず置いておいて。
問題は送信されてくる ClientID が、FingerprintJS が生成したものなのか、はたまた人為的に上書きされた文字列なのか検証していないので、実は任意の32桁の文字列ならなんでも受け入れてしまうし、偽造しようと思えばいくらでも偽造できてしまうということです。
ブラウザで test/auth.php を開いて、ブラウザの開発者ツールから
input#ClientID
の value を00000000000000000000000000000000
とかに書き換えて同意ボタンをクリックしても普通に通ってしまいます。ですから static/client.js は32桁の乱数を生成する代わりに使われてるような感じで、実は必要ないし、荒らし対策としての効果もたぶんゼロです。
なるほど。ご説明ありがとうございます。
ありがとうございます。
なるほどそうなっていたんですね〜
8833f2971a/test/auth.php (L195)
この部分のIPアドレスによるものなのか、もう一回ログを見直してみます。3日だとかなり被る人が出てしまいそうですね。
認証時の同意鍵被りについての対策を少し考えました。
認証時にIPアドレス等の一致により同じ鍵を返却する処理(おそらく自演対策)について
該当の処理は
/test/auth.php
の以下の部分です。ca415d001d/test/auth.php (L192-L199)
現在は、「IPアドレス」あるいは「IPアドレスの先頭部、回線、UA、acceptヘッダー」が同じ環境に対して、前回の認証から30日間は同じ鍵を返す処理になっています。
期間が長いほど鍵被りが発生しやすくなるので短くするのが一つの方法かもしれません。3日間の場合は
259200
、1日間の場合は86400
となります。また、メンテナンス等で現存の同意鍵を全てリセットする場合などは、復帰時に一斉に認証されることが予想されるので一時的に
0
にする等の処理が望ましいかもしれません。その場合、#34 (comment) で指摘されているように単純な操作で鍵を量産できてしまうので、生成された鍵の扱いを修正した方が良いかと思います。次項に例があります。
鍵生成をより安全に
#34 (comment) で示されているように、鍵を自由に作成可能な脆弱性があります。
対応策として、
/static/clientid.js
にて生成されたidをフォーム送信直前に入力するような修正案を考えました。完全に安全ではないと思いますがマシにはなっているかと思いますがどうでしょうか。(8ae8fe023c
)もっと良い対策や修正案があれば教えていただきたいです。