Webアプリケーションにおける脆弱性についてまとめる
今回はWebアプリケーションにおける脆弱性について、どんなものがあるのか、何が原因でどのような対策をとるべきなのかについて書いていきたいと思います。今まで体系的に勉強したことがなく、今回は基本的なことをサラッとまとめてみた形で、あまり深掘りしていないのでご了承ください。
脆弱性とは
まず初めに、そもそもWebアプリケーションにおける脆弱性とは何なのかについて書いていきたいと思います。Webアプリケーションにおける脆弱性とは、攻撃者がアプリケーションを悪用して不正な活動を行うために利用できるセキュリティ上の弱点(バグ)のことを指します。これらの脆弱性を突かれると、データの盗難、改ざん、サービスの停止、権限昇格など、さまざまなセキュリティインシデントが発生する可能性があります。また、意図的な悪用以外にも偶然発生したバグの影響で発生するセキュリティ上の事故(本来見えるべきでない個人情報などがユーザーに見えてしまうなど)なども脆弱性と呼ばれます。
脆弱性に起因する悪影響
脆弱性があるとどんな悪影響があるでしょうか。まず大きなものとして金銭的な損失があげられます。損害賠償請求がされることやサービスの停止、信用失墜による金銭的損失が発生する可能性もあります。法的な責任を負うことになる場合もありますし、自社だけでなく利用者の個人情報などが流出することによって、利用者に多大な悪影響を及ぼすことも考えられます。自社サイトを悪用されて利用者に攻撃を仕掛ける土台にされてしまうこともあり、自社だけでなく多くの人に悪影響を与える可能性があるのが脆弱性の怖さです。
脆弱性や攻撃手法
それではここからWebアプリケーションにおける脆弱性や攻撃手法にはどのようなものがあるかについて書いていきます。
SQLインジェクション
SQLインジェクションは、攻撃者が悪意のあるSQLコードをWebアプリケーションへ不正に注入(インジェクション)し、データベースシステムを不正操作する攻撃手法です。具体的にはWebアプリケーションの入力フォームやURLなどにSQL文の断片を埋め込むことで、データベースを改ざんしたり不正に情報を入手することです。
原因
SQLインジェクションが発生する原因は、SQLの呼び出し方に不備があることです。ユーザーからの入力をそのままSQLクエリに組み込むようにしていたり、ユーザーの入力に含まれる特殊文字を適切にエスケープする処理が実装できていなかったりした場合にSQLインジェクションが発生します。ここでいう特殊文字には以下のようなものがあげられます。
シングルクォート 「'」 | SQLクエリ内で文字列リテラルを定義する際に使用される。 |
セミコロン 「;」 | SQL文の終了を示すために使用される。 |
バックスラッシュ 「\」 | エスケープ文字として使用されることがある。 |
パーセント記号 「%」 | SQLのLIKE句で使用されるワイルドカード。 |
対策
SQlインジェクションを防ぐための対策には以下のようなものがあげられます。
- プレースホルダーを利用する
プレースホルダーとはユーザーが値を入力するまでの仮の値のようなもので、以下のSQL分の?
がそれにあたります。
"SELECT * FROM users WHERE user_id = ?", user_input
このSQL文の中の?
はユーザーからの入力(user_input)に適切に置き換えられます。ユーザーの入力が適切にエスケープされるため、SQLインジェクション攻撃のリスクが劇的に減少します。
- 適切なエラーメッセージを表示する
エラーメッセージにデータベースの内容などを含めてしまうと、データ構造を推測する手がかりになってしまいます。そのためエラーメッセージには攻撃の手助けになるような情報を含めないようにすることが重要です。
クロスサイトスクリプティング(XSS)
クロスサイトスクリプティング(XSS)は、攻撃者が悪意のあるコードをWebページに仕掛け、他のユーザーのブラウザ上でそのスクリプトが実行されるようにするセキュリティ攻撃です。Webページに悪意のあるリンクを埋め込み、それを他のユーザーがクリックするとCookie情報が盗まれたり、Web上の掲示板などにコメントとして悪意のあるスクリプトを残すことで、他のユーザーが訪れるたびに悪意あるスクリプトが実行されたりすることを言います。
原因
クロスサイトスクリプティングの脆弱性が発生する原因は、ユーザーからの入力をWebページが検証やエスケープせずにそのまま受け付ける状態になってしまっていることです。そのため、攻撃者が悪意のあるコードを埋め込むとその意図通りに動作してしまい、機密情報の盗難や罠サイトへの誘導が行われてしまいます。
対策
クロスサイトスクリプティングを防ぐための対策には以下のようなものがあげられます。
-
エスケープ処理
クロスサイトスクリプティング攻撃は、攻撃者が実行可能な悪意のあるコードをWebページに埋め込むことが原因で発生するので、そのような文字列が実行されないようにすることが対策としてあげられます。具体的にはHTML文においては(<)(>)(&)(")(')
、JavaScript文においては(\)(")(')(\n)
のようなHTML文やスクリプトの記述に必要な文字をエスケープする必要があります。 -
入力値を制限する
そもそものユーザーが入力できる値を制限するのも対策の一つです。名前などは漢字やひらがなのみ、郵便番号や電話番号は数字のみにしたり、入力できる文字数の上限を設定するなどの制限をかけることが有効です。 -
CookieにHTTPOnly属性を付与する
クロスサイトスクリプティング攻撃の典型例であるCookieの盗難防止のために、CookieにHTTPOnly属性を付与することも有効です。こうすることでJavaScriptからCookieを読み出すことができなくなります。ただこれは限定的な防御手法なので、その他の対策も講じる必要があります。
DOM Based XSS
DOM Based XSSは上に書いたクロスサイトスクリプティング脆弱性がJavaScript起因で発生する場合を言います。
原因
DOM Based XSSはWebアプリケーションがユーザーからの入力をDOMの一部として扱い、その入力を適切に無害化せずに処理することで発生します。攻撃者は、URLのパラメータ、フォーム入力、あるいはその他の方法で悪意のあるスクリプトを注入し、このスクリプトが被害者のブラウザ上で実行されるように仕向けます。
対策
DOM Based XSSを防ぐための対策には以下のようなものがあげられます。
-
適切なエスケープ処理を行う
これはクロスサイトスクリプティングにもありましたが、脆弱性の原因になる箇所に適切なエスケープ処理を施すことで攻撃を防ぐことができます。 -
フレームワークやライブラリを利用する
フロントエンドのフレームワークやライブラリはDOM Based XSS攻撃を防ぐ機能が搭載されています。バージョン管理もしっかりと行い、セキュリティに問題ないバージョンを使用するようにすることで攻撃を防ぐことができます。
クロスサイトリクエストフォージェリ(CSRF)
クロスサイトリクエストフォージェリ(CSRF)は攻撃者がWebアプリケーションなどにログインした状態のユーザーを罠サイトに誘導することで、ユーザーが意図しない重要なアクションをユーザーのログイン状態を利用してWebアプリケーション上で行わせる攻撃です。攻撃者は攻撃用Webページを準備し、ログイン後のユーザーがアクセスするよう誘導します。ユーザーが攻撃用Webページにアクセスすると、攻撃用Webページ内にあらかじめ用意されていた不正なリクエストが攻撃対象のWebアプリケーションなどに送られます。攻撃対象のWebアプリケーションは不正なリクエストを処理し、ユーザーが意図していない処理が行われてしまいます。
原因
クロスサイトリクエストフォージェリ攻撃は、Webアプリケーションが自動的にユーザーのセッションを使用してリクエストを認証する挙動を悪用しています。重要な処理の実行を求めるリクエストについてもセッション情報だけをもとに認証を行い、ユーザー本人による正規の手順を踏んだリクエストであるかの確認を行わない場合、クロスサイトリクエストフォージェリ攻撃を受けてしまう可能性があります。
対策
クロスサイトリクエストフォージェリを防ぐための対策には以下のようなものがあげられます。
-
トークンを利用する
クロスサイトリクエストフォージェリ対策が必要なページに対して、攻撃者が知ることができないトークンを要求することで不正なリクエストを受け付けないようにすることができます。このトークンはユーザーがログインする際などに作成されクライアントに送信されます。それを重要な処理のリクエストを受け付ける際に検証することで不正なリクエストの実行を防ぐことができます。 -
信頼性の高いWebアプリケーションフレームワークを利用する
現代の主要なWebアプリケーションフレームワークやライブラリであれば、適切なクロスサイトリクエストフォージェリ対策が施されていることが多いです。開発の際に信頼性の高いWebアプリケーションフレームワークを利用することで簡単に安全なWebアプリケーションを作成することができます。 -
パスワードの再入力を要求する
特に重要な処理を行う際にパスワードの再入力を求めるのも対策として有効です。攻撃者が利用するのはセッション情報であり、パスワードなどの機密情報そのものが漏れているわけではないので、この方法も有効な対策の一つになります。再入力の手間が発生しますが、特に重要な処理(金銭のやり取りが発生するような処理など)で利用されることが多いです。
セッションハイジャック
セッションハイジャックは、攻撃者がユーザーのセッションIDを盗み取り、そのユーザーになりすます攻撃です。これにより、攻撃者は被害者のアカウントを不正に操作したり、機密情報にアクセスしたりすることができます。
原因
セッションハイジャックはサーバーが生成するセッションIDが規則的に作成されている場合、それを推測し、総当たり攻撃なども組み合わせてセッションIDが特定されることで発生する場合があります。また、攻撃者が生成したリンクやフォームを介することで、攻撃者が事前に設定したセッションIDがブラウザに設定されてしまうこともあります。先ほど書いたクロスサイトスクリプティングによってセッションIDが盗み出される場合もあります。
対策
セッションハイジャックを防ぐための対策には以下のようなものがあげられます。
-
セッションIDが予測不能な乱数になるようにする
推測可能なセッションID(日時やユーザー情報などをもとに作成したもの)が設定されるようになっているとセッションハイジャックの危険性が高まるので、複雑な乱数を生成してくれるセッション管理機構を利用すべきです。これは主要なWebアプリケーションフレームワークにはデフォルトで備わっていることも多いので、セッションIDの生成にはそれらを使うようにしましょう。 -
ログイン成功時にセッションIDを変更する
セッションIDが攻撃者が事前に設定したセッションIDに固定されてしまうことを防ぐために、ユーザー認証が成功したらセッションIDを変更することもセッションハイジャックを防ぐ方法の一つです。攻撃者の意図するセッションIDはログイン処理前に付与されるので、それをログイン処理が成功したタイミングでリセットすることでセッションハイジャックを防ぐことができます。
オープンリダイレクト
オープンリダイレクトは、Webアプリケーションがユーザーをリダイレクトする際に、外部ドメインへの無制限なリダイレクトを許可してしまうセキュリティの脆弱性です。攻撃者はこの脆弱性を悪用して、信頼できるサイトから悪意のあるサイトへユーザーをリダイレクトさせ、そこで個人情報の入力を促すなどして情報を取得しようとします。
原因
オープンリダイレクトの脆弱性は、リダイレクト先のURLを指定するクエリパラメータやフォーム入力がWebアプリケーションによって適切に検証されない場合に発生します。例えば、ログイン後にユーザーをリダイレクトする機能があるwebアプリケーションが、リダイレクト先URLを指定するクエリパラメータをそのまま受け入れてしまうと、攻撃者は任意の外部サイトへのリダイレクトを仕掛けることができます。例えば以下のような攻撃用のURLがあるとします。
https://example.com/login?redirect=https://steal.com
このURLは、最初にユーザーを信頼できるexample.comのログインページに遷移させます。ログイン成功後、ユーザーは攻撃者が指定したsteal.comへリダイレクトされます。ユーザーは、example.comからリダイレクトされたため、steal.comを信頼してしまい、機密情報を盗まれるリスクがあります。
対策
セッションハイジャックを防ぐための対策には以下のようなものがあげられます。
-
リダイレクト先のURLを固定する
リダイレクト処理を行う際には、ユーザー入力に基づくリダイレクトを避け、アプリケーション内で定義されたURLに基づいてリダイレクトを行うようにすることで悪意のあるサイトへの遷移を防ぐことができます。 -
リダイレクト先のドメイン名やURLを検証する
リダイレクト先のドメインやURLを事前に定義したリストに基づいて検証し、承認されたドメイン名やURLのみにリダイレクトするようにします。ただし、この検証は場合によってはすり抜けられてしまう可能性があるのであまり厳格な方法とは言えません。 -
外部サイトへリンクする場合は警告メッセージを表示する
どうしても外部サイトへのリダイレクトが必要な場合は、リダイレクト前にユーザーに警告し、リダイレクト先がアプリケーション外のサイトであることを明示することが有効です。これによりユーザーの警戒心が増し、適切なページに遷移しているかどうかの確認を促すことができます。
ディレクトリトラバーサル
ディレクトリトラバーサル攻撃は、攻撃者がWebアプリケーションが意図していないディレクトリに不正な手段でアクセスし、それを閲覧・操作する攻撃手法です。サーバー上のファイル名を外部から指定できる仕様になっている場合にこの攻撃が可能になる場合があります。
原因
ディレクトリトラバーサルの脆弱性は、Webアプリケーションがファイルのパスを指定するためにユーザーからの入力(URLパラメータ、フォーム入力など)を使用する場合に発生します。例えば攻撃者が以下のようなURLを使って機密情報の入ったファイルにアクセスしてくるとします。
http://example.com/app?page=../../etc/password
この例では、攻撃者は../../etc/passwordというパスを使用して、/etc/passwordファイル(Linuxシステム上のユーザーアカウント情報を含むファイル)へのアクセスを試みます。Webアプリケーションがこの入力を適切に検証せずにファイルを読み込む場合、攻撃者はこのファイルの内容を閲覧できる可能性があります。
対策
ディレクトリトラバーサル攻撃を防ぐための対策には以下のようなものがあげられます。
-
外部からファイル名を指定できる仕様を無くす
ファイル名を外部から指定できないようにすればディレクトリトラバーサル攻撃を受ける危険性は無くなります。パラメーターに依存せずに固定化したファイル名を利用する仕様にすることで実現可能です。 -
ユーザー入力を検証する
ユーザー入力の検証を行い、相対パスを指定するために用いられる(..)などを使用不可にすることで相対パスの指定ができなくなり、相対パスを使ったアクセスができないようにすることができます。
メールヘッダインジェクション
メールヘッダインジェクションは、Webアプリケーションの用意したメール送信機能の、メールの件名や宛先メールアドレス入力部分に改行文字を利用して本文やメールヘッダを改変する攻撃手法です。これにより送信元や本文を改変されたり、迷惑メールやウイルスを含んだメールの送信に悪用されたりしてしまう恐れがあります。例えば、攻撃者がメールアドレス入力フィールドに以下のような値を入力することを考えます。
victim@example.com%0A%0ABcc: attacker@example.com
%0A
は改行文字をURLエンコードしたものです。アプリケーションがこの入力をそのままメールの「To」ヘッダに組み込んだ場合、改行によりヘッダが終了し、新たに「Bcc」ヘッダが挿入されることになります。結果として、本来の受信者に加えて攻撃者もメールのコピーを受け取ることになります。Bccを他のアドレスに変更すれば対象のメールアドレスの持ち主に悪意のあるメールを送信することもできてしまいます。
原因
メールヘッダインジェクションの原因はメールのメッセージヘッダを改行できる仕様になってしまっていることです。メールヘッダのフィールドは改行で区切られているため、外部から改行できると新たなヘッダを追加できてしまうので、それが脆弱性の原因になります。
対策
メールヘッダインジェクションを防ぐための対策には以下のようなものがあげられます。
-
メールヘッダは外部からのパラメータを受け付けないようにする
メールヘッダに外部からの値を受け付けることがメールヘッダインジェクションの根本原因なので、メールヘッダは外部からのパラメータを受け付けず、パラメーターは本文にのみ反映させるようにすることが対策としてあげられます。 -
メールヘッダに埋め込む文字列に改行コードを許可しない
メールヘッダに外部からのパラメーターを受け付けるとしても、改行コードを許可しなければメールヘッダインジェクションを防ぐことができます。 -
安全なメール送信用のライブラリを利用する
メール送信処理の実装をライブラリに任せてしまうのも手です。コスト低く実践できる上に効果も高い対策です。
HTTPヘッダインジェクション
HTTPヘッダインジェクションは、HTTPレスポンスヘッダに不正な内容を挿入する攻撃手法のことです。これにより攻撃者はユーザーのセッションハイジャック、クロスサイトスクリプティング (XSS)、リダイレクト攻撃など、さまざまな攻撃を実施することが可能になります。
原因
HTTPヘッダインジェクション脆弱性が発生する原因は、上のメールヘッダインジェクションと同じような理由で、HTTPレスポンスヘッダを外部からのパラメーターによって改行できるようになっていることです。
対策
HTTPヘッダインジェクションでの被害を防ぐための対策には以下のようなものがあげられます。
-
外部からのパラメーターをHTTPレスポンスヘッダに含めない
外部からのパラメーターをHTTPレスポンスヘッダに含めないように実装することで、HTTPヘッダインジェクション攻撃を防ぐことができます。多くの場合は設計を見直せばこの変更は可能なので、しっかりと対策をとるようにしましょう。 -
HTTPレスポンスヘッダに出力される改行をエスケープする
主要なフレームワークやライブラリなどはHTTPレスポンスヘッダを適切に出力するようになっているので、それらを活用してHTTPレスポンスヘッダにパラメーターを出力する際にも適切な処理が行われる状態を作っておきましょう。
Dos/DDos攻撃
Dos攻撃はWebサイトやサーバーに対して意図的に過剰な負荷をかけ、対象のシステムのリソースを枯渇させて、サービスの提供を妨害する攻撃です。Dos攻撃は1台のコンピューターから攻撃を仕掛ける手法で、複数のコンピューターから同時に攻撃を行う手法をDDos攻撃と言います。
原因
Dos攻撃は直接的にWebアプリケーションの脆弱性が原因になるというものではありません。しかし、攻撃を受けることを想定して対策は取っておくべきでしょう。
対策
Dos攻撃での被害を防ぐための対策には以下のようなものがあげられます。
-
リクエスト数を制限する
特定の条件範囲内で許可されるリクエスト数を制限することで、DoS攻撃のような悪意あるトラフィックの影響を軽減し、サービスを保護することができます。この条件には一定の時間枠(例えば1分間)や過去一定期間内のリクエスト履歴などで、サービス側で設定することになります。 -
同一IPアドレスからのアクセス制限
攻撃を仕掛けるIPアドレスを特定し、そのIPアドレスからのアクセスを遮断すれば攻撃による負荷を防ぐことができます。DDos攻撃については抜本的な対策にまではならずとも被害の軽減には役立ちます。 -
トラフィック分析とフィルタリング
異常なトラフィックパターンを検出する仕組みを作っておき、攻撃と思われるトラフィックをブロックまたは制限することで過剰な負荷がかかることを防ぐことができます。
OSコマンドインジェクション
OSコマンドインジェクションとは、外部からサーバのOSコマンドを不正に実行する攻撃手法のことです。OSに対してさまざまな攻撃を受ける可能性があり、サーバーを攻撃者に制御されてしまう可能性もあるので非常に危険です。
原因
OSコマンドインジェクションの脆弱性は、シェルを操作できる言語(Perl等)を使用している場合に発生します。アプリケーションの中でシェルを呼び出す関数を利用し、その関数にパラメータを渡すときにパラメーターに含まれるメタ文字(シェル利用時に特別な意味を持つ文字)をエスケープしていないことが原因で脆弱性が生まれます。
対策
OSコマンドインジェクションを防ぐための対策には以下のようなものがあげられます。
-
OSコマンド呼び出しを使わない
OSコマンド呼び出しを使わなければOSコマンドインジェクションの脆弱性は発生しないので、OSコマンド呼び出しを使わない実装を行うことで根本的な対策をとることができます。 -
シェル呼び出し機能のある関数を使わない
OSコマンド呼び出しを使用する必要がある場合には、シェルを経由しない関数を使用することでOSコマンドインジェクションの脆弱性の発生を防ぐことができます。 -
シェル呼び出し機能のある関数のパラメーターを渡さない
シェル経由でOSコマンド呼び出しを行う必要がある場合にはパラメーターを渡さないことでOSコマンドインジェクションの脆弱性の発生を防ぐことができます。また、仮にパラメーターを渡す必要があっても、メタ文字をライブラリを使って適切にエスケープすることで攻撃を防ぐことができます。
Webストレージの不適切な利用
Webストレージとはローカルストレージとセッションストレージのことで、これらの使用方法が不適切な場合に脆弱性が生まれる可能性があります。
原因
Webストレージはクロスサイトスクリプティングなどの攻撃を受けやすくなっています。そのためWebストレージに機密情報などを保存するようにしていると、それらが漏洩してしまう可能性があり危険です。にもかかわらず、Webストレージに機密情報を保存する仕様になっている場合、それは一つの脆弱性と呼べるでしょう。
対策
対策としてはWebストレージには機密情報は保存せず、サーバー側などに都度取りに行く形で実装することです。Webストレージのセキュリティに関してはこちらの記事が分かりやすかったです。
最後に
今回はWebアプリケーションにおける主要な脆弱性について簡単にまとめてみました。触りの部分だけをまとめた形になったので、また今後詳しく学んでいくようにしたいです。最後までご覧いただき、ありがとうございました。
参考
Discussion