Erlang で作りたい Web アプリがあって、認証について色々仕様を詰めてた(「特権ユーザにのみ特定の操作を許可したいな」、「アカウント情報の盗聴やリプレイ攻撃は防ぎたいな」、「でも非 SSL 通信を想定したいな」)ところ、「それ Digest 認証でできるよ」という声が頭のなかで聞こえたので Yaws に実装されてたりしないかなーと探してみたらなかった! Basic 認証しかなかった! ので実装してみました! という話です。
差分は以下に示す通りな感じです。 Erlang はほとんどはじめてみたいなレベルなので、なんというか、それっぽくないコードな感じがしますがご容赦ください。アドバイス超大歓迎です!
https://github.com/ebihara/yaws/compare/master...auth-digest
RFC 2617 で定義される最小限の Digest 認証 ( qop は auth 固定) は実装できたかなというところです。手元の curl と Firefox と Google Chrome で一通り動作確認はしています。よろしければお使いください。
Digest 認証は立ち位置的に中途半端な感があって、そのせいか Nginx では使えないし、今回の実装で主に参考にした Apache でさえ未実装部分がチラホラあるという有様で、ちょっと残念ですね。かなり頑張ってるプロトコルだと思うのですが……。
これからの予定
せっかく作ったので本体側に取り込んでもらいたいと思うわけですが、もうちょっと色々やらなきゃいかんです。
- もろもろチェックが雑なところがある [1] のを RFC に従って直す
- crypto:strong_rand_bytes() が low_entropy 例外を throw した場合に生成する nonce がひどいのでもうちょっとマシにする
- というかそもそも、元々の yaws_session_server の生成するセッション ID が最悪 (ただの int [2] なうえに、エントロピーは PRNG (not CSPRNG) の生成結果だけ [3] ) なので、今回作った nonce の生成ロジック [4] を使うように置き換えて、セッション ID 周りだけ先に pull request するかな
- Apache は毎回サーバ側の nonce-count を加算するようなのだけど、俺の現状の実装は Authorization ヘッダの検証過程でのみ nonce-count を更新していて、サーバ側の nonce-count が実際よりも小さい値になることがあり得るので、単にクライアントがサーバ側の nonce-count より大きい値を送って来ているかどうかを確認している。これで問題ない [5] と思うのだが改めて見直す必要がある
- Basic 認証の設定と同様、 Digest 認証のユーザとパスワードの組は平文で設定ファイルに書かれる。これを改善するべきか否か。海老原個人の用途では別にこれはどうでもいいのだけど
[1] | たとえば Authorization ヘッダの uri の値がリクエストラインのものと一致しているかどうかの確認とかやってない。 |
[2] | ブルートフォース攻撃に脆弱。 |
[3] | 予測可能性がある。 |
[4] | 最良ケースでは OpenSSL の RAND_bytes() を使う。最悪ケースが前述の通りひどいので改善する必要がある。あとは本当にポータブルなコードかどうかを確認しなければ…… |
[5] | この nonce-count はリプレイ攻撃対策であり、過去に同じ nonce-count を用いたリクエストと同じリクエストが許可されるようなことがない実装になっていれば要件を満たす。 |