1. ホーム
  2. forms

[解決済み] フォーム型Webサイト認証の決定版【終了しました

2022-03-16 04:58:03

質問

<ブロッククオート

モデレーターの注意

この質問は、私たちの質問と回答のフォーマットである トピックルール 現在Stack Overflowに適用されているものです。私たちは通常、コンテンツにまだ価値があるような質問には、"履歴ロック" を使用します。しかし、この質問の回答は活発にメンテナンスされており、歴史的ロックは回答の編集を許可しません。そのため、答えの編集を可能にするために "wiki answer" ロックが適用されています。通常、履歴ロックによって処理される話題性の問題が存在すると考えるべきです(つまり、この質問はStack Overflowにとってオントピックな質問の良い例ではありません)。

Webサイトにおけるフォームベースの認証

私たちは、Stack Overflow は非常に特殊な技術的な質問のためのリソースであるだけでなく、一般的な問題のバリエーションを解決する方法に関する一般的なガイドラインであるべきだと考えています。

などのトピックが含まれているはずです。

  • ログイン方法
  • ログアウト方法
  • ログイン状態を維持する方法
  • Cookieの管理(推奨設定を含む)
  • SSL/HTTPSの暗号化
  • パスワードの保存方法
  • 秘密の質問の使用
  • ユーザー名・パスワード忘れ防止機能
  • 使用方法 ノンス を防ぐために クロスサイトリクエストフォージェリ(CSRF)
  • OpenID
  • 私を記憶する」チェックボックス
  • ユーザー名とパスワードのブラウザによる自動補完機能
  • シークレットURL(公開 URL ダイジェストで保護されている)
  • パスワードの強度を確認する
  • 電子メール検証
  • などなど フォームベース認証 ...

などを含んではならない。

  • 役割と権限
  • HTTP基本認証

ご協力お願いします。

  1. サブトピックの提案
  2. このテーマに関する良い記事を投稿する
  3. 公式回答の編集

解決方法は?

PART I: ログイン方法

ここでは、ログイン+パスワードのHTMLフォームを作成し、その値をサーバー側のスクリプトにPOSTして認証を行う方法を既に知っていると仮定します。以下のセクションでは、実用的な認証のパターンと、最も一般的なセキュリティの落とし穴を回避する方法について扱います。

HTTPSにするかしないか?

SSL/TLSを使用したHTTPS接続でない限り、ログインフォームの値は平文で送信され、ブラウザとウェブサーバの間の回線を盗聴する者は、通過するログイン情報を読み取ることができます。この種の盗聴は、政府によって日常的に行われていますが、一般的に、「所有されている」配線については、この点以外には触れません。HTTPS を使用すればよいのです。

要するに、唯一の 実用的 ログイン中の盗聴/パケットスニッフィングから保護する方法は、HTTPSまたは他の証明書ベースの暗号化スキーム(例えば。 TLS )または、実績のあるチャレンジ・レスポンス方式(例. ディフィー・ヘルマン -ベースのSRP)。 それ以外の方式は簡単に回避される 盗聴された攻撃者によって。

もちろん、少し非現実的になってもいいなら、何らかの二要素認証スキーム(Google Authenticatorアプリ、物理的な「冷戦型」暗号帳、RSA鍵生成ドングルなど)を採用することも可能です。正しく適用すれば、セキュリティで保護されていない接続でも機能しますが、開発者が2要素認証は実装するがSSLは実装しないということは考えにくいです。

(Do not) ロールユアオウンJavaScript暗号化/ハッシュ化

を考えると、(今はともかく 回避可能 SSL 証明書の設定にはコストと技術的な困難が伴うため、開発者の中には、安全でないワイヤーを介して平文でログインすることを避けるために、ブラウザ内で独自のハッシュ化または暗号化スキームを作成したくなる人がいます。

これは立派な考えですが、基本的には役に立ちません( セキュリティ上の欠陥 つまり、強力な暗号化で回線を保護するか、試行錯誤を重ねたチャレンジ・レスポンス・メカニズム(これが何であるか知らなければ、デジタル・セキュリティにおいて最も証明が難しく、最も設計が困難で、最も実装が難しい概念の1つであることだけを知っておいてください)を使用するか、のどちらかと組み合わせなければ、それはできないのです。)

確かにパスワードのハッシュ化は ができる。 に対して有効です。 パスワード開示 しかし、リプレイ攻撃、中間者攻撃/ハイジャック(攻撃者が安全でないHTMLページに数バイトを注入し、それがブラウザに届く前に、彼らは単にJavaScriptのハッシュをコメントアウトすることができる)、またはブルートフォース攻撃(あなたが攻撃者にユーザー名、塩、ハッシュ化したパスワード両方を渡しているので)に対して脆弱性があります。

人道に反するCAPTCHAS

キャプチャ(CAPTCHA は、ある特定のカテゴリーの攻撃を阻止するためのものです。それは、人間が操作しない自動化された辞書/ブルートフォースの試行錯誤です。しかし、CAPTCHAを使わずにシームレスに対処する方法があります。特に、適切に設計されたサーバーサイドのログイン制限スキームについては、後で説明します。

CAPTCHAの実装は一様ではないことを知っておいてください。多くの場合、人間が解くことはできず、そのほとんどはボットに対して効果がありません。 オワスプ また、一部の実装は国によっては技術的に違法となる場合があります( OWASP認証チートシート ). どうしてもCAPTCHAを使いたい場合は、Googleの reCAPTCHA なぜなら、それは定義上OCR困難であり(すでにOCRで誤分類された本のスキャンを使用しているため)、ユーザーフレンドリーであろうと懸命になっているからです。

個人的には、CAPTCHAS は迷惑だと思う傾向があり、ユーザーが何度もログインに失敗し、スロットリングの遅延が最大になったときの最終手段としてのみ使用します。これは許容できるほど稀なことであり、システム全体を強化するものです。

パスワードの保存/ログインの確認

近年、ハッキングやユーザー情報の流出が盛んに行われているので、ようやく常識になったかもしれませんが、言っておかなければならないことがあります。データベースには、パスワードを平文で保存しないでください。ユーザーデータベースは、SQLインジェクションによって日常的にハッキング、漏洩、盗聴されており、生の平文パスワードを保存している場合、ログインの安全性は即座に失われてしまいます。

では、パスワードを保存できない場合、ログインフォームからPOSTされたログインとパスワードの組み合わせが正しいかどうか、どのように確認するのでしょうか。その答えは 鍵の導出機能 . 新しいユーザが作成されたり、パスワードが変更されたりするたびに、そのパスワードをArgon2、bcrypt、scrypt、PBKDF2などのKDFに通して、平文のパスワード("correcthorsebatterystaple")を長くランダムな感じの文字列に変え、データベースに保存するのをより安全にするのです。ログインを確認するには、入力されたパスワードに対して同じハッシュ関数を実行し、今度はソルトを渡して、結果のハッシュ文字列をデータベースに保存されている値と比較します。Argon2、bcrypt、scryptはすでにソルトをハッシュと一緒に保存しています。これをチェックアウトする 記事 sec.stackexchangeでより詳しい情報をご覧ください。

ソルトを使用する理由は、ハッシュだけでは十分ではないからです。 レインボーテーブル . ソルトは、完全に一致する2つのパスワードが同じハッシュ値として保存されることを効果的に防ぎ、攻撃者がパスワード推測攻撃を実行した場合に、データベース全体が一度にスキャンされることを防止することができます。

暗号ハッシュはパスワードの保存に使うべきではない。なぜなら、ユーザーが選択したパスワードは十分に強くなく(つまり、通常は十分なエントロピーを含まない)、ハッシュにアクセスできる攻撃者は比較的短時間でパスワード推測攻撃を完了させることができるからである。このため、KDFが使用される。KDFは効果的に 鍵を引き伸ばす。 つまり、攻撃者がパスワードを推測するたびに、ハッシュアルゴリズムが複数回、例えば1万回繰り返され、攻撃者がパスワードを推測するスピードが1万回分遅くなるのです。

セッションデータ - "You are logged in as Spiderman69"

サーバーがログイン名とパスワードをユーザーデータベースと照合して一致することを確認したら、システムはブラウザが認証されたことを記憶する方法が必要です。この事実は、サーバー側のセッションデータにのみ保存されるべきです。

<ブロッククオート

セッションデータについてよくご存じない方のために、その仕組みを説明します。ランダムに生成された1つの文字列が期限切れのクッキーに保存され、サーバーに保存されているデータの集合体であるセッションデータを参照するために使用されます。MVCフレームワークを使用している場合、これは間違いなくすでに処理されています。

可能な限り、ブラウザに送信されるとき、セッションクッキーにセキュアとHTTP Onlyフラグが設定されていることを確認してください。HttpOnly フラグは、XSS 攻撃によってクッキーが読み取られることに対する何らかの保護を提供します。secure フラグは、クッキーが HTTPS 経由でのみ送り返されることを保証し、したがってネットワーク・スニッフィング攻撃か ら保護します。クッキーの値は予測可能であってはなりません。存在しないセッションを参照するクッキーが提示された場合、その値を直ちに置き換えて、以下のことを防ぐ必要があります。 セッションの固定化 .

セッションの状態は、クライアント側でも維持することができます。これは、JWT(JSON Web Token)のような技術を使用することで実現されます。

PART II: ログインを維持する方法 - 悪名高きチェックボックス「リメンバー・ミー

永続的ログイン・クッキー(quot;remember me"機能)は危険地帯です。一方では、ユーザーがその扱い方を理解していれば従来のログインとまったく同じように安全ですが、他方では、公共のコンピューターで使用してログアウトするのを忘れたり、ブラウザ・クッキーとは何か、その削除方法は知らないという不注意なユーザーの手にかかれば、大きなセキュリティリスクとなるのです。

個人的には、定期的に訪れるWebサイトでは永続的なログインが好きですが、それを安全に扱う方法は知っています。ユーザーが同じことを知っていると確信しているのであれば、良心に則って永続的ログインを使用することができます。そうでない場合は、ログイン認証に無頓着なユーザーがハッキングされるのは自業自得という考え方に賛同できるかもしれません。私たちがユーザーの家に行って、モニターの端に並べられたパスワードの書かれた顔面蒼白のポスト・イット・ノートを全部引き剥がすようなことはしませんよ。

もちろん、システムによっては どんな そのようなシステムでは、永続的なログインを正当化することはできません。

もし、永続的ログインクッキーを実装することに決めたら、こうしてください。

  1. まずは、じっくりとお読みください。 パラゴン・イニシアティブの記事 についてです。多くの要素を正しく理解する必要がありますが、この記事ではそれぞれについて見事に説明しています。

  2. そして、よくある落とし穴のひとつを改めてご紹介しておきます。 永続的なログインクッキー(トークン)をデータベースに保存しないでください。 ログイン・トークンはPassword Equivalentなので、もし攻撃者があなたのデータベースを手に入れたら、トークンを使って、あたかも平文のログイン・パスワードの組み合わせのように、あらゆるアカウントにログインすることができます。そのため、ハッシュ化( https://security.stackexchange.com/a/63438/5002 永続的なログイン・トークンを保存する場合は、弱いハッシュで十分です。

パート III: 秘密の質問の使用

秘密の質問」を実装してはいけない . 秘密の質問」機能は、セキュリティのアンチパターンです。必読リストの4番目のリンクから論文を読んでみてください。サラ・ペイリンに聞くといい。以前の大統領選でヤフーのメールアカウントがハッキングされたとき、彼女のセキュリティ質問の答えが... "Wasilla High School"だったからだ!

ユーザー指定の質問であっても、ほとんどのユーザーがどちらかを選ぶ可能性が高い。

  • 母親の旧姓や好きなペットなど、「定番」の秘密の質問

  • ブログやLinkedInのプロフィールなど、誰もが知っているような簡単なトリビア。

  • パスワードを推測するよりも簡単に答えられるような質問。まともなパスワードであれば 想像できる限りの質問です

結論として、セキュリティ質問は、事実上すべての形式とバリエーションにおいて本質的に安全ではないので、いかなる理由であれ、認証スキームに採用されるべきではない。

セキュリティ・クエスチョンが野放しにされている本当の理由は、電子メールにアクセスできず、再アクティベーションコードにたどり着けないユーザーからのサポートコールのコストを、都合よく数回分削減するためです。これは、セキュリティとサラ・ペイリンの評判を犠牲にしてのことです。その価値は?おそらく、そうではないでしょう。

PART IV: パスワード忘れ防止機能

というのは、すでに述べたとおりです。 セキュリティ質問を使用しない また、実際のパスワードをユーザーにメールしてはいけないことは言うまでもありません。この分野では、あと2つほど、避けるべき落とし穴があります。

  1. 禁止事項 リセット このようなパスワードは覚えにくいので、ユーザーはパスワードを変更するか、モニターの端にある明るい黄色のポストイットに書き留める必要があります。新しいパスワードを設定する代わりに、ユーザーがすぐに新しいパスワードを選べるようにすればよいのです - どうせユーザーはそうしたいはずです。(新しいパスワードを設定する代わりに、ユーザーがすぐに新しいパスワードを選べるようにすればよいのです。(ただし、メモをしないと覚えられないようなパスワードをパスワードマネージャーで保存・管理している場合は例外です。)

  2. 紛失したパスワードコード/トークンを常にデータベースでハッシュ化する。 AGAIN このコードもPassword Equivalentの一種であり、攻撃者がデータベースを入手した場合に備えてハッシュ化しなければなりません。紛失したパスワードのコードが要求されたら、平文のコードをユーザーのメールアドレスに送り、それをハッシュ化してデータベースに保存します -- そして オリジナルを捨てる . パスワードや永続的なログイン・トークンと同じようにです。

最後に、「パスワード紛失コード」を入力するためのインターフェースは、少なくともログインフォーム自体と同じくらい安全であることを常に確認してください。非常に長い「パスワード紛失コード」(例えば、大文字と小文字を区別する16文字の英数字)を生成することは良いスタートですが、ログインフォーム自体に行うのと同じスロットルスキームを追加することを検討してみてください。

PART V: パスワードの強度をチェックする

まず、この小さな記事を読んで、現実を確認しましょう。 最も一般的なパスワード500

では、このリストは 正準 で最も一般的なパスワードのリスト 任意 システム どこまでも しかし、これは、強制的なポリシーがない場合に、人々がいかに不適切なパスワードを選択するかを示す良い指標となります。さらに、最近盗まれたパスワードの公開分析と比較すると、このリストは恐ろしく身近なものに見えます。

そこで パスワード強度の最低条件がない場合、2%のユーザーが最も一般的なパスワード上位20個のうちの1つを使用しています。つまり、攻撃者が20回試行すれば、あなたのウェブサイトの50アカウントに1アカウントはクラック可能ということになります。

これを阻止するためには、パスワードのエントロピーを計算し、閾値を適用する必要があります。 米国国立標準技術研究所(NIST)は 特別刊行物800-63 には、非常に優れた提案があります。 それを辞書やキーボードレイアウトの分析(たとえば、「qwertyuiop」は悪いパスワード)と組み合わせると、次のようになります。 不適切に選択されたパスワードの99%を拒否する 18ビットのエントロピーレベルで。 単純にパスワードの強度を計算し 強度メーターを表示する は良いが、不十分である。 強制されない限り、多くのユーザーはそれを無視する可能性が高いでしょう。

また、ハイエントロピーのパスワードの使いやすさについては、Randall Munroeの パスワードの強さ xkcd がおすすめです。

トロイ・ハント(Troy Hunt)の Have I Been Pwned API を使用して、ユーザーのパスワードと公的なデータ漏洩で漏れたパスワードとを照合します。

PART VI: Much More - Or: Preventing Rapid-Fire Login Attempts (ログイン失敗を防ぐ)

まず、数字を見てください。 パスワードの復旧速度 - あなたのパスワードはどのくらい持ちこたえますか?

そのリンク先の表に目を通す時間がなければ、ここにそのリストがあります。

  1. かかるのは ほぼノータイム 弱いパスワードは、そろばんで割るとしても

  2. 必要なのは ほぼノータイム の場合、9文字の英数字のパスワードを解読することができます。 ケースインセンシティブ

  3. が必要です。 ほぼノータイム 記号と文字と数字、大文字と小文字が混在する複雑なパスワードを解読するには、それが 8文字以下 (デスクトップPCなら7文字までのキースペースは数日から数時間で全探索可能)。

  4. しかし、6文字のパスワードでさえも解読するには膨大な時間がかかる。 1秒間に1回の試行回数に制限されている場合。

では、この数字から何がわかるのでしょうか。それは、大量の連続ログイン試行を防ぐことです。 ブルートフォース 攻撃)は、実はそれほど難しいことではありません。しかし、それを防ぐには は、見た目ほど簡単ではありません。

一般的に、ブルートフォース攻撃に対して有効な3つの選択肢があります。 (辞書攻撃もありますが、すでに強力なパスワードポリシーを採用しているので、問題にはならないでしょう)。 :

  • をプレゼント キャプチャ N回失敗した後(地獄のように迷惑で、しばしば効果的ではありませんが、私はここで自分自身を繰り返しています)。

  • アカウントのロック と、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のベストプラクティスの提案(必読リストのリンク1)から引用したもので、たとえそれが制限的な側面を持っていることは認めるとしても、ベストプラクティスとみなされるべきものです。

<ブロッククオート

しかし、経験則から言うと、パスワードポリシーが強固であればあるほど、ユーザーを困らせる必要はありません。9文字以上の強力なパスワード(大文字小文字を区別する英数字+必要な数字と記号)を要求する場合、スロットリングを有効にする前に、ユーザーに2~4回の遅延のないパスワード試行をさせることができます。

この最終的なログイン制限方式をDoS攻撃する場合、以下のようになります。 非常に 非現実的です。そして最後の仕上げとして、常に永続的な(クッキー)ログイン(および/またはCAPTCHAで検証されたログインフォーム)を許可して、正当なユーザーが遅延することさえないようにすることです。 攻撃進行中 . そうすれば、非常に非現実的な DoS 攻撃が 極めて 非実用的な攻撃です。

さらに、管理者アカウントは最も魅力的なエントリーポイントであるため、より積極的なスロットリングを行うことは理にかなっています。

PART VII:分散型ブルートフォース攻撃

余談ですが、より高度な攻撃者は「活動を分散させる」ことでログイン制限を回避しようとします。

  • IPアドレスのフラグを防ぐため、ボットネット上で試行を分散させる。

  • 1人のユーザーを選んで5万件の最も一般的なパスワードを試すのではなく(スロットリングのため、それはできません)、最も一般的なパスワードを選び、代わりに5万人のユーザーに対してそれを試すのです。そうすれば、CAPTCHAやログイン制限などの最大試行回数を回避できるだけでなく、最も一般的なパスワードの第1位は49.995位よりもはるかに可能性が高いので、成功する確率も高くなります。

  • 各ユーザーアカウントのログイン要求を30秒間隔にするなどして、レーダーをかいくぐる。

ここで、ベストプラクティスは次のようになります。 ログインに失敗した回数をシステム全体でログに記録する。 そして、サイトの不正ログインの頻度の平均値をもとに、すべてのユーザーに上限を設定します。

抽象的すぎる?言い直します。

あなたのサイトでは、過去3ヶ月間、1日平均120件の不正ログインがあったとします。その平均値をもとに、グローバルリミットをその3倍、つまり24時間で360回に設定することができます。そして、1日以内にすべてのアカウントで失敗した試行の合計数がその数を超えた場合(あるいは、加速度を監視し、計算された閾値でトリガーするのがより良い)、システム全体のログインスロットルをアクティブにします - すべてのユーザーに短い遅延を意味します(それでも、クッキーログインやバックアップCAPTCHAログインは例外です)。

との質問も投稿しています。 の詳細とトリッキーな落とし穴を回避する方法についての実に良い議論です。 分散ブルートフォースアタックを回避するために

PART VIII: 二要素認証と認証プロバイダ

パスワードの紛失、鍵付きのノートパソコンの盗難、フィッシングサイトへのログインなど、情報漏えいの危険はつきものです。 電話やSMSメッセージ、アプリ、ドングルから受け取った1回限りのコードなど、帯域外の要素を使用する2要素認証で、ログインをさらに保護することができます。複数のプロバイダーが二要素認証のサービスを提供しています。

認証はシングルサインオンサービスに完全に委ねることができ、認証情報の収集は別のプロバイダーが行う。この場合、問題は信頼できるサードパーティに押し付けられる。GoogleとTwitterは標準ベースのSSOサービスを提供しており、Facebookは同様の独自ソリューションを提供している。

ウェブ認証に関する必読のリンク集

  1. OWASP Guide To Authentication(認証の手引き / OWASP認証チートシート
  2. Web上のクライアント認証の注意点(とても読みやすいMITの研究論文です。)
  3. ウィキペディア HTTP クッキー
  4. フォールバック認証のための個人的な知識の質問。Facebook時代のセキュリティ質問(非常に読みやすいバークレー校の研究論文)