

ログインシステムについて質問があります。  
パスワードを暗号化ではなくハッシュ関数を使い符号化する安全性と使い方はわかりました。  
またそれに文字を足して何回か行う、ということもわかりました。(ソルトとストレッチングのことです)  
そこで質問があります。

  1. SHA256を使おうと思っているのですが、ハッシュ化という行為は元に戻せないということでした。いずれ新しいタイプのハッシュを使おうと思った際に、どのようにシステムを移行させればよいのでしょうか。あるいはどのようにSHA1などからの移行を果たしましたか?

  2. もちろんSSL通信化での送信になりますが、パスワードを送信する際は符号化して送信するべきだと思うのです。しかし符号化すると元へは戻せません。この場合サーバーと同じ処理をjsで書いてしまうとロジックの公開になり安全性が保てないような気がしています。そこで公開鍵と秘密鍵を使ったもので暗号化しようと思い立ちましたが、あまりにコストが高い気がしています。皆さんはこのようなところはどのように解決なされているのでしょうか。

以上二点、宜しくお願いします。


CC BY-SA 3.0
2016-02-02T15:28:46.317
21636
2016-02-04T10:45:51.557
2016-02-03T17:02:27.550
3061
14246
question
アルゴリズム security
ログインシステムのためのパスワードのハッシュ方式、互換性、照合方法について


ユーザー認証の問題と、通信経路の安全性の問題は分けて考えた方がいいでしょう。

まず、SSLが通信経路の安全性に関する技術で、この中に、共通鍵や公開鍵を使った暗号化の技術が含まれています。通常、自前で実装するようなものではなく、単に、サーバー側との通信でHTTPSを使うという選択なりをすればいい話です。

ユーザー認証でハッシュを使うのは、サーバーにパスワードをデータとして残さないためです。サーバーの管理者（Administrator）はサーバー上の全てのファイルにアクセスすることができます。もし、パスワードをデータとして保存して、それをユーザーからの入力されたパスワードと照合するという、単純な方式であれば、管理者によってパスワードが簡単に盗まれます。また、管理者を信用するとしても、今度は、root
権限が侵入者によって奪われてしまった場合、パスワードがそのまま即、侵入者に盗まれてしまいます。

例えるならば、家の中に、現金を、そのまま机の上に置いているような状態です。

ハッシュの形でサーバーに置いておけば、パスワードを逆類推することは不可能なので、照合用のハッシュを格納したファイルに対するアクセスが、即、パスワードを盗まれたことを意味しません。

こちらの場合、家の中に、預金通帳やキャッシュカードを置いているような状態です。泥棒が家の中に侵入してそれらを盗んだとしても、即、銀行口座から預金が盗まれたことは意味しません。


CC BY-SA 3.0
2016-02-02T16:58:36.087
21640
2016-02-02T16:58:36.087
7290
21636
answer


## ハッシュアルゴリズムを切り替える方法

  1. DBのユーザー情報を保存しているテーブルにハッシュアルゴリズムを保存するカラムを追加します。すべてのユーザーに旧アルゴリズムを表す値を入れておくか、NULであれば旧アルゴリズムと見なす、とします。
  2. ユーザー認証時は、このカラムの値を見てアルゴリズムを選択します。
  3. パスワード変更時は新アルゴリズムを用いてハッシュ値を計算し、ハッシュ値をDBに保存するのと同時にアルゴリズム示す値も更新します。
  4. ハッシュアルゴリズムの更新を強制したい場合は、「旧アルゴリズムになっているユーザーはログイン後パスワードを強制する」という動作にすればよいでしょう。

このユーザー毎にハッシュアルゴリズムを記録しておく、というのは古くから行われているオーソドックスな方法です。

## パスワードを送信する方法

一般的な用途ではSSLで経路が暗号化されているのであれば、その区間は安全と見なしてかまいません。これが信頼できないなら通信のすべてを別途暗号化する必要があります。

認証強度を高めるのが目的であれば、二要素認証のようなパスワード認証を補強する方法や、ワンタイムパスワード、ユーザー証明書による認証など別の方法を検討するほうが理にかなっています。

> サーバーと同じ処理をjsで書いてしまうとロジックの公開になり安全性が保てない

これは2つの点で間違っています。まず、ロジックの公開はセキュリティ上の懸念にはなりません。ロジック、ハッシュ値、salt、ストレッチ回数のすべてが漏洩したとしても、元のパスワードを求めることは非常に困難です。それこそがパスワードをハッシュ値で保存する目的だからです。

安全性が保てないという点は間違いではありませんが理由が間違っています。クライアント側でハッシュ値を計算して送付するのは、盗聴対策であれば全く意味がありません。第三者がハッシュ値を入手した場合、そのハッシュ値を用いて認証できてしまうからです。

どうしても生のパスワードをネットワーク上に送出したくない場合は、暗号化や[fumiyasさんの回答](https://ja.stackoverflow.com/a/21681/5793)で紹介されているようなチャレンジレスポンス認証のような仕組みの検討が必要です。そこまでのセキュリティレベルが要求されるシステムなのであれば、専門家にコンサルティングしてもらうことをお勧めします。

* * *

SHA2を用いたパスワードの保存に計算量上の弱点があり、思ったよりもかなり多い数のstretchingが必要なのは事実です。大量の計算資源を用いたブルートフォースアタックに対する高度な耐性が求められるのであれば、別のアルゴリズムの検討が必要かも知れません。

一方、SHA2には選定段階にも実運用に入ってからも微に入り細を穿つ研究が行われた上で致命的な欠陥は見つけられていない非常に信頼性の高いアルゴリズムです。

新しいアルゴリズムは古いものを研究した上で作られるので優れた点は多々ありますが、(特にセキュリティ分野では)古いからこその信頼性が存在するのも事実です。アルゴリズムそのものに問題は無くても実装に問題があると言う場合もあります。

どういうアルゴリズムを選択すべきかはこういった点も考慮して検討してください。


CC BY-SA 3.0
2016-02-02T23:09:30.433
21644
2016-02-04T10:45:51.557
2017-04-13T12:52:39.113
-1
5793
21636
answer


(suzukisさんの回答への補足です)

**パスワードハッシュにSHA256などのメッセージダイジェストハッシュを使うことは推奨されません。**
パスワードハッシュ用のアルゴリズムが開発されているので、それを使いましょう。

## まずは結論から

現時点でベストとされているのは[Argon2](https://github.com/p-h-c/phc-winner-
argon2)です。[パスワードハッシュアルゴリズムの優劣を競うコンペ](https://password-
hashing.net/)で2015年に最良と判断されました。ただ、比較的新しいので、もしお使いのシステムでライブラリやバインディングがすぐに使えない事情がある場合、とりあえずの代替としてはbcrypt,
scryptもしくはPBKDF2というアルゴリズムもあります。これらは出てしばらく経つので様々なシステムや言語処理系で使えるはずです。

なお、Argon2やbcryptではハッシュ値の文字列表現の先頭に、アルゴリズムやパラメータを区別するプレフィクスがつくようになっているので、システム移行時にアルゴリズムを切り替えたいという場合にも、新旧のアルゴリズムによるハッシュ値を混在させることができます。アルゴリズムを記録しておくカラムをDBに別に持つ必要はありません。

## やや詳しい説明

パスワードハッシュもメッセージダイジェストハッシュも一方向関数という原理は同じなのですが、使われる目的の違いにより、実装の方針が変わってきます。

メッセージダイジェストハッシュは例えば通信路上のメッセージを全て処理するなど入力が大きいので、大量のデータを効率良く処理するために比較的高速に計算できるようになっています。一方、この目的でのハッシュ関数で重視されるのは、ターゲットとなる特定のハッシュ値と同じハッシュ値を持つ意味のあるデータを作成するのを難しくすることです。MD5やSHA1はその目的では既に弱くなってしまいましたが、SHA2はまだ現時点で大丈夫とされています。

それに対し、パスワードハッシュは(1)入力が短く、しかも通常1セッションに対し1回だけ計算すれば良い(2)攻撃者は大量のハッシュ値の「どれか」に一致するものを見つけさえすれば良い(3)しかも攻撃者は比較対象のハッシュ値をあらかじめ(DBを盗み出す前に)オフラインで計算しておける、という全く異なる性質があります。そのため、メッセージダイジェストハッシュとは逆に、
**わざと計算負荷を高くする**
ことが重視されます。一回のログインでハッシュ値の計算が50ms伸びてもユーザは気になりませんが、大量のパスワードハッシュを事前に計算したい攻撃者にとっては一個一個のハッシュ値の計算が重くなることは大きな足枷になるからです。

この計算負荷も固定ではコンピュータの進歩によりどんどん追いつかれるので、適宜調整可能になっています。後でパスワードからハッシュ値を再計算するためには、ハッシュ値を計算した時に使った負荷パラメータが必要です。

最近はGPUで大量に並列計算ができるようになったため、単に時間的に計算負荷を増やすだけでは不十分になってきました。Argon2では計算に必要なメモリ量を増やす方向での強化もなされています。


CC BY-SA 3.0
2016-02-03T11:18:16.247
21667
2016-02-03T23:39:46.623
2016-02-03T23:39:46.623
5258
5258
21636
answer


質問 2 が、通信路が SSL かどうかに依らず生パスワードを受け渡したくないということであれば、SCRAM がよいと思います。

  * RFC 5802 - Salted Challenge Response Authentication Mechanism (SCRAM) SASL and GSS-API Mechanisms 
    * <https://www.rfc-editor.org/rfc/rfc5802>


CC BY-SA 3.0
2016-02-03T16:14:31.380
21681
2016-02-03T16:14:31.380
2021-10-07T07:34:52.683
-1
3061
21636
answer