SSLを利用したWebサービスでログインパスワードを安全に保存するには?

受付中

回答 9

投稿 編集

  • 評価
  • クリップ 12
  • VIEW 4,155

hojo

score 189

安全なパスワードの保存を行う為に暗号化はどこで行うべきですか?(旧タイトル)

Webサービスで安全なパスワードの保存を行いたいとします。

パスワードをSHA256などによって暗号化することはよくある話だと思います。しかし、このSHA256を利用して暗号化する場合、暗号化はサーバサイドで行うべきか、クライアントサイドで行うべきか悩んでいます。

サーバサイドで暗号化を行う場合、入力されたパスワードが暗号化されないままサーバに届くことになります。(SSLの話ではありません)

その後、アプリケーションサーバの手によってデータベースにパスワードを保存する際にはSHA256によるパスワード暗号化を行った上で保存することになるわけですが、アプリケーションサーバにはパスワードがそのままの形で届いてしまっていることに変わりありません。

我々が利用しているアプリケーションサーバはセキュリティ的に問題無いから大丈夫だ!とサービス運営者が主張したところで、サーバの権限を奪われる可能性はゼロではありませんし、それ以前にアプリケーションサーバの運営者はパスワードが直接届くような環境でアプリケーションを日々保守していたりするわけです。

また、アプリケーションサーバがGETやPOSTに対するログを取るように設定されていた場合、送信されたパスワードは暗号化されることなくログファイルに記載されることになります。

つまり、サーバサイドでSHA256によるパスワード暗号化を行う仕様の場合、暗号化されないままアプリケーションサーバに届くパスワードを運営は安全に管理してくれるだろうと信用する形でサービスを利用することになります。

これはなんかダメなんじゃないかなっていう気がするんです。

これを回避するためJavascriptなどを利用してクライアントサイドでパスワードを暗号化してからアプリケーションサーバに暗号化されたパスワードを送る方法をとれば、このような心配事は無くなります。

しかしその場合、SHA256で使用するSaltキーなどはどのように設定すれば良いのでしょうか?そのままjavascriptのソースファイルに暗号化キーであるSaltキーを記述してしまって良いのでしょうか?

なんとなくSaltキーの情報が漏れていることはあまり良くないことのような気がしています。しかし、SHA256は復号化が不可能な暗号化なので、一度暗号化されてしまったものを復号化することは不可能だと思います(そうですよね?)

だから安全だと言い切れるのでしょうか?
何か嫌な感じがします。

どうにかSaltキーの情報を隠蔽したいと思っていますが、クライアントサイドで暗号化を行う以上、隠蔽することは不可能なのではないかと思っています。本当にこのSalt隠蔽問題は気にしなくても良いことなのでしょうか?

何か考え方がおかしいのかもしれませんが、こんな私に何かアドバイスいただけたらと思います。

追記(2016/09/26 18:30)

質問がダラダラとした文章になり、分かりにくいようですので質問を変えさせていただきます。

SSLによる暗号化通信を前提としたWebサービスで入力フォームなどによってユーザが入力するパスワード文字列をサーバサイドで暗号化する場合、そのパスワードの安全性が保障されません。

なぜなら運営がパスワードを安全な形で管理しているかわからないし、暗号化していたとしても暗号化する前のパスワードをアクセスログに残している可能性なども考えられるためどこからパスワード文字列が漏れるかわからないからです。

しかし、クライアントサイドでパスワードを暗号化した場合は、アプリケーションサーバにパスワードが届いた地点ですでに暗号化されているため、パスワードの文字列が漏洩する心配は無くなります。

漏れたとしても暗号化後のハッシュ文字列だから元のパスワードが漏れるより安心できると考えられます。

そのため、クライアントサイドでSHA256によるパスワード暗号化を行った上でサーバサイドにパスワードを送る方法をとったほうがユーザにパスワードの安全性を保証することができるのではないですか?

この考え方は正しいですか?

またクライアントサイドでSHA256によるパスワード暗号化を行った場合、ハッシュを生成するために必要なSaltキーが必要になりますが、Saltキー隠蔽することは可能ですか?不可能な場合、Saltキーが漏洩していることでどのような問題が起こりますか?

追記(2016/10/01 18:06)

ここまでの流れとして、質問者(私)が認識したことをまとめてみます。

  • SSL/TLSを利用したhttpsプロトコルの利用は必須
  • SHA256は暗号化ではなく、ハッシュ生成のアルゴリズム(関数)である。
  • Saltはキーではない
  • 常識的にシステムを構築していればSaltは漏洩は気にしなくて良い
  • サーバサイドでのパスワードのハッシュ化は必須である
  • クライアントサイドで生成したパスワードハッシュをそのままDBに保存してはならない
  • パスワードのハッシュが漏洩した場合、元のパスワードを総当たりで突き止めることができる(オフラインの場合?)
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tanat

    2016/09/26 20:14

    追記部分を読んでの質問です。
    サーバ側の処理を信頼できないとした場合、
    そもそもパスワードが漏れようが漏れまいがクラックされてしまうところまで考えないといけないレベルの話になってしまいます。
    そのため、質問の焦点が
    「パスワード文字列そのものが漏洩するかどうかであり(例えばパスワードの使いまわしをしていて、パスワードの文字列自体が漏れるのが嫌だ)、パスワードを使ってその脆弱なシステムになりすましログインできるかどうかではない」
    であるように解釈したのですが、この解釈は正しいですか?

    キャンセル

  • hojo

    2016/10/01 08:00

    お返事が遅くなってすみません。

    質問の焦点としましては「より安全なパスワードの保存方法を知りたい」です。

    すなわち 「パスワード文字列そのものの漏洩を防ぐ」こととに加え「脆弱なシステムになりすましログインできることも防ぐ」というような、可能な限り安全かつ現実的な方法を求めています。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2016/10/01 08:52

    クライアントサイドで暗号化したパスワードは「複雑化されたパスワード」なだけで送信された「パスワード」をそのまま保存したら「平文のパスワード」と変わらないだろう・・・桁数が多いだけで

    キャンセル

  • hojo

    2016/10/01 08:58

    おっしゃる通りです。そのような回答を幾つか頂いております。

    キャンセル

回答 9

+7

クライアント側: パスワードからハッシュ値生成
クライアント->サーバ通信: ハッシュ値
サーバ側: ハッシュ値
サーバでの判断: 送られたハッシュ値と保存しているハッシュ値を比べる

このような方法を考えていて、これなら、ハッシュ値が漏れても安心だと言いたいのですね(Saltをどうするかは別として)。さて、もし、この方法を使っているシステムでハッシュ値が盗まれた場合、盗んだ人達は簡単に利用者のなりすましができてしまいます。盗めたのはハッシュ値だけで、システムの完全乗っ取りまではできなったとしてもです。クライアント側の処理は何でも可能です。つまり、パスワードからハッシュ値をわざわざ生成しなくても、初めからハッシュ値をサーバに送ればログインできてしまいます。これってPass-the-hashという脆弱性の一種になると思われます。

なお、一般的なサーバにパスワードそのものを送る仕組みの場合は、ハッシュ値が盗まれてもログインは不可能です。なぜなら、サーバ側で必ずハッシュ化処理をしてしまうため、ハッシュ値を送っても無駄だからです。SHA256のような安全な暗号学的ハッシュ関数で暗号学的にランダムに生成されたSalt値を使ってハッシュ化しているかぎり、ハッシュ値だけが盗まれたとしても、そのハッシュ値になるサーバへ送るべきパスワードを調べ上げることはほぼ不可能(現実的じゃない時間が必要)になるため、攻撃者はログインすることはできません。

でも、パスワードをサーバに送りたくない…では、どうするか…。となると、他に取れる手段は公開鍵認証しかないかとかと思います。クライアント証明書認証や、SSHの公開鍵認証で使われている仕組みです。サーバに登録するときに渡すのは公開鍵のみです。盗まれようが何しようが、痛くもかゆくもありません。クライアント側にある秘密鍵はクライアント側から出て行くことはありません。クライアントに保存された秘密鍵をパスフレーズで暗号化していれば、さらに安全です。(公開鍵認証の仕組みについては、長くなるので省きます)

公開鍵認証の一番の難点は、公開鍵を登録するときに、その公開鍵が本人なのかどうかです。これは別の方法で担保する(メールを送る、SMSを送るなど)しかないでしょう。ただ、うまく公開鍵さえ登録できれば、あとは通信を盗み見られようが、登録された公開鍵が漏洩しようが、秘密鍵はクライアントからは出て行きませんので、安全と言えるのでは無いでしょうか。

使い道が限られますが、あるデータを保存・管理するようなシステムであれば、もう一つ手段があります。利用者のデータをクライアント側で暗号化して、サーバ・クライアント間の通信やサーバ上のデータは常に暗号化された状態にし、クライアント側で復号化するという方法です。Passpackというパスワード管理サービスはこの方法を用いていると自称しています(私はそのサービスの利用者ですが、それが本当かどうかまでは知りません。ですので、漏れても良いものしか登録しないようにしています)。この仕組みであれば、サーバ側ではどんなにがんばっても、復号化された状態のデータを見ることはできません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/03 23:09 編集

    ちなみに、raccyさんもおっしゃっていた、SSHの鍵交換方式においては、サーバー側で生成した乱数のハッシュ値と、クライアント側で生成した乱数のハッシュ値の比較が行われており、この辺との比較も面白そうですね。

    私もあと、SSLについても、もっときちんと理解しないといけないです。
    kazさんのブログも、勉強になります。

    キャンセル

  • 2016/10/04 13:11

    みんな話が長い。長文過ぎる。

    シンプルにストレッチング(クライアントで作ったハッシュをサーバでさらにハッシュ化)すれば、とりあえず質問者さんの抱えている心配は消えるでしょう。

    あとraccyさんの「パスワードは使い回さないのが前提なんだから生パスワードが漏れても被害はそのサービスのみに限定される」というご意見は極論&理想論すぎます。実際はパスワードを使い回す人が多いのだから、ユーザに合わせて現実的な対策をすべき。

    キャンセル

  • 2016/10/05 00:53 編集

    > zico_teratailさん

    度々の長文、失礼しました。

    「セキュリティ」は、底なし沼ですからね。

    迂闊に、そこに片足を突っ込んでしまった質問者さんも、簡単には抜け出せないでしょうね。
    私も、素人で迷い込んでしまったんですけどね。

    キャンセル

+3

クライアント側でハッシュ値を求めたとして、サーバー側のデータベースには何を格納するつもりでしょうか?クライアントから送られたハッシュ値をそのまま格納するのであれば、パスワードを平文で送って平文のままデータベースに格納するのと同じ脆弱性を抱えることになります。
クライアントから送られたハッシュ値をさらにハッシュ化して格納するのであれば、平文のままパスワードを送ってサーバー側でハッシュ化するのと同じです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/01 15:44 編集

    二段階認証などの対策は、自社で漏れても、仮に他社で使い回されてて、それが漏れて自社に持って来られても、対策出来るようにそれぞれのサイトが力を入れて、頑張ってる訳です。

    他のサイトに文句を言った所で、誰も保証してくれません。
    ユーザーの自己責任と突っぱねていては、信用されません。
    自社は、自社で守る。その為の施策に全力を注ぐべきです。

    キャンセル

  • 2016/10/01 21:01

    「パスワードを平文で送ると漏れないか心配」ということですが、「ハッシュ化したパスワード」を「パスワード*」と呼ぶことにすれば、「パスワード*を平文で送るので、パスワード*が漏れないか心配」ということになりますよ。正しいパスワード*をサーバーに送れば認証されるので、パスワード*が漏れると大変ですよ。
    「パスワード」は漏れては駄目だが、「パスワード*」はいくら漏れてもかまわないと思っているのなら間違いです。

    キャンセル

  • 2016/10/04 13:16

    >平文のままパスワードを送ってサーバー側でハッシュ化するのと同じ

    同じではないですね。
    「GETやPOSTに対するログを取るように設定されていた場合」の心配をひとつ減らせるのだから。

    ただしpackさんのご意見は現実的で傾聴に値します。

    キャンセル

+1

結論:SSL/TLSを適用しましょう。そして、パスワードのハッシュ化はサーバサイドで行う。

SSLなしでパスワードをJavaScriptでハッシュ化した場合、ハッシュ化後のパスワードはそのままネットワーク上を流れますので、それを手に入れてしまえば不正ログインできてしまいます

Google ChromeはHTTPSでない全サイトを「危険」とする方向に向かっていますし、そうでなくてもパスワード入力フォームのあるサイトは、もはやHTTPでの運用は不適当と言って良いでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/26 17:44 編集

    「SSLの話ではありません」ということを書いていたつもりなのですが文章がわかりにくかったようですね。すみません。上記の質問はSSLによる暗号化通信を行った上での話になります。

    キャンセル

+1

そのため、クライアントサイドでSHA256によるパスワード暗号化を行った上でサーバサイドにパスワードを送る方法をとったほうがユーザにパスワードの安全性を保証することができるのではないですか?

この考え方は正しいですか?

端的に言うと間違っています。SSL/TLSの話ではないと思っているのであればなおさら間違いです。

パスワードを保存する際に、

  • クライアントサイドでパスワードをハッシュ
  • 通信経路上をハッシュがそのまま通過
  • サーバサイドで受け取ったハッシュをそのまま認証に利用

となるわけで、通信経路上の盗聴を行うことで、ハッシュアルゴリズムも何も関係なく「そのハッシュ」を奪取すれば良いことになり、事実上、平文のパスワードをネットワーク上を流し平文を保存しているのと同義になります。


セキュリティを考慮する場合、「安全」と言っても「何に対するどういう安全か」を1つ1つ定義して、それに対してどのような対策をとるかを検討する必要があります。

質問者さんがおっしゃっている「サーバサイドでどう管理されているかわからないし、どう漏洩するかもわからない」というのであれば、そもそもそのサービスを利用することをやめるべきでしょう。

一般に、

SSL/TLSを利用することで

  • 通信経路上を流す通信の暗号化
  • 通信の相手の真性の担保

サーバサイドで暗号化した状態で保存することで

  • 漏洩時の解読の難易度を高める

異なるサービス間で同じパスワードを使いまわさないことで

  • 漏洩時の被害範囲の縮小

といった安全を得ることができます。

現状の質問をみると、漠然と不安がある、といった状況と大差なくみえます。
少し攻撃者側の手法を知ったうえで、それに対してどの部分のどういった安全をどう担保するか、といった視点で検討してみてはいかがでしょうか。


 ■ 2016.10.01. 17時過ぎの追記

守る対象を

  • パスワードとした元の文字列
  • サービスの利用にあたっての本人確認に利用される情報

どちらと考えるかで、対処は変わってきますね。

 パスワードとした元の文字列の保護が課題の場合

質問者さんがおっしゃるように、通信経路上をそのまま流れることを避けることが優先事項となりますね。
クライアントサイドでハッシュ(もしくは何らかの対応付けされる文字列でいいわけですが)生成の上で、通信経路をそのハッシュ文字列を流す、というのは1つの解になります。

この観点でこの手法は、パスワードマネージャ等のソフトウェアを使って各アカウントのパスワードをランダム発行し管理するモデルとそう変わらない手法とも言えます。
パスワードマネージャの管理パスワードが「元のパスワード」と考えられます。
通信経路上を流れる文字列はそのサービスでしか利用していない、しかも何らかの計算ロジックに基づかないランダムな文字列なので、元のパスワード文字列は保護されます。

しかしこの場合、クライアントサイドでどう入力するかにかかわらず、通信経路上にその「ハッシュ文字列」を流せさえすればそのサービスのアカウントとしてはなりすましができることになります。
「本人確認に利用される情報」が「パスワード文字列」から「ハッシュ文字列」に置き換わっただけで、サービス側がその「ハッシュ文字列」を使える人はそのアカウントの利用者と解釈するわけです。

この手法によって安全性が向上する可能性を見込めるのは、

  • 複数のサービスで同一のパスワードを使いまわしている状況

のみです。
つまり、課題が「パスワードに入力した文字列をどこでハッシュするか」ではなく「複数のサービスで同一のパスワードを使うことを避ける」ということに置き換わります。

 サービスの利用にあたっての本人確認に利用される情報の場合

本来サービス提供者が考えるべき保護の対象はこちらになってきます。
すると、まず第一に出てくる検討課題は「何をもって認証とするか」になります。

  • パスワード認証
  • 多元要素認証(ワンタイムパスワード的なものを含む)
  • コールバック認証
  • クライアント証明書による認証

など、様々な認証手法が候補になります。

これらの中でパスワード認証は、暗号化における共通鍵のように「サーバサイド、クライアントサイドで同一の認証情報を持ち、その一致をもって認証とする」手法です。
その時点で、その認証情報(つまりパスワード)とその伝送手段は、サーバサイド、クライアントサイドそれぞれで秘匿すべき情報になります。
言い方を変えると、サーバサイド、クライアントサイドそれぞれの認証情報の保護を疑うことを前提にした場合、パスワード認証では認証として充分と言えません。

そこを疑う場合は認証手法の変更を検討すべきです。

 その他、コメント内へのコメント

ただ、少なくともクライアント側でパスワードをハッシュ化していれば「元のパスワード文字列がこのサービスから漏洩することはない」ということは保証できるのではないでしょうか?

これは上で説明したあたりですね。

(もしかしたらハッシュから元の文字列を復元する方法などがあるのかもしれませんが、もしそのようなものをご存知でしたら是非教えていただきたいです!)

これは他の方もどこかで触れていましたが、要するに総当たりで解析することをいかに効率よくやるか、という課題で、レインボーテーブルなどの手法を利用することで効率よく元の文字列を見つけ出すといった手法が作られています。

また、攻撃者の視点に立つと「特定の人物に成りすましたい」という場合よりも「誰でもいいからのっとれるアカウントを探す」という場合が多いので、ハッシュから元のパスワードを導くよりも、既にわかっているパスワードとハッシュの組み合わせに一致する文字列を使っているユーザーを探し出す、ということになるでしょう。
もっともこの場合も、いちいちハッシュからの一致を見つけ出すよりも、特定のよくあるパスワードを入力して、アカウント側をリストに沿って入力していく、というリバースブルートフォースと呼ばれる手法をとる方が現在は主流でしょう。
参考) http://securityblog.jp/words/reverse_brute_force_attack.html

このあたり、他の方もおっしゃっていましたが徳丸さんという方が非常に多くの情報をWeb上に残しておられますので検索してみるといいかと思います。
また、 体系的に学ぶ 安全なWebアプリケーションの作り方 という本を書かれていますので、こちらはこの件に関わらず必読かと思います。

 おまけ

なんとなく、SSL/TLSについて、どのような手法なのかを理解されていない部分があるのかなと感じます。
SSL/TLSで利用している通信経路の暗号化、という部分は、質問者さんがおっしゃっている通信経路上をテキストが流れる際の充分な保護になります。
つまり、適正なSSL/TLSサーバ証明書が利用されていれば、入力ポイントからサーバに到着するまでの通信内容は保護されます。
つまり、パスワード文字列を入力し、流すことを安全にできます。
サーバサイドで受け取ったそのパスワード文字列を、そのままDBに保存するのであればパスワード文字列の漏洩につながりますが、ハッシュを保存するのであればサーバ上に素のパスワード文字列が残ることはありません。

つまり、

  • パスワードは暗号(ハッシュ)化してDBに保存しています

というのが

「われわれはこのようなセキュリティ対策を行っているので安心して利用できます」と主張する

ことそのものになります。

SSL/TLSについては以前 自分のブログ で数ページまとめたことがありますので、よろしければそちらをご覧ください。


 ■ 2016.10.01. 21時過ぎの追記

raccy さんの回答のコメント欄からの派生です。

> (kazさんが「1つの解になります」とおっしゃっている様ですがこれは保証されるという意味で受け取っていいのでしょうか)

どこの範囲での保証かにもよるんですが、基本的に「保証」とまではいえません。
「保証」とまで言えるようなレベルに持ち込むには、元のパスワード文字列を画面上で入力させないところまでやらなければ難しいでしょう。

この続きです。

SSL/TLSの経路保護等、別の疑問も生まれてきているようですが、一旦そちらまで考え始めると混乱しかしないと思いますので、「クライアントサイドでハッシュすること」にテーマを絞ります。

 画面上でパスワード文字列を入力すること自体で発生するリスク

Webシステムを前提とした場合、XSSなどの攻撃手法を利用することにより認証のためのサーバへの通信を発生させる前に画面上に入力された文字列を奪取し攻撃者のサイトにそのデータを送り込むことが可能です。

また、クライアントサイドのPCのセキュリティ状態まで考慮に入れれば、どのような画面設計、通信仕様にしたところで、なんらかの箇所で入力が発生しさえすれば、元の文字列の奪取は可能でしょう。
※キーロガー、とかを調べるとわかるかと思います。

というように、保護対象をある程度限定しないとこの議論はその箇所に影響する別の要素を持ち込むことでセキュリティの綻びが発生しうるため、その箇所だけで納得いく回答を得るのはなかなか困難かと思います。

立場をサービス提供サイドと特定し、ユーザーサイドのPC環境は安全と仮定したうえで、クライアントサイドでハッシュ処理を行うことは、元のパスワード文字列を受け取らないという意味で、保護している、と言えるとまでは言えると思います。

 サービスの認証情報の保護という観点ではリスクが増すともいえるかも

ここまでは「パスワード文字列の保護」についてでしたが、ここからは「サービスの認証情報の保護」の観点で考えます。

仮にこのサービスで利用されているパスワードが他サービスで使いまわされているパスワードで、その他サービスで漏洩した場合、そのパスワードを利用してこのサービスのパスワード入力画面に打ち込めばなりすましログインが可能になることを考えると、なりすましに利用できる文字列の可能性が

  • ハッシュ:漏洩の危険度は低い
  • パスワード:漏洩の危険度は(他サービスも含めることで)高い

という2種類となることで、トータルでの危険度は増している(ハッシュの漏洩によりなりすませる分)、とも考えられます。

  • 元のパスワードをハッシュするロジックは公開されている(クライアントサイドでやるということはそういうことになります)
  • サーバに送り込むべき文字列はハッシュ

ということは、元のパスワード、ハッシュのいずれかがわかればいい、ということになることはご理解いただけますか。

 その他、全体的な整理

パスワードをクライアントサイドでハッシュし、サーバサイドにはそのハッシュを送るとした場合、サーバサイドでは「ハッシュ」こそがそのユーザーの「認証情報」として扱われる。

  • つまりこれは、「通常のパスワードよりも長くランダムな文字列をパスワードとして設定した」ことと同義となる。
  • 同じ前提で、通信経路という観点でみれば、通信経路を流れるハッシュがわかれば認証できる、ということになる。

 これで「よし」の場合

  • サーバサイドでのそのハッシュ方法などとは関係なく、「通信経路上を元のパスワード文字列を流さないこと」が課題だったことになる。
  • それであれば、パスワードマネージャなどを利用し、使いまわしたりせずにサイトごとに長いランダムなパスワードを生成したものをパスワードとして設定するのと同義。
  • ただしこの場合は「ユーザーサイドのパスワード管理の問題」となるため、サービス提供サイドの技術要件としてフォローする箇所は少ない。
    ※なくはない。パスワード要件として充分に長い文字列を設定可能とする、など。

 そうではなく「認証情報の保護」が課題だった場合

  • クライアントサイドでハッシュすることによって見込める認証情報の保護レベルの向上はほぼない。
  • サーバサイドでDB等に認証情報を格納する際、受け取ったハッシュをさらにハッシュして保存するなどすることでより安全に保存することはできますが、これは「平文のパスワードをハッシュして保存するとより安全」というのと同義。
  • 元のパスワード文字列の漏洩を気にするのであれば、使いまわさないなど別のレイヤーでの対応が必要。

→ おそらく、課題設定とその対策が一致していない。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/03 09:51

    他人事のように言ってしまいますが、非常にいい議論してますねー。
    hojoさんもpackさんもせっかくなので行けるところまで行ってみましょうね。

    hojoさん>1点だけ。

    質問1への回答(結果)として

    > 結果:
    > 当WebサービスからWebサービスを利用するユーザのパスワード文字列が漏洩することはないので、当Webサービスを利用するユーザは安心して当Webサービスを利用することができる。

    とおっしゃっていますが、ここは、

    - 元のパスワード文字列は保護できる
    - サービス利用にあたっての安全性は保護できていない(サービスの安全の侵害要因が、パスワードの漏洩から、クライアントサイドでのハッシュ結果に置き換わっただけ)

    となるのは理解できますでしょうか。
    サーバサイドでは「ハッシュ」を受け取ってそれを基に認証するので、元のパスワード文字列が何かは関係なくなっている、ということです。

    キャンセル

  • 2016/10/04 00:55 編集

    「掘り下げるというより、排除した方がいいと思います。」
    といいましたが、あまり難しく考えなくていいですからね。委縮させてしまいそうで、ごめんなさい。
    「掘り下げる」でいいと思います。

    「サービスの安全性が高まる」だと、やはりhojoさんの主観になってしまうなと思いますし、それだと「議論」というより、「ツッコまれて」しまうよなと、思ってしまいます。

    あと「保証」という言葉も、ものすごく抽象的ですね。
    「社会的責任」などの意味合いも含みますし、「安全性の立証」など、また別の行為を含んでくるなど、人によって受け取り方は様々ですので、そういった言葉を無意識に使うと、たいてい議論がこじれます。

    議論の余地のない完璧な客観的事実なんてものは無いと思いますし、どこかに主観は入ってしまうんですけどね。
    まぁ、まずは意見を出して、あれこれ付け足したりはしなくて、いいです。
    議論の余地があるからこそ、こうして議論している訳ですから。

    キャンセル

  • 2016/10/06 11:15

    すみません、今出張から帰ってきました。
    おそらく本日中に確認できると思いますのでもうしばらくお待ちください。

    キャンセル

0

SHA256ということはハッシュ値を保存すると言うことですよね。
それなら、クライアント側でハッシュ値計算して、それをサーバーへ送ってサーバーで保存すればどうでしょうか?
ハッシュは一方向の不可逆なコードなので、ハッシュ値からパスワードを逆に求めることは出来ません。
なお、MD5などはレインボーテーブルを使った攻撃などの脆弱性があるのでSHA256が推奨されています。

サーバー側では、送られてきたハッシュ値と保存されているハッシュ値の比較だけすれば良いことになります。ただ、サーバー側では平文のパスワードはわかりませんので、パスワードを忘れた時はリセットをできるような仕組みにしておかないといけません。

ただこの方法は、クライアント側でのハッシュ計算がどのように行われているかの解析が困難なようにしておかないとだめです。(解析を完全にブロックするのは難しい。ハッシュ計算の部分を暗号化して実行時に元に戻すとか、まあ、昔のコピープロテクトのようなことでもしないと難しいかもしれません)

パスワードのハッシュ化については下記URLなどが参考になるかと思います。
https://www.websec-room.com/2013/02/27/237

より安全にするには、通信経路はSSLにして、ハッシュ化はサーバー側で行うのが良いと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/26 17:47 編集

    SHA256によるハッシュ作成に利用するSaltについての扱いについてはどう思われますか?
    つまり、クライアントサイドで暗号化を行った場合、Saltを隠蔽する形で暗号化を行う手法はありますか?その術がない場合、Saltを隠蔽するまでする必要はなかったりするなどの意見というか考え方で良いかどうかなど、意見が欲しいです。

    キャンセル

  • 2016/09/26 18:07

    追記でも書きましたが、クライアント側での処理の隠蔽は完全には無理だと思います。内部でのハッシュ化の処理が解析されたら終わりです。
    処理を動的に幾つものDLLを介するとかなどリバースエンジニアリングを困難にするようなコードを組むとかの手法を用いるくらいしか思いつきません。
    コピープロテクトと言うのは、その昔、ソフトがフロッピーで売られていた頃、そのコピーガードとして組み込まれていたプロテクトガードのことです。コピーガードと言うのは、究極はそのチェックルーチンになりますから、そのチェックルーチンを解析できたらその部分をパスすればガードを外すことが出来る事になります。よくやられていたのは、チェックルーチンを暗号化しておき、動作時に復号化してからルーチンを呼び出すようにする手法です。結局、これもイタチごっこです。

    キャンセル

  • 2016/09/26 18:40

    追加された質問内容に関して。
    クライアント側での暗号化の詳細が第3者に漏れることが絶対にない、解析は絶対に不可能と保証できるのなら問題はないでしょうけど、それは保証できないと思います。リバースエンジニアリングを完全に防ぐ手段がありません。

    キャンセル

0

パスワードのハッシュ化はクライアント側ですべきでないと思います。
ハッカーになるべくヒントを与えないような作りにすべきだと思います。

基本的に、パスワードのハッシュ化はサーバーサイドで行います。
Saltを隠蔽するのは当然ですが、加えて、ユーザー固有の一意な情報(ログインIDとかメールアドレスとか)などと併せてパスワードをハッシュ化すればなおよいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/01 08:42

    ご意見ありがとうございます。質問投稿時に比べ、話が複雑になってきているため、質問の追記などを含めその他の回答をご覧になった上で何か思うところなどございましたらご指摘頂けないでしょうか?宜しくお願い致しますm(_ _)m

    キャンセル

0

元のパスワードを保護し、ハッシュは漏れてもいいという考えなら質問者様の通りで良いと思います。
SHA256はハッシュであり、暗号化ではありません。

ユーザーの安全性に何を含むかによるので、ユーザーの安全性の問題はまた別かと思います。

ただ、SSL/TLSは安全という前提なので、それだけで十分かと思います。
更に安全を求めるならユーザー別にクライアント証明書も利用し、万一ハッシュが漏れても接続クライアントが正しくない場合は利用させないなどの対応も一案かと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/26 18:41

    SHA256は「復号化不能な暗号化」と解釈していたのですが、確かに「ハッシュ」と表現した方が適切でした。ご指摘ありがとうございます。

    moonphaseさんは、クライアントサイドでSHA256によるハッシュ生成を行う際のSaltキーを隠蔽することは不可能とお考えですか?

    もしそのようにお考えの場合、ハッシュが漏れてしまった場合に起こりうる危険性はどのようなことが考えられますか?

    例えば、Javascriptに記述されているSaltキーとその漏洩したハッシュを利用してそのユーザのパスワードのハッシュとメールアドレスを利用して同じパスワードを利用している異なるサービスにログインできてしまうなどは考えられますか?

    キャンセル

  • 2016/09/26 20:27

    そもそも利用者からSaltを保護する必要がないように思えますがいかがでしょうか。
    SaltはユーザーID等を利用すればいいのでは、と思います。

    ハッシュが漏れていい場合は、ハッシュが漏れても被害なし。
    ハッシュが漏れてダメな場合は、ハッシュが漏れると被害あり(なりすまし)。
    というだけの事かと思います。

    キャンセル

  • 2016/10/01 08:39 編集

    返信ありがとうございます。moonphaseさんの意見をいただき「Saltに関してはさほど気にしなくて良い」と思えるようになりました。

    その他のユーザ様のコメントを見ても「基本的にSaltを保護する必要はない」という意見で一致しているような気がしています。

    かといってSaltを使わないのは心配なきがするのでメールアドレスやパスワードから生成した文字列などを利用してSaltを作成しようと思いました。

    キャンセル

0

なるほどな、と思いました。
おっしゃりたい事は、よく解ります。

私もセキュリティに詳しくはないので、何かの解決策を提示するものではないので、ご了承ください。
他の方の意見を聞いてみたいです。

他の方の回答にあるように

サーバー側では、送られてきたハッシュ値と保存されているハッシュ値の比較だけすれば良いことになります。

は、確かにそうなりますね。

※※これは間違いでした。なりません。サーバー側も必須です。

全ユーザー共通のSaltキーを、Javascriptに記載するという想定ですかね。
あるいは、ユーザー毎にサーバー側で生成して、Javascriptで渡すというようなお考えですかね。

参考リンク内にあった

salt とは一定長以上の文字列で、以下の要件を満たすものです。

ユーザー毎に違うこと
ある程度の長さがあること(20桁以上が目安)

を見ると、ユーザー固有であることが必要ですね。

こういう考えはどうですか?

ユーザーID(仮にメールアドレス)とパスワードを使って、固有のSaltキーを生成。
なんなら、パスワードだけからSaltキーを生成してもいいような。
⇒ そのSaltキーをを基に、ハッシュ化。
⇒ 送信。

現在よく行われているであろうサーバー側での処理で使われる値。

  • WEBアプリ毎に設定される全ユーザー共通のキー(ユーザーからは見えない。ソースには記載。運営は見える)

ユーザー側で処理する場合に使う値

  • パスワード(最後の砦。本人しか知らない。これが漏れたら元も子もない)

「ハッカーに処理が知られる」
⇒「パスワード入力からハッシュ化までの間を狙われる」
⇒「ハッシュ処理を解析される」

この2パターンが考えられると思いますが、確かに入力からハッシュ化までの距離、時間は短ければ短い方が良さそうですね。
繰り返しますが、以上は、質問を拝見しての私の感想です。

あっ、そうすると、「ハッシュ自体を途中で盗まれたら…」になるのか。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/09/29 17:15 編集

    もう一点、質問者さんの気になってた事で、参考になりそうな他の質問が、YsManaさんのクリップの中にありましたので、貼っておきます。

    『JavaScriptにはハッシュ関数は用意されていない? コードを確認されると意味がないから?』
    https://teratail.com/questions/30933

    質問者さんが戻ってきて、また私が的外れな事言ってたら、その時はYsManaさんに、ぜひとも援護願いたいです。

    キャンセル

  • 2016/10/01 12:05

    すみません、隙間時間に一つづず返信文を書いており、予想以上の長文でしたので、packさんのコメントについては時間があるときに一気に読み込もうと思って後回しにしておりました。もう少しで時間ができますので、そのときに再度返信させていただきます。

    キャンセル

  • 2016/10/01 16:25

    私も、生半可な知識だけで、いろいろ言ってしまい、長くなってしまいました。申し訳ありません。
    間違った発言も所々あります。今回の質問は、私自身も大変、勉強になりました。
    ありがとうございます。

    追加で言いたかった事は、raccyさんの回答の方に書きました。

    キャンセル

0

この場合、

  • クライアント側では平文パスワードとSaltキーAをハッシュ化
  • サーバー側ではクライアントから送られてきたハッシュとSaltキーBをハッシュ化しDBなどに保存

これが一番安全だと思います。
この場合、ログインできるのは

  • 平文パスワードを知っている人
  • 通信経路を見てクライアント側で生成したハッシュを盗んだ人

です。
通信経路を見られてもこの場合ならハッシュ化パスワードしかわからないですし(もちろんフォームページが改ざんされたら終わりです)、サーバーのDBが漏れたとしてもDBに保存してあるハッシュを利用してログインすることはできません。
(ログファイルにPOSTフォームなどが残る設定になっていて、ログファイルが漏洩してしまったらクライアントサイドのハッシュが漏れてしまいますが)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.22%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる