Djangoのパスワードリセットでtokenの一致確認に使われるconstant_time_compare

こんな関数なんですが、なんで文字列の==でなく、わざわざこんなことしてるんでしょうか?
djangoの1.3の頃は普通に比較してたと思うんですが。


django.utils.crypto.py

def constant_time_compare(val1, val2):
    """
    Returns True if the two strings are equal, False otherwise.

    The time taken is independent of the number of characters that match.
    """
    if len(val1) != len(val2):
        return False
    result = 0
    if six.PY3 and isinstance(val1, bytes) and isinstance(val2, bytes):
        for x, y in zip(val1, val2):
            result |= x ^ y
    else:
        for x, y in zip(val1, val2):
            result |= ord(x) ^ ord(y)
    return result == 0


コメントによると

The time taken is independent of the number of characters that match

一致する文字数が少なかったり多かったりしてもかかる時間は同じですよってことですね。

ということはタイミング攻撃を意識しているもののようです。

関数の実行にかかった時間から、文字列がどの程度一致していたのか推測できてしまうと、いずれは完全に一致するtokenを作成されてしまう、というわけですね。

自前で似たようなtokenの一致を実装するような機会があったら使っといたほうがよさそう。


参考 : サイドチャネル攻撃 - Wikipedia
参考 : Purpose of constant_time_compare? - Google グループ