Node.jsのBufferの比較
値が同じだが異なるオブジェクトのBufferの比較をする際、==
を使ったらfalse
になった。
ハッシュ化したパスワードの比較をしたかったので、crypto.timingSafeEqual
を使ったところ、想定通り、同値の場合はtrue
を返すようになった。
BufferにはBuffer#compare
というメソッドもある。Bufferの配列をソートしたいときにはこちらを使うと良いらしい。
Passport.jsのLocalStrategyで利用者名と暗証語を認証するコード
passport.use(new LocalStrategy(function verify(username, password, cb) {
db.get('SELECT rowid AS id, * FROM users WHERE username = ?', [ username ], function(err, row) {
if (err) { return cb(err); }
if (!row) { return cb(null, false, { message: 'Incorrect username or password.' }); }
crypto.pbkdf2(password, row.salt, 310000, 32, 'sha256', function(err, hashedPassword) {
if (err) { return cb(err); }
if (!crypto.timingSafeEqual(row.hashed_password, hashedPassword)) {
return cb(null, false, { message: 'Incorrect username or password.' });
}
return cb(null, row);
});
});
}));
『Username & Password Tutorial: Verify Password』より
何をしているコードか
- dbから与えられた利用者名と一致する利用者情報(利用者名, ハッシュ化された暗証語)を取り出す。
- 与えられた暗証語を
crypto.pbkdf2
でsha256にハッシュ化する。 crypto.timingSafeEqual
で1.と2.で得られたハッシュ化された暗証語を比較し、一致していれば利用者情報をcallback関数(cb)で返す
crypto.timingSafeEqualの概要
This function is based on a constant-time algorithm. Returns true if
a
is equal tob
, without leaking timing information that would allow an attacker to guess one of the values. This is suitable for comparing HMAC digests or secret values like authentication cookies or capability urls.
a
andb
must both beBuffer
s,TypedArray
s, orDataView
s, and they must have the same byte length. An error is thrown ifa
andb
have different byte lengths.If at least one of
a
andb
is aTypedArray
with more than one byte per entry, such asUint16Array
, the result will be computed using the platform byte order.Use of
crypto.timingSafeEqual
does not guarantee that the surrounding code is timing-safe. Care should be taken to ensure that the surrounding code does not introduce timing vulnerabilities.
DeepL訳
この関数は、定数時間アルゴリズムに基づいている。攻撃者がどちらかの値を推測できるようなタイミング情報を漏らすことなく、 a
と b
が等しい場合に true を返します。これは、HMACダイジェストや、認証クッキーやケイパビリティURLのような秘密の値を比較するのに適しています。
a
と b
は両方とも Buffer
s, TypedArray
s, または DataView
s でなければならず、同じバイト長でなければなりません。a
と b
が異なるバイト長を持つ場合はエラーがスローされます。
a
と b
の少なくとも一方が Uint16Array
のようなエントリごとに複数のバイトを持つ TypedArray
である場合、結果はプラットフォームのバイトオーダーを使用して計算されます。
crypto.timingSafeEqual
を使用することは、周囲のコードがタイミングセーフであることを保証するものではありません。周囲のコードがタイミングに関する脆弱性をもたらさないように注意する必要がある。