パートI:ログイン方法
認証のためにサーバー側のスクリプトに値をPOSTするlogin + password HTMLフォームを作成する方法をすでに知っていると想定します。以下のセクションでは、適切な認証のパターンと、最も一般的なセキュリティの落とし穴を回避する方法について説明します。
HTTPSを使用するか、またはHTTPSを使用しないか?
接続がすでに安全である(つまり、SSL / TLSを使用してHTTPS経由でトンネルされる)場合を除き、ログインフォームの値はクリアテキストで送信されます。これにより、ブラウザとWebサーバーの間の回線を盗聴しているすべてのユーザーが、ログインが通過したときにログインを読み取ることができます。使って。このタイプの盗聴は政府によって日常的に行われていますが、一般的に、私たちはこれを言う以外に「所有された」ワイヤーに対処しません:HTTPSを使用してください。
本質的に、ログイン中の盗聴/パケットスニッフィングから保護する唯一の実用的な方法は、HTTPSまたは別の証明書ベースの暗号化スキーム(TLSなど)または実証済みでテスト済みのチャレンジ/レスポンススキーム(Diffie-Hellmanなど)を使用することですベースのSRP)。その他の方法は、盗聴者によって簡単に回避できます。
もちろん、少し実用的でない場合は、何らかの2要素認証方式(Google認証システムアプリ、物理的な「冷戦スタイル」コードブック、RSAキージェネレータドングルなど)を使用することもできます。正しく適用されれば、これは保護されていない接続でも機能する可能性がありますが、開発者が2要素認証を実装してもSSLを実装しないとは想像しがたいです。
(しないでください)Roll-your-own JavaScript暗号化/ハッシュ
WebサイトにSSL証明書を設定することの知覚された(現在は回避可能ですが)コストと技術的な難しさを考えると、一部の開発者は、セキュリティで保護されていないワイヤを介してクリアテキストのログインを渡さないようにするために、ブラウザ内のハッシュまたは暗号化スキームを独自に導入したいと考えています。
これは高貴な考えですが、上記のいずれかと組み合わせない限り、つまり、強力な暗号化で回線をセキュリティで保護するか、実証済みのチャレンジ/レスポンスを使用しない限り、本質的に役に立たない(そしてセキュリティ上の欠陥になる可能性があります)メカニズム(それが何であるかがわからない場合は、それが証明するのが最も難しく、設計するのが最も難しく、デジタルセキュリティの概念を実装するのが最も難しいことの1つだと知ってください)。
パスワードのハッシュはパスワードの漏洩に対して効果的である可能性があることは事実ですが、リプレイ攻撃、中間者攻撃/ハイジャックに対して脆弱です(攻撃者がセキュリティで保護されていないHTMLページに数バイトを挿入してから、ブラウザでは、JavaScriptのハッシュをコメントアウトするか、ブルートフォース攻撃を行うことができます(ユーザー名、salt、ハッシュされたパスワードの両方を攻撃者に渡しているため)。
人道に対するキャプチャ
CAPTCHAは、特定のカテゴリの攻撃を阻止するためのものです。自動化された辞書/ブルートフォースの試行錯誤で、人間のオペレーターがいません。これが本当の脅威であることは間違いありませんが、CAPTCHAを必要としないシームレスに対処する方法があり、特に適切に設計されたサーバー側ログインスロットリングスキームがあります。これらについては後で説明します。
CAPTCHA実装は同じように作成されていないことを知ってください。それらは人間が解決できない場合が多く、そのほとんどは実際にはボットに対して効果がなく、安価な第三世界の労働力に対しては効果がありません(OWASPによると、現在のスウェットショップのレートは500テストあたり12ドルです)。一部の国では技術的に違法です(OWASP認証チートシートを参照)。CAPTCHAを使用する必要がある場合は、GoogleのreCAPTCHAを使用してください。これは、定義によりOCRが難しいため(すでにOCRと誤って分類されたブックスキャンを使用しているため)、ユーザーフレンドリーになるように非常に努力しています。
個人的には、CAPTCHASは煩わしいと感じる傾向があり、ユーザーが何度もログインに失敗し、スロットルの遅延が最大になったときの最後の手段としてのみ使用します。これが許容できるほどまれに発生し、システム全体を強化します。
パスワードの保存/ログインの確認
これは、近年見られたすべての非常に公表されたハッキングとユーザーデータリークの後、ようやく一般的な知識になるかもしれませんが、それは言う必要があります:データベースにクリアテキストでパスワードを保存しないでください。ユーザーデータベースは、SQLインジェクションを通じて定期的にハッキング、リーク、収集されます。未加工のプレーンテキストのパスワードを保存している場合は、ログインセキュリティのためのインスタントゲームオーバーです。
パスワードを保存できない場合、ログインフォームからPOSTされたログインとパスワードの組み合わせが正しいことをどのように確認しますか?答えは、キー導出関数を使用したハッシュです。新しいユーザーが作成されるか、パスワードが変更されるたびに、パスワードを取得し、それをArgon2、bcrypt、scrypt、PBKDF2などのKDFで実行し、クリアテキストのパスワード( "correcthorsebatterystaple")を長いランダムに見える文字列に変換します。 、データベースに保存する方がはるかに安全です。ログインを確認するには、入力したパスワードに対して同じハッシュ関数を実行します。今回はソルトを渡して、結果のハッシュ文字列をデータベースに保存されている値と比較します。Argon2、bcrypt、およびscryptはソルトをハッシュとともに保存しています。詳細については、sec.stackexchangeに関するこの記事をご覧ください。
ソルトが使用される理由は、ハッシュ自体では不十分であるためです。レインボーテーブルからハッシュを保護するために、いわゆる「ソルト」を追加する必要があります。ソルトは、完全に一致する2つのパスワードが同じハッシュ値として保存されることを効果的に防ぎ、攻撃者がパスワード推測攻撃を実行している場合、データベース全体が1回の実行でスキャンされるのを防ぎます。
ユーザーが選択したパスワードは十分に強力ではないため(通常、十分なエントロピーが含まれていないため)、暗号化ハッシュをパスワードの保存に使用しないでください。また、ハッシュにアクセスできる攻撃者がパスワード推測攻撃を比較的短時間で完了する可能性があります。これがKDFが使用される理由です。これらは効果的に「キーをストレッチ」します。つまり、攻撃者が作成するすべてのパスワードでハッシュアルゴリズムが複数回繰り返され、たとえば10,000回繰り返されるため、攻撃者はパスワードを10,000倍遅く推測します。
セッションデータ-「Spiderman69としてログインしています」
サーバーがユーザーデータベースに対してログインとパスワードを検証し、一致するものが見つかったら、システムはブラウザが認証されたことを記憶する方法を必要とします。この事実は、サーバー側でのみセッションデータに格納する必要があります。
セッションデータに慣れていない場合は、次のように機能します。ランダムに生成された単一の文字列が期限切れになるCookieに格納され、サーバーに格納されているデータのコレクション(セッションデータ)を参照するために使用されます。MVCフレームワークを使用している場合、これは間違いなくすでに処理されています。
可能であれば、ブラウザに送信するときに、セッションCookieにセキュアフラグとHTTP Onlyフラグが設定されていることを確認してください。HttpOnlyフラグは、XSS攻撃を通じて読み取られるCookieに対するある程度の保護を提供します。セキュアフラグは、CookieがHTTPS経由でのみ送信されることを保証し、ネットワークスニッフィング攻撃から保護します。Cookieの値は予測できません。存在しないセッションを参照するCookieが提示された場合、その値をすぐに置き換えて、セッションが固定されないようにする必要があります。
パートII:ログインを維持する方法-悪名高い「Remember Me」チェックボックス
永続的なログインCookie(「remember me」機能)は危険ゾーンです。一方では、ユーザーがそれらの処理方法を理解していれば、従来のログインと同じくらい完全に安全です。そして、その一方で、それらは公共のコンピューターでそれらを使用してログアウトするのを忘れ、ブラウザーのCookieとは何か、またはそれらを削除する方法を知らない不注意なユーザーの手に渡る巨大なセキュリティリスクです。
個人的には、定期的にアクセスするWebサイトの永続的なログインが好きですが、それらを安全に処理する方法を知っています。ユーザーが同じことを知っていると確信している場合は、クリーンな良心で永続的なログインを使用できます。そうでない場合、まあ、あなたは、ログイン資格情報に不注意なユーザーがハッキングされた場合にそれを持ち込んだという哲学に同意するかもしれません。私たちがユーザーの家に行って、それらのモニターの端に並んだパスワードを使って、フェイスパームを誘発するポストイットのメモをすべて剥ぎ取るようなものでもありません。
もちろん、いくつかのシステムが持っている余裕はありません任意のアカウントがハッキング。このようなシステムでは、永続的なログインを正当化する方法はありません。
永続的なログインCookieを実装する場合は、次のようにします。
最初に、このテーマに関するParagon Initiativeの記事を読んでください。たくさんの要素を正しく取得する必要があります。この記事では、それぞれの要素をうまく説明しています。
そして、最も一般的な落とし穴の1つを繰り返すために、永続的なログインクッキー(トークン)をデータベースに保存しないでください。ログイントークンは同等のパスワードであるため、攻撃者がデータベースを手に入れれば、平文のログインパスワードの組み合わせであるかのように、トークンを使用して任意のアカウントにログインできます。したがって、永続的なログイントークンを格納する場合は、ハッシュを使用します(https://security.stackexchange.com/a/63438/5002によると、この目的には弱いハッシュで十分です)。
パートIII:秘密の質問の使用
「秘密の質問」を実装しないでください。「秘密の質問」機能は、セキュリティ対策パターンです。必読リストのリンク4の論文を読んでください。あなたは彼女のYahoo!の後にサラPalinにそれについて尋ねることができます。以前の大統領選挙でメールアカウントがハッキングされたのは、彼女のセキュリティの質問に対する答えが「ワシラ高校」だったからです!
ユーザー指定の質問であっても、ほとんどのユーザーは次のいずれかを選択する可能性が高いです。
母親の旧姓や好きなペットのような「標準的な」秘密の質問
ブログ、LinkedInのプロフィールなどから誰でも持ち上げられる簡単な雑学
パスワードを推測するよりも答えやすい質問。適切なパスワードについては、これは想像できるすべての質問です
結論として、セキュリティの質問は本質的にすべての形式とバリエーションで本質的に安全ではなく、何らかの理由で認証スキームで使用されるべきではありません。
セキュリティの質問が実際に存在する本当の理由は、メールにアクセスして再アクティベーションコードにアクセスできないユーザーからのサポートコールの費用を節約できることです。これは、セキュリティとサラペイリンの評判を犠牲にして行われます。価値がある?おそらく違います。
パートIV:パスワードを忘れた場合の機能
忘れた/紛失したユーザーパスワードの処理にセキュリティの質問を使用してはならない理由についてはすでに述べました。言うまでもなく、ユーザーに実際のパスワードを電子メールで送信してはなりません。この分野では、少なくとも2つの、あまりにも一般的な回避すべき落とし穴があります。
忘れたパスワードを自動生成された強力なパスワードにリセットしないでください。このようなパスワードは覚えがたいことで有名です。つまり、ユーザーはパスワードを変更するか書き留める必要があります。たとえば、モニターの端にある明るい黄色のポストイットに書き留める必要があります。新しいパスワードを設定する代わりに、ユーザーがすぐに新しいパスワードを選択できるようにします-これはとにかくやりたいことです。(これの例外は、ユーザーがパスワードマネージャーを使用してパスワードを保存/管理するために普遍的に使用している場合で、パスワードを書き留めておかないと覚えることは通常不可能です)。
失われたパスワードコード/トークンは、常にデータベースにハッシュします。AGAIN攻撃者がデータベースに手を得た場合にはハッシュ化されなければならないので、このコードは、等価パスワードの別の例です。紛失したパスワードコードがリクエストされた場合は、プレーンテキストコードをユーザーのメールアドレスに送信し、ハッシュしてデータベースに保存します。元のコードは破棄してください。パスワードや永続的なログイントークンと同じです。
最後の注意:「紛失したパスワードコード」を入力するためのインターフェースが、ログインフォーム自体と少なくとも同じくらい安全であることを常に確認してください。非常に長い「失われたパスワードコード」(たとえば、大文字と小文字が区別される16文字の英数字)を生成することをお勧めしますが、ログインフォーム自体と同じスロットルスキームを追加することを検討してください。
パートV:パスワードの強度の確認
最初に、現実をチェックするためにこの小さな記事を読みたくなるでしょう:最も一般的な500のパスワード
わかりましたので、多分リストではありません正規の上の最も一般的なパスワードのリストの任意のシステムのどこか今まで、それは何の強制ポリシーが所定の位置に存在しないとき、人々が自分のパスワードを選択する方法が不十分の良い兆候です。さらに、最近盗まれたパスワードの公開されている分析と比較すると、リストは恐ろしく自宅に近いように見えます。
したがって、パスワードの強度に関する最低要件はなく、2%のユーザーが上位20の最も一般的なパスワードの1つを使用しています。意味:攻撃者が20回だけ試行した場合、Webサイトの50アカウントに1アカウントがクラッキング可能になります。
これを阻止するには、パスワードのエントロピーを計算してから、しきい値を適用する必要があります。国立標準技術研究所(NIST)の特別刊行物800-63には、非常に優れた提案がいくつかあります。つまり、辞書とキーボードレイアウト分析(たとえば、「qwertyuiop」は不適切なパスワードです)と組み合わせると、18ビットのエントロピーレベルで、不適切に選択されたすべてのパスワードの99%を拒否できます。パスワードの強度を計算し、ユーザーに視覚的な強度メーターを表示するだけで十分ですが、不十分です。強制されない限り、多くのユーザーはそれを無視するでしょう。
また、エントロピーの高いパスワードを使いやすくするために、Randall MunroeのPassword Strength xkcdを強くお勧めします。
Troy HuntのHave I Below Pwned APIを利用して、ユーザーのパスワードを、公開データ侵害で侵害されたパスワードと照合します。
パートVI:はるかに-または:即時起動ログイン試行の防止
最初に、数字を見てください:パスワード回復速度-パスワードはどれくらいの期間有効ですか
そのリンクのテーブルを確認する時間がない場合は、それらのリストを次に示します。
そろばんを使ってクラックしても、弱いパスワードをクラックするのにほとんど時間はかかりません
大文字と小文字を区別しない場合、英数字の9文字のパスワードをクラックするのに実質的に時間はかかりません
8文字未満の複雑な記号と文字と数字の大文字と小文字のパスワードを解読するのに実質的に時間はかかりません(デスクトップPCは、最大7文字のキースペース全体を検索できます)日または時間の)
ただし、1秒あたりの試行回数が1回に制限されている場合、6文字のパスワードを解読するのにも非常に時間がかかります。
では、これらの数字から何を学ぶことができるでしょうか?ええ、たくさんありますが、最も重要な部分に焦点を当てることができます。大量の高速な連続ログイン試行(つまり、ブルートフォース攻撃)を防止することは、実際にはそれほど難しくありません。しかし、それを正しく防止することは、思ったほど簡単ではありません。
一般的に、ブルートフォース攻撃(および辞書攻撃)に対して効果的な3つの選択肢がありますが、既に強力なパスワードポリシーを採用しているため、問題にはなりません。
N回の試行が失敗した後、CAPTCHAを提示します(地獄のように迷惑で、多くの場合無効ですが、ここでは繰り返します)。
N回の試行の失敗後にアカウントをロックし、電子メールの検証を要求する(これは、発生するのを待っているDoS攻撃です)
そして最後に、ログインスロットリング:つまり、N回の試行が失敗した後の試行間の時間遅延を設定します(そうです、DoS攻撃はまだ可能ですが、少なくとも攻撃の可能性ははるかに低く、引き離すのははるかに複雑です)。
ベストプラクティス#1:次のように、失敗した試行の数とともに増加する短い遅延時間。
- 1回失敗した=遅延なし
- 2回失敗した場合= 2秒の遅延
- 3回失敗した= 4秒の遅延
- 4回失敗した場合= 8秒の遅延
- 5回失敗した場合= 16秒の遅延
- 等
結果として生じるロックアウト時間は、以前のロックアウト時間の合計よりもわずかに長いため、このスキームを攻撃するDoSは非常に非実用的です。
明確にするために:遅延は、ブラウザーに応答を返す前の遅延ではありません。これは、特定のアカウントまたは特定のIPアドレスからのログイン試行がまったく受け入れられないか評価されないタイムアウトまたは不応期に似ています。つまり、ログインが成功しても正しい認証情報が返されず、誤った認証情報によって遅延の増加が引き起こされることはありません。
ベストプラクティス#2: N回の試行が失敗した後に有効になる中程度の時間遅延。
- 1〜4回失敗した場合=遅延なし
- 5回失敗した場合= 15〜30分の遅延
このスキームを攻撃するDoSは実際的ではありませんが、実行可能です。また、このような長い遅延は、正当なユーザーにとっては非常に煩わしいものであることに注意してください。忘れっぽいユーザーはあなたを嫌います。
ベストプラクティス#3: 2つのアプローチを組み合わせる-次のように、N回の試行が失敗した後に有効になる固定の短い遅延。
- 1〜4回失敗した場合=遅延なし
- 5回以上失敗した場合= 20秒の遅延
または、次のように上限が固定された遅延の増加。
- 1回失敗した場合= 5秒の遅延
- 2回失敗した= 15秒の遅延
- 3回以上の失敗= 45秒の遅延
この最終的なスキームは、OWASPのベストプラクティスの提案(MUST-READリストのリンク1)から取られたものであり、たとえそれが明らかに制限的な側面にあるとしても、ベストプラクティスと見なされるべきです。
しかし、経験則として、私は言うでしょう:パスワードポリシーが強力であるほど、遅延によるユーザーのバグを減らす必要があります。強力な(大文字と小文字を区別する英数字+必要な数字と記号)9文字以上のパスワードが必要な場合は、スロットリングをアクティブにする前に、ユーザーに遅延のないパスワードを2〜4回試行させることができます。
この最終ログインスロットルスキームを攻撃するDoSは、非常に非現実的です。そして最後の仕上げとして、永続的な(Cookie)ログイン(および/またはCAPTCHAで検証されたログインフォーム)の通過を常に許可するので、正当なユーザーが攻撃の進行中に遅れることもありません。このように、非常に非現実的なDoS攻撃は、非常に非現実的な攻撃になります。
さらに、管理アカウントは最も魅力的なエントリポイントであるため、管理アカウントでより積極的な調整を行うことは理にかなっています。
パートVII:分散ブルートフォース攻撃
余談ですが、より高度な攻撃者は、「アクティビティを分散させる」ことでログインスロットリングを回避しようとします。
ボットネットでの試行を分散してIPアドレスのフラグ付けを防止する
1人のユーザーを選んで50.000の最も一般的なパスワード(スロットルのためにできない)を試すのではなく、最も一般的なパスワードを選んで50.000人のユーザーに対して試行します。そうすることで、CAPTCHAやログインスロットリングなどの最大試行回数を回避できるだけでなく、最も一般的な1番目のパスワードが49.995よりもはるかに可能性が高いため、成功の可能性も高くなります。
各ユーザーアカウントのログインリクエストを30秒間隔で間隔をあけてレーダーの下に忍び込む
ここでのベストプラクティスは、失敗したログインの数をシステム全体でログに記録し、サイトの不正ログイン頻度の移動平均を、すべてのユーザーに課す上限の基準として使用することです。
抽象的すぎる?言い換えましょう:
サイトで過去3か月間、1日あたり平均120回の不正ログインがあったとします。これを使用して(移動平均)、システムはグローバル制限をその3倍に設定する可能性があります。24時間で360回失敗しました。次に、すべてのアカウントで失敗した試行の合計数が1日以内にその数を超えた場合(さらに良い場合は、加速率を監視し、計算されたしきい値でトリガーします)、システム全体のログインスロットルをアクティブにします。つまり、すべてのユーザーに短い遅延が発生します(ただし、Cookieログインおよび/またはバックアップCAPTCHAログインを除く)。
私はまた、詳細と質問を投稿し、分散型ブルートフォース攻撃をかわす際にトリッキーなピットフォールを回避する方法について非常に良い議論をしました
パートVIII:2要素認証および認証プロバイダー
悪用、パスワードの書き留めと紛失、鍵が盗まれたラップトップ、またはユーザーがフィッシングサイトにログインを入力することによって、認証情報が侵害される可能性があります。ログインは、2要素認証でさらに保護できます。これは、電話、SMSメッセージ、アプリ、ドングルから受信した使い捨てコードなどの帯域外要素を使用します。複数のプロバイダーが2要素認証サービスを提供しています。
認証は、シングルサインオンサービスに完全に委任できます。シングルサインオンサービスでは、別のプロバイダーが資格情報の収集を処理します。これにより、信頼できるサードパーティに問題が発生します。GoogleとTwitterはどちらも標準ベースのSSOサービスを提供していますが、Facebookは同様の独自のソリューションを提供しています。
ウェブ認証についての必読リンク
- OWASP認証ガイド / OWASP認証チートシート
- Webでのクライアント認証の推奨事項と禁止事項(非常に読みやすいMITリサーチペーパー)
- ウィキペディア:HTTP cookie
- フォールバック認証のための個人的な知識の質問:Facebookの時代のセキュリティに関する質問(非常に読みやすいバークレーの研究論文)