web-dev-qa-db-ja.com

HTTP経由でパスワードを保護する方法は?

私のパスワードはabcだとしましょう。 HTTP経由でサーバーに送信します。

これをプレーンテキストで送信し、サーバーでハッシュしてデータベースのエントリと比較することもできますが、その接続でトラフィックを見ることができる人は誰でもパスワードをプレーンテキストで見ることができます。

それで、私はそれをクライアント側でハッシュし、サーバーにハッシュなしで比較させることができます(既にハッシュされているため、サーバーはハッシュを2倍にすることもできますが、この状況では違いはありません)。しかし、トラフィックを見ることができる人なら誰でも、ハッシュ化されたパスワードを見て、ハッシュ化されたパスワードをサーバーに送信すると、サーバーはそれを受け入れます。

HTTP経由でパスワードを送信するにはどうすればよいですか? RSA公開鍵暗号化などの暗号化アルゴリズムを実装する必要がありますか?それともこれは不可能ですか?

このメソッドは、どのブラウザでも使用できる必要があります。

27
FireCubez

できません。

安全でないチャネルを介して情報を安全に送信するには、暗号化が必要です。

最初に鍵をトランスポートする必要があるため、対称暗号化は使用できません。これは、安全でないチャネルを介して安全に行うことはできません[*]。

これにより、公開鍵暗号化が残ります。もちろん 自分でロール することはできますが、 デイブになりたい はしたくないので、HTTPSのままにしておきます。

[*]もちろん、物理的なキーの交換など、安全なチャネルを使用してキーを交換することもできます。次に、Kerberosなどの秘密鍵暗号を使用できます。

112
tim

TLSは実際にそれを行う唯一の方法です。

しかし、JavaScriptで暗号化するとどうなりますか?

攻撃者は、クライアントに送信するJavaScriptを変更したり、入力したすべての情報を記録する独自のJavaScriptを挿入したりすることができます。

次に、CSPとSRIを使用して、スクリプトの追加と自分のスクリプトの変更を防止します。

最新のツールを使用してサイトを保護していることをうれしく思いますが、SRIは 非セキュアコンテキスト の場合、実際には外部リソースの侵害からのみ保護します。攻撃者は、CSPヘッダーとSRIタグを単純に変更できます。

最初から暗号化を使わずにこれを行う方法は実際にはありません。それを行う唯一の標準的な方法は、TLSを使用することです。

45
AndrolGenhald

HTTPSを使用する必要があることに同意しますが、実際の認証交換にソルトチャレンジレスポンス認証メカニズム(SCRAM、 RFC 5802 を参照)を使用することで、さらに安全にすることができます。

実装するのは簡単ではありませんが、その要点は、サーバーにパスワードを送信するのではなく、パスワードを知っているという証明をサーバーに送信することです。証明の導出はクライアントとサーバーからのナンスを使用するため、攻撃者が再利用できるものではありません(ハッシュ自体を送信するなど)。

これには、説明する基本認証でHTTPSを使用することに対するいくつかの追加の利点があります。

  1. ログイン時にサーバーが実際にパスワードを確認することはありません。誰かが悪意のあるコードをサーバーに挿入できたとしても、ユーザーのパスワードはわかりません。
  2. HTTPSの実装にバグがある場合(Heartbleedなど)、攻撃者は引き続きパスワードを取得できません。 TLSがバイパスされても、パスワードは使用できないためです。
  3. なんらかの理由でHTTPSを使用できない場合は、パスワードを平文で送信するよりもよいでしょう。攻撃者は、交換に基づいてパスワードを推測することはできません。とはいえ、多層防御の方が優れているため、引き続きHTTPSを使用する必要があります。

注意してくださいこれは、クライアントがSCRAM計算を実行できる場合にのみ安全ですなしサーバーからコードをダウンロードします。ファットクライアントを提供するか、ユーザーが自分で制御する独自のコードを記述できる場合があります。 HTTP経由でSCRAMコードをダウンロードすると、攻撃者はSCRAMコードを変更してパスワードをクリアテキストで送信したり、パスワードを公開したりすることができます。

25
Melanie

この場合は必ずTLSをデプロイする必要があります。

HTTPを介してトランスポートセキュリティシステムを発明しようとする場合、最終的には、とにかくTLS機能のsusbsetを実装することになります。そのようなシステムを設計および実装する際に注意すべき多くの落とし穴があり、それらは多くの安全機能を提供しない言語でシステムを実装しようとする場合にさらに増幅されます。

JavaScriptで暗号化プロトコルの正しい実装を実装したとしても(すでに大きな課題です)、その実装がタイミング攻撃に耐性があることに依存することはできず、誰かがスクリプトを無効にすると(たとえば、NoScriptを使用して)すべてが壊れます)。

一般的なルールとして、セキュリティクリティカルなコードを最小限に記述する必要がある、最も単純でよく理解された信頼できるコンポーネントで構成される実装を選択する必要があります。 Andrew Tannenbaumを引用するには:

かなりの数の問題(アプリケーションのセキュリティで)は、バグのあるソフトウェアが原因で発生します。これは、ベンダーがプログラムにますます多くの機能を追加し続けるために発生します。

7
Polynomial

RSA公開鍵暗号化などの暗号化アルゴリズムを実装する必要がありますか?

あなたがそれを試してみることを考えているなら、あなたはまた、全力を尽くしてHTTPSを使用することもできます。あなたはエキスパートではないようですので、「独自のローリング」暗号化は間違いなくそれを安全でなくする誤実装があります。

6
Brian Williams

それは実際にはかなり可能です。

パスワードはクライアント側でハッシュする必要がありますが、静的関数ではハッシュしないでください。次の方法は2つのステップを使用し、 ダイジェストアクセス認証 から着想を得ています。

注:サーバーは、Passwordと対応するKeyのHMACを保持します(ダイジェスト);

  1. クライアントはサーバーにナンスを要求することから始め、サーバーはKeyNonce;
  2. クライアントの計算:HMAC(HMAC(PasswordKey)、Nonce)そしてそれをサーバーに送信します。
  3. サーバーは次を計算します:HMAC(DigestNonce)と比較します受け取った値。

これにより、リプレイから保護されます。

私が目にする主な関心は盗聴に対する保護ではありませんが、プレーンテキストのパスワードがシステムログにさえサーバーに保存されないことを完全に確認するためです( Twitter または を参照)。 GitHub )。

注:HMACはPBKDF2で置き換えることができます。

2

安全でない接続を介してユーザーを認証する方法は実際にあります: Secure Remote Password(SRP)protocol 。 SRPは、中間者攻撃者がクライアントのパスワードを取得したり、認証を再生したりせずに、クライアントがサーバーに対して自分自身を認証できるように特別に設計されています。さらに、SRPによる認証が成功すると、クライアントとサーバーの両方が知っている共有秘密鍵が作成されますが、MitMは作成しません。この秘密鍵は、対称暗号化やHMACに使用できます。

ただし、SRPにはいくつかの制限があります。

  1. 登録プロセスではパスワードと同等の素材を送信する必要があるため(サーバーは保存する必要はありません)、ユーザーは何らかの安全な方法で登録しておく必要があります。
  2. 信頼されていないサーバーでSRPログインを試行しても安全です(つまり、そのサーバーにパスワードが公開されることはなく、サーバーのデータベースにパスワードがなかったことがわかります)。信頼されていないサーバーからログインWebページをロードするのは安全ではありません(すべてのキーストロークをキャプチャし、どこかに送信する可能性があります)。
  3. SRPによる認証が成功すると安全な共有秘密鍵が生成されますが、Webアプリでこの鍵を実際に使用するためのコードをサーバーからロードする必要があり、攻撃者はそのコードを改ざんして対称鍵を盗み、変更を加えることができますリクエストとレスポンス。

言い換えると、SRPは、安全でない接続を介してコードをダウンロードする必要のない信頼できるクライアントがあり、ユーザーを登録する他の安全な方法がある場合にも役立ちますが、SRPは適していません。 Webアプリケーションの場合。 Webアプリは常にサーバーからコードをダウンロードするため、サーバーへの接続が安全でない場合、MitM(または他のネットワーク攻撃者、たとえばDNSのなりすまし)がWebアプリに悪意のあるコードを挿入する可能性があります。犠牲者はそれについてすることができます。そのコードが存在すると、入力したパスワードやその他のデータを取得し、生成されたキーを盗み、知らないうちに送信した要求や受信した応答を改ざんできます。

2
CBHacking

HTTPを使用して安全にパスワードを送信することは確かに可能です。そのための基準さえあります。それは呼ばれています HTTP-DigestおよびRFC 7616で定義されています。これは、しばらくの間、HTTP仕様の一部でした。もともとはMD5メッセージダイジェスト(「ハッシュ」)アルゴリズムのみを使用するように設計されていましたが、規格のその後の改訂では、クライアントとサーバーが使用するアルゴリズムをネゴシエートできるようになりました。

残念ながら、HTTPダイジェストには多くの問題があり、最も明白なのは、サーバーがパスワードを平文で持つ必要があることです。したがって、HTTPを使用してパスワードを安全に通信することは可能ですが、使用中にサーバーにパスワードを安全に格納することはできません。つまり、基本的に、それは役に立ちません。

他の人が言ったように、TLSは複数の問題を同時に解決し、かなり前方互換性があるため、TLSを実装する方が良いでしょう。

2

他の人がTLSを言ったように! TLS! TLS! (そしてまともなキーの長さも)

しかし、実装するためにHTTPとサーバーを使用する必要がある場合、これはプログラムによる使用ですか、それとも人間による使用ですか?人間が使用する場合、基本認証とフォームベースのどちらを使用していますか?そして、あなたの用途は少しロジックを適用することができますか? joe publicは使用できません。他に保護する必要があるものはありますか、それともパスワード自体だけですか?

もしそうなら、あなたは見ることができるかもしれません:

  • ワンタイムパスワードパッド/ジェネレーターを使用します(RSAフォブは安くはありません。そのようなお金を使うことができれば、TLSを購入できます)。
  • SMSのような他の2要素認証(それ自体に問題がないわけではありません)。
  • パスワードを難読化するための単純なチャレンジ/レスポンスメカニズム。たとえば、ページにテキストに2つの数字が表示されます(露骨にラベル付けされていません)。ユーザーは、各数字に追加された2つの数字の差などの簡単な計算でパスワードを開始する必要があります。 PINの前後にランダムなものを含める場合があります(例:98634572dkkgdld)。チャレンジ番号を変更すると、即座に試行されないリプレイ攻撃を停止する必要がありますが、攻撃者が十分な試行をキャプチャできれば、攻撃を回避できる可能性があります。ユーザー向けのスクリプトに難読化ロジックを追加することはできません。「cosが表示されます。また、スキームが複雑すぎると、ユーザーはさらに嫌いになります。

私はまだTLSを使用していますが、最近の証明書は安価(無料でも)なので、複雑な難読化スキームが存在する理由はまったくありません。

1
Richard N