水無月ばけらのえび日記

bakera.jp > 水無月ばけらのえび日記 > ワンタイムトークンをハッシュ関数で処理する意味はある?

ワンタイムトークンをハッシュ関数で処理する意味はある?

2008年10月28日(火曜日)

ワンタイムトークンをハッシュ関数で処理する意味はある?

更新: 2008年10月29日

PHPでのセキュリティ対策についてのメモ (note.openvista.jp)」。なかなか良くまとまっていると思いますが、CSRFの話で少し気になった点が。

第三者が知り得ない文字列(ユーザIDやワンタイムトークンなど)をハッシュ関数(md5関数やsha1関数)を複数回用いて擬似乱数化した文字列をフォームに埋め込んでおき、サーバ側で照合することで、リクエストが利用者の意図した動作かどうかをチェックする

以上、PHPでのセキュリティ対策についてのメモ クロスサイトリクエストフォージェリ(略称:CSRF) より

※強調は引用者による。原文では<span class="weaken">でマーク付けされている

※2008-10-29追記: 引用した部分は既に修正されています。

「疑似乱数化」ってなんでしょう……。「疑似乱数」は良く聞きますが、「疑似乱数化」は耳慣れない言葉です。複数のハッシュ関数で処理することをそう呼ばれているようなのですが、ハッシュ関数を何度通しても得られる結果は常に一定なはずですから、乱数とはあまり関係ないように思います。

それから、ユーザIDをハッシュ関数に通してそれをトークンとして使うという手法は、CSRF対策としては不適切です。ハッシュ関数を通すと、「生成後の値から元の値を推測することが困難になる」という効果が得られます。しかし、ここで推測されて困るのは元の値 (ユーザID) ではなく、生成後の値のほうです。ユーザIDとハッシュアルゴリズムがわかれば攻撃者もトークンを作れてしまいますから、CSRFの対策としては問題があります。

※あるいは、オリジナルのハッシュアルゴリズムを採用して、そのアルゴリズム自体を秘匿するとか? :-)

ワンタイムトークンを使うのであれば、それ自体はCSRFの対策になります。が、トークンが安全に作られていればハッシュ関数を使用する必要はありません。逆に、トークンの生成アルゴリズムに問題があれば、ハッシュ関数を通しても安全にはなりません。ハッシュ関数を使う必要はないと思います。

なお、類似するケースとして、「セッションIDをハッシュ関数で処理してトークンとして利用する」という処理があります。これは実際、よく見かける実装です。ただ、この場合は「トークンを推測されないように」という理由でハッシュ関数を使っているのではなく、「たとえトークンが漏洩してもセッションIDを推測されないように」という理由でハッシュ関数を使っています。つまり、ここでのハッシュ関数による処理はセッションID漏洩への対策であって、CSRFへの対策ではないのです。

※もっとも、「トークンだけ漏れてセッションCookieが漏れない」という状況も考えにくいように思うので、このハッシュ関数も必須ではないように思います。気分的な問題で採用されているというのが近いかも。まあ、やっても害はないので問題ありませんが。

というわけで、「第三者が知り得ない文字列」というところまではよいと思うのですが、その生成方法として「ハッシュ関数を」というのは問題があるように思います。基本的には、安全な疑似乱数を使用して生成する、というのがセオリーでしょう。

とは言っても、とにかく疑似乱数を使えば良いというわけではありません。疑似乱数にもいろいろありますが、線形合同法やメルセンヌ・ツイスタなどのアルゴリズムでは、値を観測することで次に生成される値が予測されてしまう事があります。

……ただ、PHPだと、標準では安全な乱数が使えないかも……。

※通常はセッションIDが安全な疑似乱数によって生成されているので、それをそのまま使うことでもCSRF対策になります。これをそのまま使うのではなく、ハッシュ関数で処理してから使うというのが前述の方法ですね。

※あと、どうでも良いのですが「セキュリティ対策」という言葉自体に違和感があります。セキュリティに対抗してそれを破るという話ではなく、セキュリティを高めるための話をしていますので……。まあ、意味はわかるので問題はありませんが、どちらかというと「セキュリティ施策」とか言った方が良いのかも。

関連する話題: Web / セキュリティ

最近の日記

関わった本など