Passport.js digest-strategy で パスワードを安全に管理する
泣きながらDigest認証を行うnode.jsサーバを構築していて詰まったところがあったのでメモ。
passport.jsのdigest認証は、request時に受け付けたユーザIDを引数にして関数を組み、 DBなりと照合して最後のコールバックでパスワードをDigest Strategyコンストラクターに返す必要があるんだけれども、 コールバックで受け付けるパスワードがみた感じ平文でしか受け付けない。
passport.use(new DigestStrategy({ qop: 'auth' },
function(username, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user, user.password); //Wow, we must use plaintext...
});
},
function(params, done) {
// validate nonces as necessary
done(null, true)
}
));
は?これくそすぎないっすか・・・
ソースコード書き換えるしかないかと思って元のコード読んでたら、こんな事が書いてあった。
this._secret(creds.username, function(err, user, password) {
if (err) { return self.error(err); }
if (!user) { return self.fail(self._challenge()); }
var ha1;
if (!creds.algorithm || creds.algorithm === 'MD5') {
if (typeof password === 'object' && password.ha1) {
ha1 = password.ha1;
} else {
ha1 = md5(creds.username + ":" + creds.realm + ":" + password);
}
}else
137行目の部分、コールバックで返す際に ha1 というデータを持つObjectを返すと、 すでに{ユーザ名}:{realm}:{パスワード} をMD5ハッシュ化したものとして扱ってくれるみたいだ。 逆に単純なString形式の値を渡された場合、そのStringを使ってha1を作り出している。
(Digest認証で生成するハッシュのうちの一つですね)
料理できていればそのまま出すし、材料だけ渡されたら足りない部分を使って料理する感じ。 exampleにも書いておいて欲しかった・・・
ということで、 あらかじめデータベースには 上記のようなMD5ハッシュ値を保管しておき、Digest認証時に
let md5HashedString = "a867af741df2e7004b62c10f38063db8"; //hash of "hoge:Users:hoge"; foo.ha1 = md5HashedString; return done(null, userId, foo.ha1); //callback to digestStrategy constructor.
で返してあげれば良さそうだ。
/以上