WSSEのセキュリティリスクとその対処法に関する一考察
2008.04.03
引き続きiPhone SDKで遊んでいる私だが、Typepadやはてなが採用しているAtomを使ったiPhoneアプリを作ってみようとしたところで、WSSE認証の仕組みを(Objective-Cで)ゼロから作らなければならないことに気づき挫折しかける。SHA1のライブラリまで自前で用意しなければならないのはちょっと荷が重かったのだが、増井さん(masuidrive)からRFC中のコード(参照)が使えることを教えていただき、それを元に実装(持つべきものは友だ^^)。
細かな間違いをいくつもしていた上に、WSSEの仕様を少し勘違いして始めたためになかなか動かず、はてなからステータスコード200がもらえたのは夜の10時過ぎ。半日ぐらいで軽く作れると思っていたのに、結局丸一日かかってしまったが、「WSSEとは何ぞや」を何も知らないところから始めたのだから良しとしよう。
しかし、WSSEの仕様に関して少し心配なのは、生のpasswordテキストをcreationDateとNonceをくっつけてからハッシュを作ってからサーバーに送るという部分。認証のためにはサーバー側で全く同じ計算をしなければならないのだが、そのためにはデータベースに生のpasswordをしまっておかなければならないことを意味する。これはセキュリティ上大きな問題があるように思える(参照)。
私の知る限り、複数のアカウント間で同じパスワードを使っている人は多い(これはこれで大きな問題だが、そんなユーザーたちを非難するのではなく、ちゃんと守ってあげるのがジェダイ・ナイトのおもてなし)。そんな人たちのパスワードを「万が一のデータ漏れ」から守るには、パスワードをそのままデータベースにしまうのではなく、SHA1などの一方向関数を使ってハッシュ化してからデータベースに格納しておくべき。そうすれば、なんらかの理由(ハックされる、マシンが盗まれる、社員が暴走するなど)で「データ漏れ」が起こってしまった場合にも、被害をそのサービス内だけにとどめることができる。
という意味では、元々のWSSEのスペックを少し拡張し、passwordをサーバーに送る際には、サービス独自のハッシュをかけたもの(hashedPassword)をcreationDateとNonceとくっつけてからさらにハッシュをかけてからサーバーに送り、サーバー側では生のpasswordではなく、hashedPasswordををデータベースにしまっておき、それを利用して認証するようにすれば良いと思うんだがどうだろう。
もう少し分かりやすく言うと、
base64(SHA1(password + creationDate + Nonce))
を送るのではなく、
base64(SHA1(SHA1(password+"hatena") + creationDate + Nonce))
を送り、サーバー側ではデータベースにしまっておいたhashedPasswordを使って、
base64(SHA1(hashedPassword + creationDate + Nonce))
を計算して比較することにすれば良いというのが私の提案である。
WSSEの存在を知ったばかりの私が言うので、何か大きな勘違いをしているかも知れないが、こうやって文章にして公開することにより、より理解を深めようと言ういつもの作戦だ。
それにしても、暗号の話はこんなふうに一筋縄で行かないところがとても面白い。全体としてどんな技術が何のために作られているかを理解するにはサイモン・シンの暗号解読がおすすめだ。