- 検索エンジンからいらした方は、上の検索欄で検索すると、なにか見つかるかもしれません。
2006-03-30
■[技術] はてなはパスワードを生データで管理してる?

WSSE認証は「安全」かつ「手軽に導入できる」認証として、当初Atom APIで採用されていました。Perl CGIしか動かせないようなホスティングサービスでも使えることが大切で、HTTPSが必須とかでは目的に合わないと考えられていたようです。
以下の記事では、冒頭で4つの選択肢が検討されています。
- HTTP Basic認証を使う。Basic認証は、簡単に元のパスワードにデコードできてしまう。平文を直接送るのと変わらないので却下。
- パスワードをMD5ハッシュしてハッシュだけを送信。盗聴者が平文のパスワードを入手することは不可能。しかし、リプレイ攻撃に耐えられない。Bobのハッシュが通信中に盗まれるとBobに成りすますことができてしまう。
- SSLでHTTP Basic認証を使う。これならパスワード盗聴の問題は解決できる。しかし、Bobのブログは、安いホスティングサービスで動いていて、SSLなんか使えない。
- HTTP Digest認証を使う。これもパスワード盗聴の問題を解決でき、リプレイ攻撃の問題も解決できる。しかし、Bobのホスティングサービスは.htaccessを編集する権限を与えていない。ApacheがDigest認証に必要なヘッダーを剥ぎ取ってしまうので、CGIが自前でDigest認証を実装することも出来ない。
まあ2年以上前の記事なので、実情にどのくらい合ってるのかわかりませんが……。ただMTはローエンドの環境で動作することを非常に重視していて、それが成功の一因になっていた印象はあります。
さて、今の話。Atom Publishing Protocolの仕様では、WSSEへの言及は全て取り除かれています。
draft-ietf-atompub-protocol-01 - (...) Elided all mentions of WSSE.
代わりに、
Atom Protocol servers and clients MUST support one of the following authentication mechanisms, and SHOULD support both.
o HTTP Digest Authentication [RFC2617]
o CGI Authentication
Digest認証か、CGI認証のどちらか、あるいは両方をサポートすることになっています。
CGI認証というのは、CGIで実装できる認証という程度の意味でしかないみたいです(13.1)。WSSEはこれに含まれるのでしょう。
HTTP Digest認証の仕組みは(よく知らなかったので調べたら)、
PasswordDigest = MD5( MD5( Password ) + Nonce )
だそうです。(追記) 上のはだいたいのフィーリングです。というか正直に言うと間違いです。すみません……。sheepmanさんのコメントを参照してください。
Nonceはサーバから送られてきたランダムな(あるいは改変されていないことをサーバ側で確認可能な何らかの)文字列。
WSSEと基本は一緒ですが*1、Digest認証の場合、サーバにパスワードを平文で保存する必要がないんですね。MD5(Password)を持っとけばOK。
というわけで、はてなのAtom APIはHTTP Digest認証に移行するのがいいのかもしれません。でも、クライアントのサポート状況との兼ね合いもあって、難しかったりするのかも*2。(追記) id:sshiさんのコメントと、下の続きをご覧下さい。
ちなみに、Bloggerは、去年の早い段階でWSSEを捨てて、HTTPS + Basic認証に移行しています。これはでも今のAtom PPに合わなくなった感じですねー。
- 117 http://satoshi.blogs.com/life/2008/04/wsse.html
- 104 http://q.hatena.ne.jp/1175745744
- 84 http://b.hatena.ne.jp/entrylist?sort=hot
- 78 http://www.machu.jp/diary/20070723.html
- 49 http://satoshi.blogs.com/life/
- 48 http://sheepman.sakura.ne.jp/diary/
- 46 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rls=RNWE,RNWE:2005-39,RNWE:ja&q=株式会社ニューコンセプト
- 37 http://satoshi.blogs.com/
- 25 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&q=ハッシュ 計算 利点&btnG=検索&lr=lang_ja
- 23 http://www.google.co.jp/search?q=パスワード 日記&hl=ja






>PasswordDigest = MD5( MD5( Password ) + Nonce )
>Digest認証の場合、サーバにパスワードを平文で保存する必要がないんですね。MD5(Password)を持っとけばOK。|
(これは少しおかしい気もしますが)そうだとしても、MD5(password)が結局生パスワードと同じことになりますよね。クライアントはMD5(password)だけ持ってれば認証できちゃうわけだし。
(MD5値を使って)ダイジェスト認証するものと、SSL+Basic認証するものを使いわけておけば、MD5値が漏れてもアクセスされるのは前者だけで後者へのアクセスは防げるかもしれませんね。気がついてませんでした。(また適当なこといってるかも)
MD5( usernamre + ’:’ + realm + ’:’ passwd )
なので、このハッシュが盗まれても、サーバの realm が同じでない限り、
このハッシュを使って認証できるということはありません。
そして、RFC 2617 では Digest 認証の realm にはサーバのホスト名を
入れておくべきだと書かれています。なので、サーバ上に保存されているハッシュ値を盗まれても、他で悪用される危険性はkosekiさんが書かれているよりかは低いと思います。
ハッシュ関数だけでは、盗聴と漏洩の両方からパスワードを守ることはできないのだ、ということで納得したところだったので、どのような領域で「何ら問題ない」のかが、ちょっと気になりました。
「暗号技術大全」はぜひ拝読したいです。とずっと思っています……怠惰ですみません……。
最初はHash(password + salt) = hashedpassとしてDBに記録します。毎回の認証時にはHash(hashedpass + challenge)とすれば、まいかい違う情報を要求することができそうですよ。クライアントにはsaltとchallengeを提示すればよいのです。
これによってウェブサイト毎に異なり、また毎回の要求ごとに異なる認証文字列をつかうことができます。これにより傍受とDB漏洩の両者からパスワードが守られます。
すると、上でsshiさんが指摘されている通り、hashedpassがその認証における生のパスワードになってしまいます。hashedpassが漏れるとchallengedに対して正しい答えを返すことができてしまう。
Basic認証のハッシュ関数の使い方には (1) 元のpasswordがバレない (2) 認証も通らない、という2つの利点があって、Digest認証では(1)しか満たせないということだと思います。
sheepmanさんは、Digest認証でDBに記録したハッシュは、(漏洩させたサービスの認証に使えても)他のサービスの認証には使えない、ということを指摘されているのだと思います。
ともあれ体系を二つにすれば解決できそうです。上のDigest認証とは別に、0. hash(password,salt1) = hashed1, hash(hashed1,salt2) = hashed2という計算をして、DBにはhashed2, salt1, salt2だけを記録しておき、1.ユーザにまずsalt1を提示し、2.ユーザがhash(password + salt1)を計算し、hashed1をサーバに送る、3.システムはhash(それ + salt2)を計算し、DBのhashed2と照合する。
こうしておけばpasswordないしhashed1は、hashed2からは簡単に計算できないので、真のパスワードを知っている人しかhashed1を提示することができなくなりそうです。どうですか?
ここまでやるなら素直に公開鍵やSSLをつかっちゃったほうがいいような気がしますけど。
http://d.hatena.ne.jp/koseki/20060403#hash