お首が長いのよお首が長いのよ

チラシの裏よりお届けするソフトウェアエンジニアとして成長したい人のためのブログ

2018-05-17

Passport.js digest-strategy で パスワードを安全に管理する

泣きながらDigest認証を行うnode.jsサーバを構築していて詰まったところがあったのでメモ。

passport.jsのdigest認証は、request時に受け付けたユーザIDを引数にして関数を組み、 DBなりと照合して最後のコールバックでパスワードをDigest Strategyコンストラクターに返す必要があるんだけれども、 コールバックで受け付けるパスワードがみた感じ平文でしか受け付けない。

javascript
1passport.use(new DigestStrategy({ qop: 'auth' },
2  function(username, done) {
3    User.findOne({ username: username }, function (err, user) {
4      if (err) { return done(err); }
5      if (!user) { return done(null, false); }
6      return done(null, user, user.password);   //Wow, we must use plaintext...
7    });
8  },
9  function(params, done) {
10    // validate nonces as necessary
11    done(null, true)
12  }
13));
14

は?これくそすぎないっすか・・・

ソースコード書き換えるしかないかと思って元のコード読んでたら、こんな事が書いてあった。

javascript
1this._secret(creds.username, function(err, user, password) {
2    if (err) { return self.error(err); }
3    if (!user) { return self.fail(self._challenge()); }
4
5    var ha1;
6    if (!creds.algorithm || creds.algorithm === 'MD5') {
7      if (typeof password === 'object' && password.ha1) {
8        ha1 = password.ha1;
9      } else  {
10        ha1 = md5(creds.username + ":" + creds.realm + ":" + password);
11      }
12    }else
13

137行目の部分、コールバックで返す際に ha1 というデータを持つObjectを返すと、 すでに{ユーザ名}:{realm}:{パスワード} をMD5ハッシュ化したものとして扱ってくれるみたいだ。 逆に単純なString形式の値を渡された場合、そのStringを使ってha1を作り出している。

(Digest認証で生成するハッシュのうちの一つですね)

料理できていればそのまま出すし、材料だけ渡されたら足りない部分を使って料理する感じ。 exampleにも書いておいて欲しかった・・・

ということで、 あらかじめデータベースには  上記のようなMD5ハッシュ値を保管しておき、Digest認証時に

javascript
1    let md5HashedString = "a867af741df2e7004b62c10f38063db8";  //hash of "hoge:Users:hoge"; foo.ha1 = md5HashedString; return done(null, userId, foo.ha1); //callback to digestStrategy constructor.
2

で返してあげれば良さそうだ。

/以上

よかったらシェアしてください!