Open55

『安全なWebアプリケーションの作り方』

mabomabo

脆弱性(vulnerability)

悪用できてしまうバグ。セキュリティバグとも呼ばれる。


https://internet.watch.impress.co.jp/docs/column/security_basic/1250919.html より画像引用

悪用の例
・個人情報などの秘密情報を勝手に閲覧する
・Webサイトの内容を書き換える
・サイトを閲覧した利用者のPCをウイルスに感染させる
・別の利用者になりすまし、秘密情報の閲覧、投稿、買い物、送金などを行なう
・Webサイトを利用不能にする
・自分の個人情報を確認したら、他人の個人情報が見えてしまう


https://www.ntt.com/business/services/security/security-management/wideangle/zeijaku.html より画像引用

脆弱性があるとダメな理由

経済的損失

(例)
・利用者が受けた金銭的損失の補填・補償
・迷惑料として配る金券などの費用・配送費
・Webサイト停止による機会損失
・信用失墜による売り上げの減少

法的な要求

「個人情報の保護に関する法律」によって、5000件を超える個人情報を有する事業者は個人情報取扱事業者として安全管理措置を講じる義務が課せられている。

利用者が回復不可能なダメージを受ける場合が多い

一旦漏洩した個人情報を回収することはできない。

Webサイト利用者に嘘をつくことになる

ボットネットワーク構築に加担する

ボット:マルウェア(不正プログラム)の一種で、PCに感染後は外部からの指令を受けて、迷惑メール送信やDDoS攻撃(分散型サービス妨害攻撃)などの不正活動を行うもの。

脆弱性が生まれる理由

バグによるもの

・SQLインジェクション
・クロスサイトスクリプティング(XSS)

チェック機能の不足によるもの

・ディレクトリ・トラバーサル脆弱性

Webアプリケーションの脆弱性は、思わぬところに大きな落とし穴が潜んでいる。
Web特有の脆弱性は以下の知識不足で起きる。
・どの情報が漏洩しやすいか
・どの情報が書き換えられるのか
・安全に情報を保持するにはどうすればよいか

セキュリティバグとセキュリティ機能

セキュリティバグ

ソフトウェアやシステムの設計や実装における欠陥(バグ)のうち、セキュリティ上のリスクを引き起こす可能性があるものを指す。

(例)
・クロスサイトスクリプティング(XSS): ユーザー入力が適切にエスケープされず、悪意のあるスクリプトが実行される。
・SQLインジェクション:データベースクエリにユーザー入力がそのまま反映され、不正なクエリが実行される。
・バッファオーバーフロー:メモリ領域を超えたデータが書き込まれ、プログラムの動作が不正に変更される。
・認証の不備:パスワードが平文で保存される、または認証プロセスに脆弱性がある。

セキュリティ機能

システムやソフトウェアが持つ、セキュリティを確保するための仕組みや機能を指す。
これらの機能は、不正アクセスや攻撃からシステムやデータを保護するために設計されている。

(例)
・認証機能:ユーザーが正しい資格情報(ユーザー名とパスワードなど)を提供した場合にのみアクセスを許可する。
・暗号化:データを暗号化して、第三者に読み取られないようにする。
・アクセス制御:ユーザーやシステムがアクセスできるリソースを制限する。
・ログ記録:システムの利用状況やイベントを記録し、不正なアクセスや操作を検出する。
・ファイアウォール:不正なネットワークトラフィックをブロックする。

アプリケーションのセキュリティを「要件」と「バグ」に整理することは、開発マネジメントの上からも重要

バグをなくすこと、脆弱性をなくすことは必須要件

※セキュリティ機能を要件として盛り込むかどうかは、費用との兼ね合いでアプリケーション発注者が決めるべきこと。

mabomabo

HTTPとセッション管理

HTTPメッセージの構成

HTTP1.1とHTTP2 / HTTP3の場合


※『イラスト図解式 この一冊で全部わかるWeb技術の基本 第2版』より抜粋

HTTPメッセージの構成要素(HTTP1.1)

1. 開始行(リクエスト行・ステータス行)

2. HTTPヘッダー

3. 空行

4. メッセージボディ

HTTPメッセージの構成要素(HTTP2、HTTP3)

1. HEADERSフレーム

HTTP1.1における
・開始行
・HTTPヘッダー
・空行

2. DATAフレーム

HTTP1.1における
・空行
・メッセージボディ

HTTPリクエストの構成要素

1. 開始行(リクエスト行)

Webサーバーに対してどのような処理を依頼するのかを伝える情報が含まれる

「メソッド」/ 「パス名」「HTTPバージョン」

・メソッド:Webサーバーに対するリクエストの種類
・パス名:リクエストの対象となるリソースのパス・リクエスト対象のデータを示す(リクエストURLの一部)。
※リクエストURLは複数の部分で構成されており、その中の「パス」部分が「パス名」に該当する。
・HTTPバージョン:使用するHTTPのバージョン

2. HTTPヘッダー

Webブラウザの種類、対応しているデータのタイプ、データの圧縮方法などの情報を伝える。
リクエストに関する追加情報を提供する部分。
各行は「フィールド名:値」の形式で記述される。
ヘッダーは複数行にわたることがあります。

主なヘッダーフィールド
・Host:リクエスト先のサーバーのホスト名
(例)Host: www.example.com
・User-Agent:クライアントの情報
(例)User-Agent: Mozilla/5.0
・Content-Type:メッセージボディのデータ形式
(例)Content-Type: application/json
・Content-Length:メッセージボディのサイズ
(例)Content-Length: 123

3. 空行

1行空けることでHTTPヘッダーの終わりを伝える。ヘッダーとメッセージボディを区切る。

4. メッセージボディ

リクエストの本文。
Webサーバーにデータを送るために使われる。
・GETリクエスト:通常、メッセージボディはありません。
・POSTリクエスト:フォームデータやJSONデータなどが含まれる。

HTTPレスポンスの構成要素

1. 開始行(ステータス行)

WebブラウザにWebサーバー内での処理結果を伝える。

「HTTPバージョン」「ステータスコード」「テキストフレーズ」

・HTTPバージョン:使用するHTTPのバージョン
・ステータスコード:リクエストに対するWebサーバーでの処理の結果を示す3桁の数字
・テキストフレーズ:ステータスコードの内容をテキストで示す

2. HTTPヘッダー

Webサーバーのソフトウェア情報、返信するデータのタイプ、データの圧縮方法などを伝える。
レスポンスの追加情報を含む部分で、キー: 値 の形式で書かれる。

よく使われるヘッダーの例
・Content-Type: text/html → レスポンスのデータがHTMLであることを示す
・Content-Length: 1234 → レスポンスのサイズ(バイト数)
・Set-Cookie: session_id=abcdef; HttpOnly → クライアントにCookieを設定
・Cache-Control: no-cache → キャッシュを無効にする指示

3. 空行

1行空けることでHTTPヘッダーの終わりを伝える。ヘッダーとメッセージボディを区切る。

4. メッセージボディ

HTMLや画像、JSONなどのデータを格納する場所。

mabomabo

リクエストURLの構成


https://www.hostinger.com/tutorials/what-is-a-url より画像引用

スキーム://ホスト名:ポート番号/パス?クエリパラメータ#フラグメント
https://www.example.com:443/index.html?search=hello#section1

URLに使用できない文字(スペース、日本語など)は、パーセントエンコーディング(%エンコーディング)で変換される。


https://rainbow-engine.com/basic-domain-url/ より画像引用

スキーム:プロトコル

(例)http, https

ホスト名:サーバーのドメイン名またはIPアドレス

(例)www.example.com

ポート番号:サーバーのポート番号


https://webukatu.com/wordpress/blog/1214/ より画像引用

ポート番号は省略可能。デフォルトは
・HTTPが80
・HTTPSが443

https://webukatu.com/wordpress/blog/1214/ より画像引用

パス:リソースのパス


https://www.hostinger.com/tutorials/what-is-a-url より画像引用
(例) /index.html

クエリパラメータ:オプションのクエリ文字列

・クエリパラメータは、URLのパスの後に?記号で始まり、キー=値のペアで構成される。
・複数のパラメータがある場合は、&記号で区切られる。
キー (Key)
・パラメータの名前を表す。
・サーバー側でパラメータを識別するために使用される。
値 (Value)
・パラメータの値を表す。
・サーバーに送信される情報。

https://www.hostinger.com/tutorials/what-is-a-url より画像引用
(例)?search=hello

フラグメント:オプションのフラグメント

フラグメント(fragment)は、ウェブページ内の特定の位置を指定するために使用される。
(例)#section1

主な役割

1. ページ内リンク(アンカーリンク)
・フラグメントは、#記号の後に続く文字列で、ページ内の特定の要素(通常はid属性が設定された要素)を指し示す。
・ユーザーがフラグメントを含むURLにアクセスすると、ブラウザはその要素まで自動的にスクロールし、ページ内の特定の位置を直接表示する。これにより、長いページ内の特定の部分に素早くアクセスできる。
2. クライアントサイドでの処理
・フラグメントは、サーバーに送信されることはない。ブラウザ側でのみ解釈され、処理される。
・JavaScriptなどのクライアントサイドのスクリプトは、フラグメントを使用して、ページの状態を変更したり、特定のアクションを実行したりできる。
・シングルページアプリケーション(SPA)などでは、フラグメントを使用して、ページ遷移をエミュレートしたり、アプリケーションの状態を管理したりすることがある。
3. テキストフラグメント
・近年では、特定のテキストを指定できるテキストフラグメントも利用可能。
・テキストフラグメントは、URLフラグメントの特定の構文を使用することにより、作成者がIDで注釈を付けなくても、ウェブ文書内のテキストの特定の部分に直接リンクできるようにするものです
【例】
https://example.com/page.html#section1
このURLは、page.html内のid属性がsection1に設定された要素を表示する。

https://example.com/long-article.html#paragraph-10
このURLは、long-article.html内のid属性がparagraph-10に設定された段落を表示する。

フラグメントの注意点
・フラグメントは、サーバーに送信されないため、サーバーサイドの処理には影響を与えない。
・フラグメントは、ブラウザの履歴に記録されるため、ブラウザの「戻る」「進む」ボタンを使用して、フラグメント間の移動が可能。
・セキュリティ上の理由から、フラグメントを使用して機密情報を渡すことは避けるべき。

mabomabo

よく使うステータスコード一覧

HTTPレスポンスには ステータスコードがあり、リクエストの結果を表す。

コード 情報 内容
1xx 情報・処理継続 -
100 Continue クライアントに「続けて送ってOK」と伝える
101 Switching Protocols プロトコルを変更(WebSocketなど)
2xx 成功・正常終了 -
200 OK 正常に処理成功
201 Created 新しいリソースが作成された(APIでよく使う)
204 No Content 成功したが、返すデータなし
3xx リダイレクト -
301 Moved Permanently URLが永久に変更された
302 Found 一時的なリダイレクト
304 Not Modified キャッシュを使ってOK(変更なし)
4xx クライアントエラー -
400 Bad Request リクエストが不正
401 Unauthorized 認証が必要(ログインが必要)
403 Forbidden アクセス禁止
404 Not Found ページやリソースが見つからない
5xx サーバーエラー -
500 Internal Server Error サーバー内部エラー
502 Bad Gateway サーバーが不適切なレスポンスを受け取った
503 Service Unavailable サーバーが一時的に利用不可
mabomabo

主なMIMEタイプ一覧

MIMEタイプ:ファイルの種類(コンテンツの形式)を識別するための文字列

「タイプ / サブタイプ」 という形式になっている。
MIMEタイプを適切に設定すると、ブラウザやサーバーが正しくファイルを処理できる。

タイプ(大分類)

タイプ 説明
text 文字データ
image 画像データ
audio 音声データ
video 動画データ
application アプリケーションデータ
multipart 複数のデータを含む

テキスト系

MIMEタイプ 説明
text/plain プレーンテキスト(.txt)
text/html HTMLファイル(.html)
text/css CSSファイル(.css)
text/javascript JavaScriptファイル(.js)
text/csv CSVファイル(.csv)

画像系

MIMEタイプ 説明
image/png PNG画像(.png)
image/jpeg JPEG画像(.jpg, .jpeg)
image/gif GIF画像(.gif)
image/svg+xml SVG画像(.svg)
image/webp WebP画像(.webp)

音声・動画系

MIMEタイプ 説明
audio/mpeg MP3音声(.mp3)
audio/ogg Ogg音声(.ogg)
video/mp4 MP4動画(.mp4)
video/webm WebM動画(.webm)

アプリケーションデータ

MIMEタイプ 説明
application/json JSONデータ(.json)
application/xml XMLデータ(.xml)
application/pdf PDFファイル(.pdf)
application/zip ZIP圧縮ファイル(.zip)
application/msword Word文書(.doc)
application/vnd.ms-excel Excel文書(.xls)
application/vnd.openxmlformats-officedocument.wordprocessingml.document Word(.docx)
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet Excel(.xlsx)

フォーム・アップロード

MIMEタイプ 説明
multipart/form-data ファイルアップロード(フォーム送信)
application/x-www-form-urlencoded URLエンコードされたデータ(通常のフォーム送信)
mabomabo

HTTPの主なヘッダーフィールド

ヘッダーフィールドの種類

種類 説明
リクエストヘッダー クライアントが送る情報 User-Agent, Referer, Accept
レスポンスヘッダー サーバーが送る情報 Server, Set-Cookie, WWW-Authenticate
エンティティヘッダー 本文(コンテンツ)の情報 Content-Type, Content-Length, Content-Encoding
一般ヘッダー リクエスト・レスポンス両方で使われる Cache-Control, Connection, Date

リクエストヘッダー(クライアント → サーバー)

クライアントがサーバーへリクエストを送る際に含める情報

ヘッダー 説明
User-Agent クライアントの情報(OSやブラウザ) Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Referer リンク元のURL https://example.com
Accept クライアントが受け入れ可能なデータの種類 text/html, application/json
Accept-Language 受け入れ可能な言語 ja, en-US;q=0.9
Authorization 認証情報を送信 Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Cookie クライアントのCookie情報 sessionid=abc123; lang=ja
Host リクエスト先のホスト名 example.com

レスポンスヘッダー(サーバー → クライアント)

サーバーがクライアントへレスポンスを返す際に含める情報

ヘッダー 説明
Server サーバーの種類 Apache/2.4.41 (Ubuntu)
Set-Cookie クライアントにCookieを設定 sessionid=xyz123; HttpOnly
WWW-Authenticate 認証が必要な場合の認証方式 Basic realm="Secure Area"
Location リダイレクト先URL https://newsite.com

エンティティヘッダー(コンテンツの情報)

コンテンツ(本文)の情報を表すヘッダー

ヘッダー 説明
Content-Type コンテンツの種類 text/html; charset=UTF-8
Content-Length 本文のバイト数 1024
Content-Encoding 圧縮形式 gzip
Content-Disposition ファイルのダウンロード指示 attachment; filename="file.pdf"

一般ヘッダー(共通)

リクエスト・レスポンスどちらでも使われるヘッダー

ヘッダー 説明
Cache-Control キャッシュの制御 no-cache, no-store
Connection 接続の制御 keep-alive / close
Date サーバーの日時 Tue, 18 Feb 2025 12:34:56 GMT

※Referer ヘッダー

クライアント(ブラウザなど)がどのページからリンクをたどって現在のページにアクセスしたか をサーバーに伝えるためのヘッダー。
リンク元(直前に見ていたページ)のURLがどこか、という情報が書いてある項目

https://wa3.i-3-i.info/word129.html より画像引用

Referer ヘッダーの役割
・リンク元の情報を提供:サーバーがユーザーの流入経路を知ることができる
・トラフィック解析:どのサイトからアクセスが多いか分析できる
・セキュリティ管理:不正なリクエストや CSRF(クロスサイトリクエストフォージェリ)対策に活用できる

(例)

GET /page2.html HTTP/1.1
Host: example.com
Referer: https://example.com/page1.html

サーバーは「ユーザーが page1.html から page2.html に来た」ことを認識できる

Referer の問題点

①プライバシーリスク
Referer にはユーザーが直前に見ていたページのURLが含まれるため、機密情報が漏れる可能性がある。
②検索キーワードの漏洩
検索エンジンで「プライベートな検索」をした場合、そのURLが Referer に含まれ、外部サイトに送信されることがある。
③ログイン情報の漏洩
https://example.com/profile?user=john_doe のようなURLで、user=john_doe が Referer に含まれると、外部サイトに送信されることがある。

RefererはURLが秘密情報を含んでいる場合、セキュリティ上のリスクがある

URLがセッションIDを含んでいる場合、Referer経由で外部に情報が漏洩し、なりすましに悪用される可能性がある。
※参考URL:https://privacyinternational.org/guide-step/4150/http-referer-explanation

mabomabo

HTTPとセッション管理

HTTPメソッド

データ送信におけるGETとPOST

GETメソッド

URLの後ろに送りたいデータを付与する
URLにクエリー文字列の形でパラメータを渡す
・URLの末尾に「?」をつけ、「パラメータ名 = 値」の形式で送信する(HTTP1.1)
・URLに機密情報が含まれ、ブラウザの履歴に残ってしまう。
※ブラウザやサーバーが処理できるURLの長さには上限があるため、データ量が多い場合はPOSTメソッドを使った方が安全


https://zenn.dev/masahiro_toba/books/3daf7dc0d5dfd7/viewer/c07433 より画像引用

POSTメソッド

HTTPリクエストのメッセージボディ内にデータを含めて送る
※情報をメッセージボディに記録して送信する(HTTP1.1)
・個人情報を扱う場合に利用される。

GETとPOSTの使い分け


https://konoti.com/website/html-css/get-post.html より画像引用

GETメソッド

GETメソッドは参照(リソースの取得)のみに用いる
GETメソッドは副作用がないことが期待される
◎GETメソッドを使用してもいいケースは、以下の要件に1つもあてはまらない場合
・データ更新など副作用を伴うリクエストの場合
・秘密情報を送信する場合
・送信するデータの総量が多い場合

POSTメソッド

秘密情報の送信にはPOSTメソッドを用いる
サーバー側でのデータの追加・更新・削除といった更新系の画面ではPOSTメソッドを使わなければならない。
GETメソッドの場合は以下の可能性があり、秘密情報の送信に適さない
・URL上に指定されたパラメータがReferer経由で外部に漏洩する
・URL上に指定されたパラメータがアクセスログに残る

◎POSTメソッドの使用が適しているケース

・データ更新など副作用を伴うリクエストの場合
・秘密情報を送信する場合
・送信するデータの総量が多い場合

hidden パラメータは書き換え可能

mabomabo

HTTP

クライアントの状態を覚えておかない設計
ステートレスな設計

◎HTTPというレーヤーでは、テキストボックスもラジオボタンの選択も、hiddenパラメータも同じように扱われ、ブラウザ上では変更できない値も書き換え可能


https://college.globalsign.com/ssl-pki-info/https-http/ より画像引用

mabomabo

hidden パラメータ

ステートレス

hiddenパラメータで識別

https://blog.senseshare.jp/hidden.html より画像引用

フォーム送信時に渡すべきデータを、ブラウザが一時的に持っておく仕組み
hidden パラメータを使うと、hidden に指定したデータはサーバーを介さずに一時的なデータをブラウザ側で保持することができる。
ユーザーが入力することはできないものの、初期値のように設定されており、送信されるまでブラウザが保持しているデータ。

※フォーム送信時に追加データを渡せるため、ユーザーが直接入力するフォーム要素だけでなく、システム側で決めた値を一緒に送信できる

クライアント側(ブラウザ)で一時的に保持する

通常のフォーム送信と違い、hidden パラメータはユーザーが直接入力するものではなく、開発者が事前に埋め込むか、JavaScript で変更する可能性がある。
・HTML に埋め込まれた値が、送信されるまでブラウザ内に残る
・JavaScript で変更可能
・ユーザーが直接編集できない

⚪︎通常の入力欄(<input type="text"> など)
→ ユーザーが入力した瞬間にデータがメモリに保持され、送信時にデータが渡される。

⚪︎hidden フィールド
→ ページの HTML に埋め込まれた値 または JavaScript によって動的に設定された値が、送信時までブラウザのメモリに保持される。

メリット一覧表

メリット 説明
画面に表示せずにデータを送れる ユーザーに見せずにデータを送信可能
追加情報を送信できる ユーザーが入力しないデータも送信可能
JavaScript で動的に変更できる 送信前に値を変更することが可能
ページ間でデータを引き継げる セッションを使わずに値を保持可能
CSRF対策などに活用できる セキュリティトークンを埋め込める

クッキー・セッションとの比較

項目 hiddenパラメータ セッション クッキー
データの保存場所 HTML フォーム
(ブラウザ)
サーバー ユーザーのブラウザ
データの保持範囲 そのページ内のみ
(フォーム送信が必要)
サーバー全体
(ページ間で共有可)
ブラウザ全体
(有効期限まで保持可)
データの変更 JavaScript で変更可能 サーバー側で管理 JavaScript で変更可能
(HttpOnly なしの場合)
セキュリティ 簡単に書き換え可能 セキュア
(認証情報の管理に向いている)
書き換え可能
(HttpOnly なしだと脆弱)

◎hidden は利用者自身からは書き換えできるが、情報漏洩や第三者からの書き換えに対しては堅牢

◎利用者によっても書き換えされては困る認証や認可に関数情報はセッション変数に保存すべき。それ以外の情報はhiddenパラメータに保存することを検討するといい。特に、ログイン前の状態では認証・認可に関する情報はないはずなので、原則としてセッション変数の使用を避け、hiddenパラメータを使うことが情報漏洩に対して安全。

hidden パラメータが適しているケース

  1. ページ遷移時の一時的なデータ保持
    セッションやクッキーを使わずに、特定のデータをページ遷移間で引き継ぐ手段として使える。
    (例)transaction_id を次のページのフォームに持たせる
  2. ユーザーの選択情報を保持
    (例)ユーザーが選んだオプションをサーバーに送る前に設定
  3. JavaScript で変更可能なデータを送信
    (例)クーポンコード適用時に hidden の値を変更
  4. CSRF トークンの埋め込み
    (例)hidden フィールドで CSRF トークンを送る

hidden パラメータが向かないケース

  1. ページをまたいで長期間データを保持したい
    → セッションを使う
  2. URLでデータを簡単に共有したい
    → GET パラメータを使う
  3. 機密情報の保持(ユーザーが書き換え可能なため)
    → セッション or データベースを使う

通常のデータとhiddenパラメータの比較

状態保持の方法 ページ遷移時の挙動 データの受け渡し
通常のフォーム入力 ページ遷移でリセット 別ページへは送信されない
hidden パラメータ ページ遷移前に <form> を通じて送信 サーバー経由で次のページに渡せる
URL パラメータ
(GET メソッド)
ページ遷移後もURLに保持 直接URLで値を渡せる
(example.com?key=value)
セッション (サーバー側管理) ページをまたいでも保持 ユーザーごとの情報をサーバーが管理

hiddenパラメータの脆弱性

hiddenパラメータは、ブラウザ上ではユーザーに見えませんが、以下の方法で簡単に内容を確認・改ざんできる。
(1)開発者ツール(DevTools)
・ブラウザの開発者ツール(ChromeのDevToolsなど)を使うと、HTMLのソースコードを確認できる。
・hiddenパラメータの値も簡単に確認・編集可能。
(2)パケットキャプチャツール(Fiddlerなど)
・FiddlerやWiresharkなどのツールを使うと、クライアントとサーバー間で送受信されるデータをキャプチャできる。
・hiddenパラメータを含む送信データを確認し、改ざんすることが可能。
(3)ブラウザの「ソース表示」
・ブラウザの「ページのソースを表示」機能を使うと、HTML全体を確認できる。
・hiddenパラメータの値も含まれているため、簡単に確認できます。

hiddenパラメータが改ざんされると起こること

(1)不正なデータの送信
(例)hiddenパラメータに商品の価格が含まれている場合、ユーザーが価格を改ざんして安く購入しようとする可能性がある。
(2)セキュリティ上の問題
(例)hiddenパラメータにユーザーIDや権限情報が含まれている場合、攻撃者がこれを改ざんして他のユーザーになりすます可能性がある。
(3)アプリケーションの動作不良
hiddenパラメータの値が改ざんされると、サーバー側で想定外の処理が行われ、アプリケーションが誤動作する可能性がある。

hiddenパラメータの脆弱性を防ぐ方法

(1)サーバー側での検証
hiddenパラメータを含むすべての入力データを、サーバー側で厳密に検証する。
(例)商品の価格が正しいか、ユーザーIDが正当なものかなどをチェックする。
(2)セッション管理
クライアント側で状態を保持するのではなく、サーバー側でセッションを使って状態を管理する。
(例)ユーザーIDや権限情報をセッション変数に保存し、hiddenパラメータには含めない。
(3)暗号化や署名
hiddenパラメータの値を暗号化したり、署名を付与したりする。
(例)サーバー側で生成したトークンをhiddenパラメータに埋め込み、改ざんを検出する。
(4)HTTPSの使用
HTTPではなくHTTPSを使用して、通信内容を暗号化する。
これにより、パケットキャプチャツールを使った中間者攻撃を防ぐ。
(5)重要なデータをhiddenパラメータに含めない
ユーザーIDや価格、権限情報などの重要なデータは、hiddenパラメータに含めず、サーバー側で管理する。

mabomabo

アクセスログ

サーバーやアプリケーションが受信したリクエストや発生したイベントを記録するための仕組み。
これにより、システムの運用状況を監視し、問題の特定やパフォーマンスの分析、セキュリティ監査などに役立つ。

アクセスログの仕組み

リクエストの記録

クライアント(ブラウザやアプリケーション)がサーバーにリクエストを送信すると、サーバーはそのリクエストに関する情報をログファイルに記録する。

記録される情報に含まれる情報例
・リクエストの日時
・クライアントのIPアドレス
・リクエストされたURL
・HTTPメソッド(GETやPOSTなど)
・レスポンスステータスコード

ログのフォーマット

ログは特定のフォーマットで記録される。
例えば、WebサーバーソフトウェアであるApacheやNginxは、共通ログフォーマット(Common Log Format)や組み込みフォーマットを使用する。
フォーマットはカスタマイズ可能で、必要な情報を追加・削除できる。

ログの保存

ログは通常、テキストファイルとしてサーバー上に保存される。
ファイル名や保存場所はサーバーの設定によって異なる。
ログファイルは定期的にローテーション(新しいファイルに切り替える)され、古いログは圧縮されたり削除されたりする。

ログの分析

ログファイルは、ツールやスクリプトを使って分析される。
例えば、アクセス数が多いページやエラーの発生状況、不正アクセスの兆候などを確認できる。

アクセスログに記録される主な情報
・クライアントのIPアドレス
リクエストを送信したクライアントのIPアドレス
これにより、アクセス元を特定できる。
・リクエスト日時
リクエストが行われた日時。タイムスタンプ形式で記録される。
・HTTPメソッド
リクエストの種類(GET、POST、PUT、DELETEなど)。
・リクエストされたURL
クライアントがアクセスしたページやリソースのパス。
・HTTPバージョン
使用されたHTTPプロトコルのバージョン(例: HTTP/1.1、HTTP/2)。
・レスポンスステータスコード
サーバーが返したHTTPステータスコード(例: 200(成功)、404(ページが見つからない)、500(サーバーエラー))。
・レスポンスサイズ
サーバーがクライアントに返したデータのサイズ(バイト単位)。
・リファラー (Referrer)
クライアントがそのページにアクセスする前に閲覧していたページのURL。
・ユーザーエージェント
クライアントが使用しているブラウザやデバイスの情報。

mabomabo

ユーザーエージェント(User Agent)

ユーザーが使用しているデバイスだけでなく、そのデバイス上で動作しているブラウザやアプリケーションの情報も含まれる。具体的には、ユーザーエージェントは、クライアント(ユーザーの端末)がサーバーにリクエストを送信する際に、自身の情報を伝えるための文字列。

mabomabo

HTTP認証

HTTP の認証機能は、Web サイトや Web アプリケーションへのアクセスを制限し、許可されたユーザーのみがリソースにアクセスできるようにするための仕組み
HTTP通信においてクライアント(ユーザー)がサーバーに対して自身の身元を証明するための仕組み。これにより、サーバーはクライアントがアクセス権を持っているかどうかを確認し、許可されたリソースのみを提供する。
HTTPがステートレスなプロトコル → HTTP認証もステートレス

HTTP 認証の仕組み

HTTP 認証は、クライアント (通常は Web ブラウザ) とサーバー間で以下のような手順でやり取りを行なう。
①クライアントからのリクエスト
クライアントが保護されたリソース (Web ページなど) にアクセスしようとする。
②サーバーからの認証要求
サーバーは、クライアントに認証が必要であることを伝え、どのような認証方法をサポートしているかを提示する。
③クライアントからの認証情報
クライアントは、サーバーが提示した認証方法の中から 1 つを選択し、必要な認証情報 (ユーザー名とパスワードなど) をサーバーに送信する。
④サーバーでの認証
サーバーは、受け取った認証情報が正しいかどうかを確認する。
⑤アクセス許可または拒否
認証に成功した場合、サーバーはクライアントにリソースへのアクセスを許可する。
認証に失敗した場合、サーバーはアクセスを拒否する。

HTTP 認証の種類

Basic 認証

最も基本的な認証方式。
ユーザー名とパスワードを Base64 エンコードして送信する。
セキュリティ上の問題があるため、HTTPS と組み合わせて使用することが推奨される。
→暗号化はされていない

概要
①認証の必要なページにアクセス
②一旦「401 Unauthorized(認証が必要なのにされていない)」というステータスをサーバが返す
③ブラウザがユーザ名とパスワードを要求
④認証情報を伴って再リクエスト
⑤ドキュメントをサーバーから取得できる

※②のとき、サーバーは「401 Unauthorized」というステータスコードと共に、WWW-Authenticateヘッダーを含めて応答する。 このWWW-Authenticateヘッダーに、サーバーがサポートする認証方式が記述されている。
ブラウザは、サーバーから受け取ったWWW-Authenticateヘッダーに基づいて、どの認証方式を使用するかを判断する。通常は、最もセキュリティの高い認証方式が優先的に選択される。

認証に成功すると、ブラウザが自動的にAuthorizationヘッダを付与する。
見かけ上は1回だけ認証ダイアログが表示されるので認証状態が保持されているように見えるが、実際にはリクエストごとにIDとパスワードがヘッダを介して送信されており、認証状態はどこにも保存されていない。

Digest 認証

Basic 認証のセキュリティ上の問題を改善した認証方式。
パスワードをハッシュ化して送信します。

Bearer 認証

主に OAuth 2.0 などの認可フレームワークで使用される認証方式。
アクセストークンを HTTP ヘッダーに含めて送信する。

フォーム認証(HTML)

HTMLフォームでIDとパスワードを入力させる

クライアント認証

SSLクライアント証明書を使用する

HTTP 認証のメリット

・セキュリティの向上: 不正なアクセスから Web サイトや Web アプリケーションを保護することができる。
・アクセス制限: 特定のユーザーやグループに対してのみリソースへのアクセスを許可することができる。
・ユーザー管理: ユーザーアカウントを作成し、管理することができる。

HTTP 認証の注意点

・セキュリティ: 認証情報を安全に管理する必要がある。Basic 認証はセキュリティ上の問題があるため、HTTPS と組み合わせて使用するか、より安全な認証方式を使用することが推奨される。
・利便性: ユーザーにとって使いやすい認証システムを構築する必要がある。

認証(Authentication)

利用者が確かに本人であることを何らかの手段で確認すること

認可(Authorization)

認証済みの利用者に権限を与えること
具体的な操作を「できるようにする」

mabomabo

クッキーとセッション管理

セッション管理

アプリケーションの状態を覚えておくこと
・HTTP認証を使う場合:ブラウザがIDやパスワードなど認証状態を記憶する
・HTTP認証を使わない場合:サーバが認証状態を記憶する


https://shukapin.com/infographicIT/session-management より画像引用

クッキー

セッション管理をHTTPで実現する目的で導入された仕組み。
サーバ側からブラウザに対して、「名前=変数」の組を覚えておくよう指示するもの。
レスポンスヘッダの Set-Cookie: により覚えておくよう指示する。

一旦クッキー値を覚えたブラウザは、その後同じサイトにリクエストを送信する際には、覚えたクッキー値を送信する。
リクエストヘッダのCookie: で送信する。

https://shukapin.com/infographicIT/cookie より画像引用

セッションID:覚えたクッキー値のこと。セッション情報にアクセスするためのキー情報となるもの。

※クッキーには有効期限を設定できる。
※クッキーに有効期限を設定していない場合、ブラウザを終了させるまで有効になる。

クッキーによるセッション管理

アプリケーションのデータを保持する目的でクッキーそのものに値を入れることをあまりしない理由
・クッキーが保持できる値の個数や文字列長には制限があるため
・クッキーの値は利用者本人には参照・変更できるので、秘密情報の格納には向かないため

実際には、クッキーには整理番号としてのセッションIDを格納しておき、実際の値はサーバーで管理する方法が広く用いられている。

https://shukapin.com/infographicIT/session-management より画像引用

クッキー受渡しのフロー

https://shukapin.com/infographicIT/cookie より画像引用

セッションIDに求められる要件

①第三者がセッションIDを推測できないこと

・別人による なりすましを防止するため、乱数を使うが、具体的にセッションIDには暗号論的疑似乱数生成器を用いて生成される。
・実際の開発には、Webアプリケーション開発ツールで提供されるセッションIDを利用する。
◎セッション管理機構は自作しないこと

②第三者からセッションIDを強制されないこと

・認証後にセッションIDを変更する
(例)セッションIDの固定化攻撃(Session Fixation Attack)

③第三者に情報が漏洩しないこと

セッションID漏洩の原因
・クッキー発行の際の属性に不備がある
・ネットワーク的にセッションIDが盗聴される
 →ネットワークの経路上に盗聴の仕掛けがある場合
※セッションIDをネットワーク盗聴から保護するにはSSL(Secure Socket Layer)による暗号化が有効だが、クッキーを発行する際の属性指定には注意が必要
・クロスサイト・スクリプティングなどアプリケーションの脆弱性により漏洩する
・PHPやブラウザなどプラットフォームの脆弱性により漏洩する
・セッションIDをURLに保持している場合、Refererヘッダから漏洩する

クッキーの属性


https://levelup.gitconnected.com/same-site-cookie-and-other-attributes-6a3c705efe0c より画像引用

属性 意味
Domain ブラウザがクッキー値を送信するサーバーのドメイン
Path ブラウザがクッキー値を送信するURLのディレクトリ
Expires クッキー値の有効期限
指定しない場合はブラウザの終了まで
Secure SSLの場合のみクッキーを送信
HttpOnly この属性が指定されたクッキーはJavaScriptからアクセスできない

Domain 属性

複数のサーバーに送信されるクッキーを生成したいときに使用する
※原則設定しないもの
・異なるドメインに対するクッキー設定はできないように制限している。
→異なるドメインに対するクッキーが設定できてしまうと、セッションIDの固定化攻撃の手段として利用されてしまうため
・Domain属性を指定しない状態がもっともクッキーの送信範囲が狭く、安全な状態と言える。クッキーを生成したサーバーにのみクッキーが送られる。
・Domain属性を不用意に設定してしまうと、脆弱性の原因になる。

※クッキーモンスター問題(Cookie Monster Bug)
Webサイトが過剰なCookieを生成したり、無駄に大きなCookieを送信したりすることで、以下のような問題が発生する現象を指す。
・ネットワークの遅延:大量のCookieがブラウザとサーバー間でやり取りされるため、通信速度が低下する。
・サーバーの負荷増加:サーバーが大量のCookieを処理するため、負荷が高くなる。
・ユーザー体験の低下:ページの読み込みが遅くなり、ユーザーがストレスを感じる。
・ドメインやサブドメインごとのCookie:メインドメインとサブドメインで別々のCookieが生成され、重複して送信されることがある。

Secure 属性

SSLの場合のみサーバーに送信される。
※Secure属性のついていないクッキーは、SSL通信かどうかに関係なく、常にサーバーに送信される。

HttpOnly 属性

JavaScriptからアクセスできないクッキーを設定するもの。
クッキーとして格納されたセッションIDを盗み出す攻撃の典型はクロスサイト・スクリプティング攻撃により、JavaScriptを悪用してクッキーを盗み出すというもの。
※セッションIDにはHttpOnly属性をつけるようにすると良い

セッションとクッキーの紐付け

1回目のアクセス

https://kanda-it-school-kensyu.com/php-basic-contents/pb_ch11/pb_1103/ より画像引用

2回目のアクセス

https://kanda-it-school-kensyu.com/php-basic-contents/pb_ch11/pb_1103/ より画像引用

ブラウザを閉じた後に再アクセス

https://kanda-it-school-kensyu.com/php-basic-contents/pb_ch11/pb_1103/ より画像引用

mabomabo

セッションID固定化攻撃(Session Fixation Attack)

Webアプリケーションの脆弱性を利用して、攻撃者が正規ユーザーのセッションIDを乗っ取り、ユーザーになりすまして不正な行為を行う攻撃手法

仕組み

①攻撃者がセッションIDを生成
攻撃者は、Webアプリケーションが発行するセッションIDを事前に生成する。
②ユーザーにセッションIDを送り込む
攻撃者は、生成したセッションIDをユーザーに何らかの方法で送り込む。
例えば、メールにURLを添付したり、Webサイトに罠を仕掛けたりする。
③ユーザーがセッションIDを使ってログイン
ユーザーは、攻撃者から送られたセッションIDを使ってWebアプリケーションにログインする。
④攻撃者がユーザーになりすます
攻撃者は、ユーザーが使用したセッションIDを保持しているため、ユーザーになりすましてWebアプリケーションにアクセスし、不正な操作を行なう。

対策

ログイン時にセッションIDを再生成する

ユーザーがログインするたびに、新しいセッションIDを発行します。これにより、攻撃者が事前に用意したセッションIDが無効になります。

セキュアなCookieを使用する

Cookieには、セッションIDなどの重要な情報が含まれている。
Cookieを安全に管理するために、以下の設定を行なう。
①Secure属性:HTTPS通信でのみCookieを送信するように設定する。
②HttpOnly属性:JavaScriptからCookieにアクセスできないように設定する。

セッション管理を適切に行う

セッションの有効期限を適切に設定し、不要なセッションを破棄する。

Webアプリケーションの脆弱性を解消する

Webアプリケーションに脆弱性があると、攻撃者に利用される可能性があるため、脆弱性を定期的にチェックし、修正することが重要。

mabomabo

ドメイン(Domain)

インターネット上のリソースを簡単に見つけるための「名前」

ドメインの構造

ドメイン名は、ピリオド(.)で区切られた階層構造を持っている。
右側からトップレベルドメイン(TLD)、セカンドレベルドメイン、サブドメインなどに分かれる。
(例)www.example.com

トップレベルドメイン(TLD): 「.com」

(例).com, .jp, .org, .netなど

セカンドレベルドメイン: 「example」

独自に決める部分

サブドメイン: 「www」

オプションで、Webサーバーを指すことが多い

mabomabo

受動的攻撃と同一生成元ポリシー


https://www.shiksha.com/online-courses/articles/difference-between-active-and-passive-attacks/ より画像引用

https://attaxion.com/blog/how-are-attack-vectors-and-attack-surfaces-related/ より画像引用

能動的攻撃(active attack)

攻撃者がWebサーバーに対して直接攻撃すること。
(例)SQLインジェクション

受動的攻撃(passive attack)

攻撃者がサーバーを直接攻撃するのではなく、Webサイトの利用者に罠を仕掛けることにより、罠を閲覧したユーザを通してアプリケーションを攻撃すること。

①単純な受動的攻撃

典型例:怪しいサイトを閲覧してマルウェアに感染するケース
※マルウェア:ウイルスなどの不正プログラム

攻撃の手順
(1)ユーザが罠を閲覧
(2)仕掛けのあるHTMLをサーバから取得
(3)マルウェアに感染

②正規サイトを悪用する受動的攻撃

攻撃の手順
(1)攻撃者があらかじめ正規サイトを攻撃してコンテンツに罠をしかける
(2)ユーザがサイトを閲覧
(3)仕掛けのあるHTMLをサーバから取得
(4)マルウェア感染、情報漏洩、不正操作

罠を仕込む手法
・FTPなどのパスワードを不正入手してコンテンツを書き換える
・Webサーバの脆弱性をついた攻撃によりコンテンツを書き換える
・SQLインジェクション攻撃によりコンテンツを書き換える
・SNSなどの利用者が投稿できるサイト機能のクロスサイト・スクリプティング脆弱性を悪用する

③サイトをまたがった受動的攻撃

攻撃の手順
(1)利用者が罠サイトを閲覧する
(2)罠サイトから、仕掛けを含むHTMLをダウンロードする
(3)HTMLの仕掛けが発動して正規サイトに攻撃のリクエストを送信する
(4)正規サイトからJavaScriptなどの仕掛けを含むレスポンスが返る

特徴
正規サイトにログインしている利用者のアカウントを利用した攻撃
・(3)のリクエストでセッションクッキーを正規サイトに送信するため、利用者が正規サイトにログイン状態であれば、ログインした状態で攻撃が実行される。

(典型例)
・クロスサイト・リクエストフォージェリ(CSRF):(3)のリクエストで攻撃するタイプ
・クロスサイト・スクリプティング(XSS):(4)のレスポンスによりブラウザを介して攻撃するタイプ
・HTTP・ヘッダインジェクション:(4)のレスポンスによりブラウザを介して攻撃するタイプ

ブラウザはどのように受動的攻撃を防ぐか

サンドボックス



https://misile00.github.io/notes/Browser-Sandboxing より画像引用

・ブラウザが悪意のあるコードからユーザーを守るための仕組み
・ブラウザが備えている重要なセキュリティ機能の一つ
・プログラムを隔離された環境で実行する技術。
・ブラウザでは、ウェブページやプラグインをサンドボックス内で動作させ、システムや他のタブに影響を与えないようにする。
・サンドボックス内で実行することによって、システムや他のタブに悪影響を及ぼすことができないため、ユーザーのデータやプライバシーが保護される。
・利用者のブラウザ上で悪意のあるプログラムが動かないように、JavaScriptなどは安全性を高めるための機能を提供している。
→基本的な考え方
 ①利用者に配布元を確認させた上で、利用者が許可した場合のみ実行する
 ②プログラムの「できること」を制限するサンドボックスという環境を用意する

仕組み
・隔離: 各タブやプラグインは独立して実行され、他の部分にアクセスできない。
・制限: サンドボックス内のコードは、システムリソースへのアクセスが制限される。
・監視: ブラウザがサンドボックス内の動作を監視し、異常があれば停止する。

メリット
・セキュリティ向上: 悪意のあるコードの影響を最小限に抑える。
・安定性: 一つのタブがクラッシュしても、他のタブに影響しない。

デメリット
・リソース使用: 各タブが独立して動作するため、メモリやCPUの使用量が増える。

同一生成元ポリシー


https://shukapin.com/infographicIT/origin-policy より画像引用

・JavaScriptによるサイトをまたがったアクセスを禁止するセキュリティ上の制限
・ブラウザのサンドボックスに用意された制限の一つ
・ブラウザが「異なるオリジン(ドメイン)からのリソースアクセスを制限する」ためのルール。
これにより、悪意のあるサイトが他のサイトのデータを勝手に読み取ったり、操作したりするのを防ぐ。
・仕組み:プロトコル、ドメイン、ポート番号が完全に一致しない場合、アクセスを制限する。

※「オリジン」
3つの要素で構成されている。
・プロトコル(通信方法): http や https など。
・ドメイン(サイトのアドレス): example.com など。
・ポート番号: 80(HTTP)や 443(HTTPS)など。

https://shukapin.com/infographicIT/origin-policy より画像引用

(例)
https://example.comhttp://example.com → プロトコルが異なるため「別のオリジン」
https://example.comhttps://sub.example.com → ドメインが異なるため「別のオリジン」

同一生成元ポリシーが実際に行なうアクセス制限
・他のサイトのデータ読み取り: 別のオリジンのサイトからデータを取得できないようにする。
・他のサイトへの不正な操作: 別のオリジンのサイトに勝手にリクエストを送信できないようにする。

「同一生成元」を満たす条件 ※以下全てを満たす必要がある

①URLのホストが一致している
②スキーム(プロトコル)が一致している
③ポート番号が一致している

※クッキーに対する条件はJavaScriptの制限の方が厳しい。クッキーに対する条件はスキームとポート番号は関係ない。
※JavaScriptにはディレクトリに関する制限がない。

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

ブラウザは同一生成元ポリシーにより受動的攻撃を防止できるが、アプリケーションに脆弱性があると受動的攻撃を受ける場合がある。
XSSはJavaScriptを送り込むことで同一生成元ポリシー下でJavaScriptを実行する

第三者のJavaScriptを許可する場合

①サイト運営者が第三者を信頼して実行するJavaScript
サイト運営者がアクセス解析、バナー広告、ブログパーツなど、第三者の提供するJavaScriptを自社サイトに埋め込む場合がある。埋め込まれたJavaScriptに悪意があると、情報漏洩やサイト改ざんのリスクがある。

脅威の例
・提供元が意図的に個人情報を収集する
・提供元サーバーに脆弱性があり、JavaScriptが差し替えられる
・提供元のJavaScriptに脆弱性があり、別のスクリプトが実行される

②閲覧者が第三者を信頼して埋め込むJavaScript
(例)Firefoxのグリースモンキーアドオン
ブラウザの利用者がインストールするスクリプトで、Web閲覧の内容を簡単に改変できる。

iframe・frame


https://catnose.me/learning/html/iframe より画像引用

ウェブページ内に別のウェブページを表示するためのHTMLタグ。
例えば、YouTubeの動画を自分のサイトに埋め込むことができるが、これはiframeを使っている。
クロスドメインのアクセスができるが、JavaScriptによってクロスドメインのドキュメントにアクセスすることは禁止されている。

<iframe>要素と同一生成元ポリシー
<iframe>要素自体は同一生成元ポリシーに違反するものではない。
<iframe>要素は、単に外部のWebページを埋め込むための要素であり、それ自体が同一生成元ポリシーに違反するわけではない。
しかし、<iframe>内で表示されるコンテンツが別のオリジンである場合、そのコンテンツとのやり取りにおいて同一生成元ポリシーが適用され、CORSの設定が必要になることがある。
問題となるのは、<iframe>内で読み込まれたページと、それを読み込んでいる親ページとの間でのJavaScriptによる操作やデータ交換がある場合。これらの操作やデータ交換を行おうとした場合に、同一生成元ポリシーによる制限が働くことがある。

X-FRAME-OPTION

ウェブサイトのセキュリティを強化するためのHTTPヘッダー。レスポンスヘッダとして定義されている。
これにより、他のサイトが自分のサイトを iframe という形で埋め込むのを防ぐことができる。

X-FRAME-OPTIONの役割

X-FRAME-OPTIONは、他のサイトが自分のサイトを iframe で埋め込むことを制限する。
これにより、クリックジャッキングという攻撃を防ぐことができる。
※クリックジャッキング:悪意のあるサイトが自分のサイトを透明な iframe で表示し、ユーザーに意図しない操作をさせる攻撃のこと。

X-FRAME-OPTIONの設定方法(3つの値)

・DENY:すべてのサイトでの iframe 埋め込みを禁止する
・SAMEORIGIN:同じドメイン(オリジン)内でのみ iframe 埋め込みを許可する
・ALLOW-FROM uri:指定したURI(サイト)のみ iframe 埋め込みを許可する
※セキュリティを強化するために、DENYまたはSAMEORIGINを使用することが推奨される。

img 要素

・src 属性はクロスドメインの指定が可能
→ 画像に対するリクエストには、画像のあるホストに対するクッキーがつくので、罠サイトに「認証の必要な画像」を表示させることも可能。
・JavaScriptから画像の中身にアクセスできない。
・意図しないサイトに画像が貼られることを禁止したい場合、画像に対するRefererヘッダをチェックするという手法がある。

script 要素

・src 属性を指定すると他のサイトからJavaScriptを読み込むことができる。
・クロスドメインでのスクリプト読み込みとは、あるドメイン(サイト)が、別のドメイン(サイト)にあるJavaScriptファイルを読み込んで実行することを指す。
・外部のJavaScriptを読み込むとは、自分のウェブサイトとは別の場所(別のドメインやサーバー)にあるJavaScriptファイルを、自分のウェブページに読み込んで使うことを指す。
・ウェブページは、<script>タグを使って外部のJavaScriptファイルを読み込むことができる。

<script src="https://他のドメインのURL/script.js"></script>

クロスドメインのイメージ

https://www.cardinalpath.com/blog/cross-domain-and-roll-up-reporting より画像引用

・クロスドメインのスクリプト読み込みが必要な理由
①共通ライブラリの利用
(例)Google Analyticsのような共通のライブラリを、複数のサイトで共有する場合に便利。
②CDNの利用
コンテンツ配信ネットワーク(CDN)を使って、高速にスクリプトを配信することができる。
③外部サービスの統合
(例)Google MapsやYouTubeの埋め込みなど、外部サービスを利用する際に必要。

・JSONP (JSON with Padding) は、クロスオリジンリクエストを可能にするための技術で、もともと、JavaScript の XMLHttpRequest (AJAX) では、同一生成元ポリシー(Same-Origin Policy) によって、異なるドメインへのリクエストが制限されていた。しかし、<script> タグはクロスオリジンでの読み込みが許可されていたため、その特性を利用して JSON データを取得する方法が JSONP 。
・JSONP の仕組み
①クライアントがスクリプトタグを動的に作成し、src 属性に API のエンドポイントを指定する。
②サーバーは JSON データを JavaScript 関数の引数として返す (「パディング」する)。
③クライアント側で指定した関数が実行され、データを受け取る。

※AJAX(Asynchronous JavaScript and XML)

https://jitera.com/ja/insights/5480 より画像引用

・Webページの一部を非同期的に更新するための技術。
・JavaScriptを使用して、サーバーとデータのやり取りを行う。
・ユーザーエクスペリエンスを向上させるために使用される。

※XMLHttpRequest

https://blog.grancursosonline.com.br/ajax-formas-criacao-objeto-xmlhttprequest/ より画像引用

・JavaScriptからHTTPリクエストを送信するためのオブジェクト。
・AJAXにおけるサーバーとの通信を担う。
・データの送受信を行うための機能を提供する。

form 要素の action 属性

・クロスドメインの指定が可能
・form の送信(submit)はJavaScriptから常に操作できる
・CSRF攻撃では、ユーザの意図しない form を送信させられ、アプリケーションの機能が勝手に実行される。

mabomabo

CDNからのデータ取得と同一生成元ポリシーの関係

同一生成元ポリシーの基本的なルール

同一オリジン

同一オリジンからのリソースへのアクセスは許可される。
例えば、https://example.com/page1.html から https://example.com/script.js へのスクリプトの読み込みは許可される。

異なるオリジン

異なるオリジンからのリソースへのアクセスは、原則として禁止される。
例えば、https://example.com から https://cdn.example-cdn.com/script.js へのスクリプトの読み込みは、同一生成元ポリシーによって制限される可能性がある。

CDN(コンテンツデリバリーネットワーク)のような異なるオリジンからのリソースへのアクセス

CDNは、世界中に分散されたサーバーからコンテンツを配信することで、ウェブサイトの表示速度を向上させるサービスのこと。CDNを利用する場合、ウェブサイトのオリジンとCDNのオリジンが異なるため、同一生成元ポリシーによってアクセスが制限される可能性がある。
しかし、以下の方法でCDNなどの異なるオリジンからのリソースへのアクセスを許可できる。

CORS(Cross-Origin Resource Sharing)


https://qiita.com/hirohero/items/886733f50f37404235db より画像引用

CORSは、サーバーが異なるオリジンからのリクエストを許可するための仕組み。
オリジンサーバーが特定のオリジンからのアクセスを許可するために、HTTPヘッダーを使用して設定を行う仕組み
サーバーは、HTTPヘッダーを使用して、許可するオリジン、メソッド、ヘッダーなどを指定する。
これにより、ウェブサイトは、CDNなどの異なるオリジンからのリソースを安全に読み込むことができる。

アクセスされる側のサーバー(オリジンサーバー)が、どのオリジン(ドメイン)からのアクセスを許可するかを制御する仕組み
CORSはアクセスされる側のサーバーが「このオリジンからのアクセスなら許可する」という許可リストを作成し、ブラウザがそのリストに従ってアクセスを制御する仕組みと言える。

※CROSはあくまでもサーバー側の設定であるため、クライアント側(ブラウザ)では制御できない。


https://qiita.com/hirohero/items/886733f50f37404235db より画像引用

流れ

アクセスされる側のサーバーが許可リストを作成
CORSの設定は、アクセスされる側のサーバーが行なう。このサーバーは、どのオリジンからのリクエストを受け入れるかをHTTPヘッダーで指定する。
具体的には、「Access-Control-Allow-Origin」というヘッダーを使って、許可するオリジンを指定する。

ブラウザが許可リストをチェック
ブラウザは、クロスオリジンリクエストを行う際に、サーバーからの応答ヘッダーをチェックし、リクエスト元のオリジンが許可されているかどうかを確認する。
許可されていない場合、ブラウザはレスポンスをJavaScriptに渡さず、エラーとして処理する。

サブオリジンの利用

CDNのドメインをサブオリジンとして利用する方法。

https://it-infomation.com/samesite-crosssite-sameorigin-crossorigin/ より画像引用

例えば、https://example.com のウェブサイトで https://cdn.example.com のCDNを利用する場合、同一オリジンとして扱われるため、同一生成元ポリシーによる制限を受けない。

リバースプロキシ

リバースプロキシを利用することで、CDNのコンテンツを自社サーバーのコンテンツとして配信する方法。これにより、ブラウザからは同一オリジンからのアクセスに見えるため、同一生成元ポリシーによる制限を受けない。

https://jitera.com/ja/insights/39365 より画像引用


https://atmarkit.itmedia.co.jp/ait/articles/1608/25/news034.html より画像引用

cf. フォワードプロキシ

https://jitera.com/ja/insights/39365 より画像引用

JavaScriptとサーバーから受け取るデータ形式

①HTML (Webページ)
・概要:サーバーから受け取る最も一般的な形式で、ブラウザがレンダリングして表示する。
・DOMアクセス:documentオブジェクトを介してDOMにアクセスし、操作できる。
②JSON (JavaScript Object Notation)
・概要:軽量なデータ交換形式で、JavaScriptで簡単に扱うことができる。
・DOMアクセス:JSONデータを解析し、DOMに動的に反映させることができる。
③XML (Extensible Markup Language)
・概要:データを構造化して表現するためのマークアップ言語。
・DOMアクセス:XMLデータを解析し、DOMに動的に反映させることができる。
④テキストファイル
・概要:プレーンテキスト形式のデータ。
・DOMアクセス:テキストデータをそのまま表示したり、解析してDOMに反映させたりできる。
⑤バイナリデータ (画像、動画、音声など)
・概要:画像、動画、音声などのバイナリデータ。
・DOMアクセス:バイナリデータを解析し、DOMに動的に反映させることができる。
⑥CSV (Comma-Separated Values)
・概要:表形式のデータをカンマで区切ったテキスト形式。
・DOMアクセス:CSVデータを解析し、DOMに動的に反映させることができる。

mabomabo

HTTPリクエストの主な方法

①HTMLの<form>タグ

HTMLの<form>タグは、ユーザーが入力したデータをサーバーに送信するための最も基本的な方法。
<form>タグを使うと、ブラウザが自動的にHTTPリクエストを生成し、サーバーに送信する。

(例1)GETリクエスト

GETリクエスト
<form action="/submit" method="GET">
    <input type="text" name="username" placeholder="ユーザー名">
    <input type="password" name="password" placeholder="パスワード">
    <button type="submit">送信</button>
</form>

・action:リクエストを送信するURLを指定
・method:HTTPメソッド(GETまたはPOST)を指定
・name:入力フィールドの名前。これがクエリパラメータやリクエストボディのキーになる
このフォームを送信すると、ブラウザは以下のようなURLにリクエストを送信する

/submit?username=入力された値&password=入力された値

(例2)POSTリクエスト

POSTリクエスト
<form action="/submit" method="POST">
    <input type="text" name="username" placeholder="ユーザー名">
    <input type="password" name="password" placeholder="パスワード">
    <button type="submit">送信</button>
</form>

このフォームを送信すると、ブラウザは以下のようなHTTPリクエストを送信する

POST /submit HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=入力された値&password=入力された値

②リンク(<a>タグ)

<a>タグを使うと、ユーザーがリンクをクリックしたときにGETリクエストが送信される

<a href="/page">ページに移動</a>

このリンクをクリックすると、ブラウザは/pageにGETリクエストを送信する。

③ページの読み込み

ブラウザがページを読み込むときも、自動的にHTTPリクエストが送信される。
例えば、<img>タグや<script>タグ、<link>タグなどは、リソースを取得するためにHTTPリクエストを送信する。

<img src="/image.png" alt="画像">
<script src="/script.js"></script>
<link rel="stylesheet" href="/style.css">

④JavaScriptによるリクエスト

fetch APIやXMLHttpRequestを使うと、JavaScriptからプログラム的にHTTPリクエストを送信できる。
これにより、ページを再読み込みせずにデータを送受信できる。

fetch('/submit', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username: 'user', password: 'pass' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('エラー:', error));

⑤その他のHTTPクライアント

・cURL: コマンドラインからHTTPリクエストを送信するツール。
・Postman: GUIベースのHTTPクライアントで、リクエストを簡単にテストできる。
・Axios: JavaScriptのHTTPクライアントライブラリで、ブラウザとNode.jsで使用可能。

mabomabo

Webアプリケーションの機能と脆弱性の対応

スクリプト出力と混入しやすい脆弱性の例

・HTMLの出力(クロスサイト・スクリプティング)
・HTTPヘッダの出力(HTTPヘッダ・インジェクション)
・SQLの呼び出し(SQLインジェクション)
・シェルコマンドの呼び出し(OSコマンド・インジェクション)
・メールヘッダおよび本文の出力(メールヘッダ・インジェクション)

◎脆弱性には、①処理に起因するもの出力に起因するもの がある。
・入力に起因する脆弱性はない
出力に起因する脆弱性には「インジェクション」という単語がつくものが多い

◎Webアプリケーションの脆弱性は機能との関連性が強いため、設計やプログラミングしている時点で、注意すべき脆弱性は自動的に判別できる。

インジェクション系脆弱性

基本的に 「外部からの入力が適切に処理されず、意図しないコードやコマンドが実行される」 という共通した攻撃手法に基づいている。
データの中に引用符やデリミタなど「データの終端」を示すマークを混入させて、その後の文字列の構造を変化させる。

SQLインジェクション脆弱性が発生する原因は、もともと「データ」を想定しているところにシングルクウォート「'」を使って、データ部分を終わらせ、SQL文の構造を変化させるところにある。

インジェクション系脆弱性の比較

脆弱性名 インターフェース 悪用手口 データの終端
クロスサイト・スクリプティング HTML JavaScriptなどの注入 <"など
HTTPヘッダ・インジェクション HTTP HTTPレスポンスヘッダの注入 改行
SQLインジェクション SQL SQL命令の注入 'など
OSコマンド・インジェクション シェルスクリプト コマンドの注入 ; |など
メールヘッダ・インジェクション sendmailコマンド メールヘッダ
本文の注入・改変
改行

「外部からの入力を信頼しない」「適切に処理する」 ことが、どのインジェクション攻撃でも共通の防御手段になる。


https://blog.flatt.tech/entry/how_to_deal_with_injection_vulnerabilities より画像引用

Webアプリケーション脆弱性の全体像

mabomabo

入力処理とセキュリティ


https://xtech.nikkei.com/it/article/COLUMN/20090208/324377/ より画像引用

「入力」ですること

「入力」とは、アプリケーションロジックの処理が始まる前にデータを準備する段階にあたる。
Webアプリケーションの入力には、HTTPリクエストとして渡されるパラメータ(GET, POST, Cookieなど)がある。

HTTPリクエスト → 入力 → 処理(アプリケーションロジック) → 出力 → HTTPレスポンス


https://xtech.nikkei.com/it/article/COLUMN/20090507/329626/ より画像引用

入力処理で入力値に対して行なう処理

①文字エンコーディングの妥当性検証

・文字コードを使った攻撃手法がある。
※プログラムが正しく動作するためには、文字エンコーディングが正常であることが前提となっており、その前提条件を保証するための処理

bool mb_check_encoding(string $var, string $encoding)

・第一引数の $var :チェック対象の文字列
・第二引数の $encoding :省略可能
 ※省略した場合、PHPの内部文字エンコーディングが使われる。

②文字エンコーディングの変換(必要な場合のみ)

・文字エンコーディングの変換が必要なケースは、HTTPメッセージとプログラム内部で文字エンコーディングが異なる場合
・文字エンコーディングの交換手段は言語によって異なる。
・おおまかな分類として、文字エンコーディングを自動的に変換する言語と、スクリプトで変換ロジックを明示する言語がある。

https://gihyo.jp/admin/serial/01/charcode/0004 より画像引用

※文字エンコーディングの自動変換とセキュリティ
文字エンコーディングを変換すると、不正な文字エンコーディングは削除されるか、別の文字(?やUnicodeの代替文字U+FFFD)に置き換えられるので、不正な文字エンコーディングによる攻撃は防止できる。

自動変換を行なったときのデメリット
・文字が化けた場合でも、利用者が気づかずに処理を継続してしまう
・サーバーの移転などで php.ini が変更された場合に、チェックが掛からなくなる危険性がある
自動変換・手動変換どちらを採用するかは、開発チームとしてポリシーを決めるか、プロジェクトごとに決定すると良い。

③パラメータ文字列の妥当性検証

・セキュリティ上の要求というより、アプリケーションの仕様に基づいて行なうもの

mabomabo

入力値の検証

文字エンコーディング関連の処理が終わったら、入力値の検証を行なう。
入力値の検証はあくまでも書式のチェックなので、書式以外の条件はチェックしない。


https://blog.flatt.tech/entry/how_to_deal_with_injection_vulnerabilities より画像引用

目的
・利用者の入力ミスを早期に発見して再入力を促すことで、アプリケーションの使いやすさを向上する。
・間違った処理を継続することによるデータの不整合を防ぎ、システムの信頼性を向上させる。

※入力値の検証がされていないアプリケーションで起こること
①数値のみを受け付ける項目に英字や記号を入力して、データベースエラーになる。
②更新処理が途中でエラーになり、データベースの不整合が発生する。
③利用者が多数の項目を入力して実行ボタンをクリックしたら内部エラーとなり、入力が最初からやり直しになる。
④メールアドレスの入力を忘れているのにアプリケーションがメール送信処理を実行する。

入力値検証とセキュリティ

入力値検証がセキュリティの役に立つケース
・SQLインジェクション対策が漏れていたパラメータがあるが、英数字のみ許可していたので実害に至らない
・PHPのバイナリセーフでない関数を使っているが、入力段階で制御文字をチェックしているので実害に至らない
・表示処理の関数に文字エンコーディングの指定を怠っているが、入力段階で不正な文字エンコーディングをチェックしているので実害に至らない。

mabomabo

文字エンコーディングの目的・使い方


https://step-learn.com/article/fundamental/001-char-encoding.html より画像引用

目的

文字のデジタル表現・文字のコード化

文字をコンピュータが処理できるバイナリデータ(0と1)に変換する。

異なるシステム間での互換性

異なるシステムやアプリケーション間でテキストデータを正しくやり取りする。

多言語対応

世界中の言語や特殊記号をサポートし、多様な文字を表現する。

データの整合性

テキストデータの保存や転送時に情報が失われないようにする。

使い方

エンコーディングの選択

用途に応じて適切なエンコーディングを選ぶ(例:UTF-8、Shift_JIS)。

テキストのエンコード

テキストを指定したエンコーディングでバイナリデータに変換する。

テキストのデコード

バイナリデータを元のテキストに戻す。

ファイルの保存と読み込み

ファイルを保存する際にエンコーディングを指定し、読み込む時も同じエンコーディングを使用する。

通信プロトコルでの使用

ネットワーク通信でデータを送受信する際にエンコーディングを指定する。

主なエンコーディング
・UTF-8:多言語対応で広く使用される。
・Shift_JIS:日本語環境でよく使われる。
・EUC-JP:主にUNIX系システムで使用される日本語エンコーディング。

mabomabo

バイナリセーフという考え方とヌルバイト攻撃

バイナリセーフ:入力値がどんなバイト列であっても正しく扱うことができる

①NULLバイトを安全に扱える
・バイナリデータには、NULLバイト(\0)が含まれることがある。C言語など、一部のプログラミング言語では、NULLバイトを文字列の終端として扱うため、バイナリデータを文字列として扱うと、意図しないところでデータが途切れてしまう可能性がある。
※このような関数をバイナリセーフではないという。
・バイナリセーフな関数や処理は、NULLバイトを特別な文字として扱わず、データの一部として正しく処理できる。
②任意のバイト列を安全に扱える
・バイナリデータは、テキストデータのように特定の文字コードに従っているとは限りません。そのため、どのようなバイト列が含まれていても、正しく処理できる必要がある。
・バイナリセーフな関数や処理は、どのようなバイト列が入力されても、データの破損や誤動作を起こさずに処理できる。

ereg 関数はバイナリセーフの関数ではないため、検査対象文字列にヌルバイト(%00など)があると、そこで文字列が終わっていると判断する。

◎アプリケーションの入り口でバイナリセーフの関数を用いて、入力値のヌルバイトをチェックし、ヌルバイトがあればエラーにすることにより、確実な対応が可能になる。

○入力値検証だけでは対策にならない
○入力値検証の基準はアプリケーション要件
○制御文字のチェック
※制御文字:テキストデータや通信プロトコルの中で特殊な機能を表す非表示の文字。ASCIIコードの0から31、および127に割り当てられている。
○文字数のチェック
すべてのパラメータについて、最大文字数を仕様として定義すべき。
動作保証するための最大文字数を仕様として決める必要がある。
最大文字数をチェックしておくと、セキュリティ上の保険的対策になる場合がある。
○数値の最小値・最大値のチェック
数値項目について行なうといいこと
・最小値と最大値の範囲内にあることの確認
・数値文字列としての文字種・文字数のチェック
・文字列型から数値型への型変換

mabomabo

DoS攻撃(Denial of Service Attack)


https://www.lanscope.jp/blogs/cyber_attack_pfs_blog/20231024_15726/ より画像引用

サーバーやネットワークに過剰な負荷をかけることで、サービスを利用不能にする攻撃

DoS攻撃の種類

リソース枯渇型

サーバーのリソース(CPU、メモリ、帯域幅など)を過剰に消費させ、サービスを停止させる。
(例)SYN Flood攻撃、UDP Flood攻撃。

脆弱性攻撃型

ソフトウェアの脆弱性を突き、サービスをクラッシュさせる。
(例)Ping of Death、Teardrop攻撃。

アプリケーション層攻撃

アプリケーションの特定の機能に負荷をかける。
(例)HTTP Flood攻撃、Slowloris攻撃。

mabomabo

入力値の検証

◎アプリケーションの入り口でバイナリセーフの関数を用いて、入力値のヌルバイトをチェックし、ヌルバイトがあればエラーにすることにより、確実な対応が可能になる。

○入力値検証だけでは対策にならない

○入力値検証の基準はアプリケーション要件

検証内容

制御文字のチェック
※制御文字:テキストデータや通信プロトコルの中で特殊な機能を表す非表示の文字。ASCIIコードの0から31、および127に割り当てられている。

文字数のチェック
すべてのパラメータについて、最大文字数を仕様として定義すべき。
動作保証するための最大文字数を仕様として決める必要がある。
最大文字数をチェックしておくと、セキュリティ上の保険的対策になる場合がある。

数値の最小値・最大値のチェック
数値項目について行なうといいこと
・最小値と最大値の範囲内にあることの確認
・数値文字列としての文字種・文字数のチェック
・文字列型から数値型への型変換

○filter_input()
配列でない値を期待したプログラムに入力値として配列が指定されると、思わぬバグや脆弱性の原因になる場合があるため、関数でこういった事態を防ぐ。

○パラメータの検証対象
入力値検証となるのはすべてのパラメータ
クッキーにセッションID以外の値を入れているときは、クッキーの値も検証する。

○正規表現
入力値検証には正規表現が便利。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

preg_match()

u 修飾子

日本語環境でpreg_match関数を用いる場合はUTF-8エンコーディングであることを示す u 修飾子を指定する。

i 修飾子

大文字・小文字を区別しないでマッチングする場合に使用する。

全体一致は\A\zで示す

データの先頭は\A、データの末尾は\zで示す。
\A\zの代わりに、^$を使う場合があるが、「行の」先頭と末尾を示すものであるため、$が改行にマッチすることから^$をデータの先頭・末尾として使うと不具合が生じる場合がある。
※改行文字がチェックをすり抜けてしまう。

文字クラス

[] に囲まれた部分は文字クラスという。
角括弧内に文字を列挙するか、[0-9]のように範囲を指定する。

量指定子

{}で囲まれた部分。
空文字でもいい場合は {0, 5}のように指定する。

住所欄や氏名欄などは、通常文字種の制限がなく、文字数のみが指定されている場合が多いが、文字種の制限がない場合でも、制御文字が混入していないというチェックをすべきで、これによりヌルバイト攻撃を防ぐことができる。

※定義済み文字クラスには開発者の意図以外の文字がマッチする可能性があるため、[A-Za-z0-9_]などと文字クラスを明示する方が安全

mabomabo

Webアプリケーションの入り口で行なう検証


https://www.ssk-kan.co.jp/topics/topics_cat05/?p=12564 より画像引用

・入力値の検証はアプリケーション仕様に基づいて行なう
・文字エンコーディングの検証
・制御文字を含む文字種の検証
・文字数の検証
・数値の最小値・最大値の検証

実施は以下の手順で行なう
①設計段階で各パラメータの文字種および最大文字数、最小値・最大値を仕様として決める
②設計段階で入力値検証の実装方針を決める
③開発段階では仕様に従い入力値検証を実装する

表示処理に伴う問題

表示処理が原因で発生する問題
・クロスサイト・スクリプティング
・エラーメッセージからの情報漏洩

mabomabo

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


https://eset-info.canon-its.jp/malware_info/special/detail/221115.html より画像引用

WebアプリケーションにXSS脆弱性がある場合の影響
・サイト利用者のブラウザ上で、攻撃者の用意したスクリプトの実行によりクッキー値を盗まれ、利用者がなりすましの被害にあう。
・同じくブラウザ上でスクリプトを実行させられ、サイト利用者の権限でWebアプリケーションの機能を悪用される。
・Webサイト上に偽りの入力フォームが表示され、フィッシングにより利用者が個人情報を盗まれる。
Webアプリケーションには外部から変更できるパラメータを表示する箇所が多数含まれるが、そのうち一箇所でもXSS脆弱性があると、サイトの利用者がなりすましの被害を受ける恐れがある。

※Crossサイト・Sameサイトの違い

https://it-infomation.com/samesite-crosssite-sameorigin-crossorigin/ より画像引用

反射型

格納型

https://www.ubsecure.jp/blog/cross-site-scripting より画像引用

対策

表示の際にHTMLで特殊な意味をもつ記号文字(メタ文字)をエスケープすること

XSS脆弱性

発生箇所

Webアプリケーション上でHTML、JavaScriptを生成している箇所

影響を受けるページ

Webアプリケーション全体が影響を受ける

影響の種類

Webサイト利用者のブラウザ上でのJavaScriptの実行、偽情報の表示

利用者の関与の度合い

罠サイトの閲覧、メール記載のURLの起動、攻撃を受けたサイトの閲覧など

対策の概要

・属性値はダブルクウォート「""」で囲む
・HTMLで特別な意味を持つ記号文字をエスケープする

攻撃手法と影響

①クッキー値の盗み出し

外部から注入されたJavaScriptによってセッションIDの読み出しが可能

受動的攻撃により別人のクッキー値を盗み出す

罠サイトの構造の例
①罠サイトの iframe 内で、脆弱なサイトが表示される
②脆弱なサイトはXSS攻撃により、クッキー値をクエリ文字列につけて、情報収集ページに遷移する
③情報収集ページは受け取ったクッキー値をメールで攻撃者に送信する

②その他のJavaScriptによる攻撃

APIは悪用することも可能なため、XSSとJavaScriptの組み合わせによる攻撃がしやすいため、使用する際には注意が必要。

XSSを悪用したワーム(XSS Worm)は、XSS(クロスサイトスクリプティング)の脆弱性を利用して、自動的に拡散する悪意のあるスクリプトのこと。
このワームは、ユーザーのブラウザ上で動作し、他のユーザーにも感染を広げることで、急速に拡散する特徴がある。

XSSワームの仕組み
①XSS脆弱性のあるサイトを利用
攻撃者は、XSS脆弱性のあるサイトを見つける。この脆弱性は、ユーザー入力が適切に処理されず、スクリプトが実行される場合に発生する。

②ワームスクリプトを仕込む
攻撃者は、悪意のあるスクリプト(ワーム)を脆弱なサイトに仕込む。
このスクリプトが行なう動作
・ユーザーのセッション情報(クッキーなど)を窃取
・他のユーザーに自動的に感染するためのリンクやメッセージを生成
・ユーザーのアクション(例: ボタンクリック)を自動化

③ワームの拡散
ユーザーが脆弱なサイトにアクセスすると、ワームスクリプトが実行される。
このスクリプトで他のユーザーに感染を広げる方法
・自動投稿:ユーザーのアカウントを利用して、SNSやフォーラムに自動的に悪意のあるリンクを投稿する。
・メッセージ送信:ユーザーの連絡先リストを利用して、メッセージやメールを自動送信する。
・リダイレクト:ユーザーを他の脆弱なサイトにリダイレクトし、さらに感染を広げる。

④連鎖的な拡散
感染したユーザーが他のユーザーとやり取りするたびに、ワームが自動的に拡散する。
これにより、ワームは急速に広がり、大規模な影響を及ぼすことがある。

③画面の書き換え

XSS脆弱性はログイン機能のないサイトでも影響がある。
$_POSTの前につける@はエラー制御演算子というもので、POST変数が未定義の場合のエラーを抑止するために使用する。
◎XSS攻撃は常にJavaScriptを使うとは限らない。
(例)元の form を隠し、新たな form 要素を追加することにより画面を改変する

反射型XSS・持続型XSS

反射型XSS

攻撃用のJavaScriptが、攻撃対象サイトとは別のサイトにある場合
多くの場合、入力値をそのまま表示するページで発生する。
典型例:入力値の確認用ページ

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

持続型XSS

攻撃用のJavaScriptが、攻撃対象のデータベースなどに保存される場合
WebメールやSNSなどが典型的な攻撃ターゲット
HTMLを生成している箇所に原因がある。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

脆弱性が生まれる理由

HTML生成の際に、HTMLの文法上特別な意味を持つ特殊記号(メタ文字)を正しく扱っていないことにより、開発者の意図しないHTMLやJavaScriptを注入・変形されているため。

mabomabo

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

脆弱性が生まれる理由

HTML生成の際に、HTMLの文法上特別な意味を持つ特殊記号(メタ文字)を正しく扱っていないことにより、開発者の意図しないHTMLやJavaScriptを注入・変形されているため。

XSS攻撃は、WebブラウザがHTML文書を解釈する際に、ユーザーが入力した文字列をHTMLの一部として誤って解釈してしまうことで発生する。
例えば、ユーザーが<script>alert("XSS");</script>という文字列を入力フォームに入力し、サーバーがこの文字列をそのままHTMLに出力した場合、ブラウザはこの文字列をJavaScriptのコードとして解釈し、実行してしまう。

ブラウザは、<script>alert("XSS");</script>という文字列をHTMLとして解釈するが、<や>はそれぞれ <> として表示されるだけで、<script>タグとして解釈されることはない。
つまり、エスケープ処理によって、ユーザーが入力した文字列は単なる文字列として表示されるだけで、スクリプトとして実行されることはない。

エスケープされた文字列は、HTMLタグとしては解釈されない。
ブラウザは、<script>を<script>タグとは認識せず、JavaScriptコードとして実行しない。
これにより、悪意のあるスクリプトがWebページ上で実行されるのを防ぐことができる。

HTMLエスケープの概要

メタ文字の持つ特別な意味を打ち消し、文字そのものとして扱うエスケープ処理。
HTMLのデータは、構文上の場所に応じてエスケープすべきメタ文字も変わる。
HTMLエスケープは、Webページへの出力時に行なうのが基本
※HTMLエスケープは、あくまでもタグとして認識させないための処理であり、HTMLタグを無効化するものではない。エスケープされた文字列は、ブラウザによって元の文字に戻されて表示される。

パラメータが置かれた場所とエスケープ方法

置かれている場所 説明 最低限のエスケープ内容
要素内容 ・タグと文字参照が解釈される
・「<」で終端
<」と「&」を文字参照に
属性値(ダブルクウォートで括られたもの) ・文字参照が解釈される
・ダブルクウォートで終端
属性値を「"」で囲み、「<」「"」「&」を文字参照に

※エスケープ

https://cybersecurity-jp.com/column/33684 より画像引用

ユーザーが入力した情報をエスケープする主な目的は、ユーザー入力に基づいて動的に生成されるコンテンツが、意図しないHTML構造になったり、セキュリティ上の問題を引き起こしたりするのを防ぐこと。

サーバーサイドでの処理

Webアプリケーションのサーバーサイドでは、データベースから取得したデータやユーザーからの入力データをHTMLに埋め込む際に、テンプレートエンジンやWebアプリケーションフレームワークの機能を利用して、データをHTMLに埋め込む直前にエスケープ処理を行なう。

HTMLエスケープのタイミング

① サーバーサイドでの処理
データベースから取得したデータやユーザーからの入力データをHTMLに埋め込む際に、テンプレートエンジンやWebアプリケーションフレームワークの機能を利用して、データをHTMLに埋め込む直前にエスケープ処理を行なう

② HTTPレスポンス送信直前

要素内容のXSS
・XSSによるクッキー値の盗み出し
・「<」のエスケープができていない場合に発生する

引用符で囲まない属性値のXSS
属性値を引用符で囲まない場合、空白で属性値の終わりになる。
→空白を挟んで、属性を追加することができる。

引用符で囲った属性値のXSS
属性値を引用符で囲っていても、「"」をエスケープしていないとXSS攻撃が可能。

サーバー側でのエスケープ処理

主な役割
ユーザーからの入力データをデータベースに保存する前や、HTMLとして出力する直前にエスケープ処理を行なうことで、悪意のあるスクリプトがWebページに埋め込まれるのを防ぐ(XSS攻撃に対する主要な防御策)

利点
・クライアント側の環境に依存せず、確実にエスケープ処理を行なうことができる
・データベースに保存する段階でエスケープ処理を行なうことで、後続の処理でエスケープ処理を忘れるリスクを減らすことができる

注意点
・エスケープ処理を行なうタイミングや方法を誤ると、意図しない表示結果になることがある
・すべての入力データをエスケープ処理するのではなく、出力先のコンテキスト(HTML、JavaScriptなど)に応じて適切なエスケープ処理を行なう必要がある

mabomabo

Webアプリケーションの動作原理

HTTPリクエストからHTTPレスポンスまでの流れ

① ユーザーがHTMLフォームに入力し、送信する
・ユーザーがWebページ上のフォームにデータを入力し、<form>タグのsubmitボタンをクリック。
・<form>タグのmethod属性で指定されたHTTPメソッド(通常はGETまたはPOST)が使用される。
・action属性で指定されたURLにデータが送信されます。

② データのエンコーディング
・フォームデータは、<form>タグのenctype属性に基づいてエンコードされる。
・application/x-www-form-urlencoded: デフォルト。キーと値がURLエンコードされる。
・multipart/form-data: ファイルアップロード時に使用される。
・エンコードされたデータは、HTTPリクエストのボディ(POSTの場合)またはクエリ文字列(GETの場合)として送信される。

③ HTTPリクエストの送信
・ブラウザは、エンコードされたデータをHTTPリクエストとしてサーバーに送信。
・リクエストには、HTTPメソッド、ヘッダー(例: Content-Type、Content-Length)、ボディ(POSTの場合)が含まれる。

④ サーバー側でのリクエスト受信
・サーバーはHTTPリクエストを受信し、リクエストヘッダーやボディを解析。
・サーバーは、リクエストされたURLやHTTPメソッドに基づいて適切な処理を行なう。

⑤ サーバー側での入力検証
・サーバーは、クライアントから送信されたデータを検証する。
・必須フィールドのチェック、データ形式の検証(例: メールアドレスの形式)、セキュリティチェック(例: XSSやSQLインジェクション対策)などが行われる。
・検証に失敗した場合、エラーメッセージを含むHTTPレスポンスがクライアントに返される。

⑥ サーバー側でのデータ処理
・検証を通過したデータは、サーバー側のアプリケーション(例: PHP、Python、Node.jsなど)で処理される。
・データベースへの保存、ビジネスロジックの実行、外部APIとの連携などが行われる。

⑦ HTTPレスポンスの生成
・サーバーは、処理結果に基づいてHTTPレスポンスを生成する。
・レスポンスには、ステータスコード(例: 200 OK、404 Not Found)、ヘッダー(例: Content-Type)、ボディ(例: HTML、JSON)が含まれる。

⑧ HTTPレスポンスの送信
・サーバーは、生成したHTTPレスポンスをクライアントに送信。

⑨ クライアント側でのレスポンス受信
・ブラウザはHTTPレスポンスを受信し、ステータスコードやヘッダーを解析。
・レスポンスボディがHTMLの場合、ブラウザはHTMLをレンダリングして表示。
・レスポンスボディがJSONなどのデータ形式の場合、JavaScriptで処理されることがある。

⑩ データのデコードと表示
・ブラウザは、必要に応じてデータをデコード(例: URLエンコードされたデータをデコード)。
・最終的に、ユーザーに結果が表示される。

mabomabo

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

対策

XSS対策の基本
通常の(JavaScriptやCSSでない)HTMLについては、文字参照によりエスケープすることが基本
要素内容については「<」「&」をエスケープする
 ※script 要素やstyle 要素の内容は例外
属性値については、ダブルクォートで囲って「<」「&」「"」をエスケープする

PHPではHTMLのエスケープ処理に htmlspecialchars 関数が利用できる。

書式
string htmlspecialchars (string $string, int $quote_style, string $charset);

htmlspecialchars 関数で指定する文字エンコーディングは、内部文字エンコーディングで、正しく指定しないと、処理がおかしくなる場合があるので、必ず第3引数を指定すること。

htmlspecialchars関数の引数

引数 説明
$string 変換対処の文字列
$quote_style 引用符の変換方法
$charset 文字エンコーディング
※必ず指定すること
"UTF-8", "Shift-JIS", "EUC-JP"

・要素内容については $quote_style はどの値でもよい
・属性値はダブルクォートで囲む
・$quote_style はENT_COMPATかENT_QUOTESを指定する
※要素内容と属性値のどちらもENT_QUOTESで統一するのもOK

ENT_COMPAT
・"Compatibility"(互換性)の略。
・意味:ダブルクォート (") のみをエンティティに変換し、シングルクォート (') は変換しません。

ENT_QUOTES
・"Quotes"(引用符)の略。
・意味:ダブルクォート (") とシングルクォート (') の両方をエンティティに変換する。

エンティティ
・HTMLやXMLなどのマークアップ言語において、特殊な文字や記号を表現するための仕組み 
・具体的には、特定の文字をエンティティ参照(Entity Reference)として記述することで、その文字を安全に表示したり、ブラウザが正しく解釈できるようにしたりする。
(例)&lt; => < (小なり記号)
・2つの形式:文字実体参照(例: <)・数値文字参照(例: <)


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

レスポンスの文字エンコーディング指定
Webアプリケーション側で想定している文字エンコーディングとブラウザが想定する文字エンコーディングに差異があると、XSS攻撃の原因になり得る。
最も確実な文字エンコーディング指定方法は header 関数を用いること

header('Content-Type: text/html; charset=UTF-8');

XSSに対する保険的対策

X-XSS-Protection レスポンスヘッダの使用

利用者によるXSSフィルタ設定を上書きして有効化・無効化を設定したり、その動作モードを変更したりするための機能。
※XSSフィルタ:反射型XSSをブラウザが検知し、無害な出力に変更するもの

X-XSS-Protection: 1; mode=block

すべてのHTTPレスポンスで出力することが推奨されている

Apacheの設定

Header always append  X-XSS-Protection: 1; mode=block

nginxの設定

add_header  X-XSS-Protection: 1; mode=block;

入力値検証

入力値検証がXSS対策になるのは、入力値の条件が英数字のみに限定されている場合に限られる。
自由書式の入力欄についてはこの方法で対策できない。

クッキーにHttpOnly属性を付与する

HttpOnly属性は、JavaScriptからのクッキーの読み出しを禁止するもの。
クッキーにHttpOnly属性を付与することで、セッションIDの盗み出しを防止することができる。
PHPで開発する場合、セッションIDにHttpOnly属性を付与するためには、php.ini に以下の設定を追加しよう

session.cookie_httponly = On

Traceメソッドの無効化

※「Traceメソッドの無効化とXST」参照

対策まとめ

必須(共通)
HTTPレスポンスに文字エンコーディングを明示する

必須(個別)
・HTMLの要素内容: htmlspecialchars 関数によりエスケープ
・属性値: htmlspecialchars 関数によりエスケープしてダブルクォートで囲む

保険的対策
・X-XSS-Protection レスポンスヘッダの使用
・入力値の検証
・クッキーにHttpOnly属性を付与
・Traceメソッドの無効化

エンティティ

※エンコードやエスケープ処理におけるエンティティとは、特定の文字や記号を、別の表現方法(通常は文字列)に置き換えたもののことを指す。

(例)
HTMLエンティティ
HTML文書内で、特定の記号(例えば <>&"' など)をそのまま記述すると、HTMLの構文として解釈されてしまうため、これを避けるために、これらの記号は特殊な文字列(エンティティ参照)に置き換えられる。
< → < (less than)
> → > (greater than)
& → & (ampersand)
" → " (quotation mark)
' → ' (apostrophe)
例えば、HTML内で 1 < 2 と表示したい場合、そのまま記述すると < がタグの開始と解釈される可能性があるため、1 < 2 と記述する。< が < のエンティティということになる。

XMLエンティティ
XMLでも同様に、<>&"' などは特別な意味を持つため、エンティティ参照を使って表現する。HTMLエンティティとほぼ共通だが、XMLでは ' のエンティティ参照 ' の使用が必須ではない(属性値の囲み文字と異なる場合はそのまま記述できる)。

URLエンコード (パーセントエンコーディング)
URL(Uniform Resource Locator)では、特定の文字(例えばスペース、日本語、記号など)をそのまま含めることができない。これらの文字は、% に続けてその文字のASCIIコード(またはUTF-8コード)を16進数で表した形式にエンコードされる。この %XX の形式が、エンティティの一種と捉えることができる。
・スペース → %20
! → %21
" → %22
# → %23
$ → %24
% → %25
& → %26

mabomabo

クロスサイト・スクリプティング(発展編)


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

href属性やsrc属性のXSS

a要素のhref属性、img要素やframe要素、iframe要素の src属性などはURLを属性値としてとる。
このURLを外部から変更できる場合、URLとして「JavaScript: JavaScript式」という形式(javascriptスキーム)でJavaScriptを起動できる。

① URLを生成する場合の対策
URLをプログラムで生成する場合は、httpスキームとhttpsスキームのみを許可するようにチェックする必要がある。
チェックが通ったURLは、属性値としてHTMLエスケープする必要がある。

具体的に、URLとしては以下のいずれかを許容するようにするといい
http: またはhttps: で始まる絶対URL
スラッシュ「/」で始まる相対URL(絶対パス参照)

② リンク先ドメイン名のチェック
外部のドメインに対するリンクが自明の場合以外には以下のどちらかを実施するといい
・リンク先URLを検証して、URLが外部ドメインである場合はエラーにする
・外部ドメインへのリンクであることを利用者に注意喚起するためのクッションページを表示する
※外部ドメイン:自分のWebサイトやシステムが管理しているドメインとは異なる、第三者が管理しているドメインのこと
※自分がWebサイトを運営していない場合、インターネット上に存在するすべてのWebサイトは外部ドメインとなる。

JavaScriptの動的生成

イベントハンドラのXSS

JavaScriptの文字リテラルを動的生成するケース(JavaScriptの一部をサーバー側で動的生成する例)
→ JavaScriptの文字列リテラルのエスケープが抜けていることによる脆弱性

サーバーが動的に生成したJavaScriptのデータを、スクリプトとして実行されるのではなく、安全な文字列として扱うためにエスケープ処理を行なうことを指す。

背景
サーバーサイドで生成されたデータをWebページ上でJavaScriptから利用する場合、そのデータをJavaScriptの変数に代入したり、オブジェクトのプロパティとして設定したりする必要がある。
この際、データにJavaScriptの構文として解釈される文字(例えば、引用符、改行文字など)が含まれていると、意図しないスクリプトが実行されたり、構文エラーが発生したりする可能性がある。

対策
① まず、データをJavaScript文字リテラルとしてエスケープする
② この結果をHTMLエスケープする

※script要素がエスケープ処理によってタグとして認識されなければ、JavaScriptエンジンはそれをスクリプトとして実行しない。

※JavaScriptエンジンの動作
HTMLの解析
・ブラウザは、HTML文書を解析し、DOM(Document Object Model)ツリーを構築する。
・この際、<script>タグを検出すると、JavaScriptエンジンにスクリプトの実行を指示する。

スクリプトの実行
JavaScriptエンジンは、<script>タグで囲まれたコードをJavaScriptとして解釈し、実行する。
※ただし、<script>タグがエスケープ処理されると、ブラウザはそれを単なる文字列として扱い、DOMツリーにテキストノードとして追加する。JavaScriptエンジンは、DOMツリーを解析する際に、エスケープされた<script>タグを検出しても、それをスクリプトとして認識しない。その結果、エスケープされたスクリプトは実行されない。

JavaScriptの文字リテラルとしてエスケープすべき文字

文字 エスケープ後
\ \\
' \'
" \"
改行 \n


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

script要素のXSS

script要素内はタグや文字参照を解釈しないので、HTMLとしてエスケープする必要はなく、JavaScriptの文字列リテラルとしてエスケープを行なう。
しかし、これだけでは脆弱性がある。


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

HTML5の規格では、script要素内のデータには「</script」という文字の並びは出現できないことになっている。文字参照も解釈されないため、文字参照を使って書くこともできない。
そのため、生成するJavaScript のソースを変更することにより、この問題を避ける必要がある。

<script>要素の役割
<script>要素は、HTML文書の中にJavaScriptコードを埋め込むためのもの。
ブラウザは、<script>要素の中身をHTMLではなく、JavaScriptとして解釈する。

タグや文字参照の解釈
① HTMLの解釈
ブラウザは、HTML文書を読み込む際に、タグ(<p>など)や文字参照(<など)を解釈し、それぞれの意味に従って表示する。
② JavaScriptの解釈
<script>要素の中にあるJavaScriptコードは、HTMLとは異なるルールで解釈される。
JavaScriptは、タグや文字参照を特別な意味を持つものとは認識しない
<script>要素内はJavaScriptの領域なのでJavaScriptのルールで解釈される。

JavaScript の文字列リテラルの動的生成の対策

JavaScriptの文字列リテラルを動的生成する場合に従うべき原理
① JavaScriptの文法から、引用符(「"」または「'」)と「\」や改行をエスケープする
② イベントハンドラ中の場合は、①の結果を文字参照によりHTMLエスケープして、ダブルクォート「"」で囲む
③ script 要素内の場合は、①の結果に「</script」という文字列が出現しないようにする

※JavaScriptのエスケープルールは複雑で対策漏れが生じやすいため、できる限りJavaScriptを動的に生成するのは避けたいところ。

JavaScript に動的なパラメータを渡す方法

1. script 要素の外部でパラメータを定義して、JavaScriptから参照する方法
この目的のためにカスタムデータ属性が利用できる。
カスタム属性内は通常のHTMLエスケープによってXSS対策ができる。

2. インラインJSONPによる方法
JSON形式のパラメータを伴う関数をscript要素で呼び出す方法。
※JSONはJavaScriptのオブジェクトリテラルと互換性があるので、文字列はJavaScriptのデータとして扱うことができる。
PHPには、JSONを安全に生成できるjson_encode関数があり、JavaScript の動的生成に関する複雑さをこの関数に任せることができる。

HTMLタグやCSSの入力を許す場合の対策

HTMLタグの入力を許す場合、script要素やイベントハンドラによって開発者が意図しないJavaScriptの実行が可能になる場合がある。
CSSのexpressionsによりJavaScriptが起動できる。
◎HTMLタグやCSSの入力を許可するサイトを開発する場合は、HTMLテキストを構文解析して必要な要素のみを抽出するライブラリを使用することが望ましい

mabomabo

文字参照

ブラウザがHTMLを読み込む際に文字参照があった場合、基本的にはタグとしてではなく、文字列として解釈します。

文字参照の役割

HTMLにおける文字参照は、特定の文字を安全に表示するために使用されます。
例えば、「<」や「>」はHTMLタグの開始・終了記号として使われるため、そのまま記述するとブラウザがタグとして解釈してしまう可能性があります。
そこで、「<」は「<」、「>」は「>」という文字参照を使って記述することで、ブラウザに「これはタグではなく、単なる文字として表示してください」と伝えることができます。
つまり、文字参照は「特殊な意味を持つ文字を、安全な文字列に置き換えるための仕組み」と言えます。

ブラウザの解釈

ブラウザはHTMLを解析する際に、文字参照を見つけると、それを対応する文字に置き換えて表示します。
例えば、HTML内に「<p>」と記述されていた場合、ブラウザはこれを「<p>」という文字列に置き換えて表示します。
この置き換えは、HTMLの解析段階で行われるため、結果として表示されるのはあくまでも文字列です。
ただし、この置き換えのタイミングが重要で、HTMLの解析が終わった後にJavaScriptなどによってHTMLを操作すると、また違った解釈になります。

重要な注意点

文字参照は、あくまでも「文字」を表現するためのものであり、タグそのものを生成するものではありません
JavaScriptなどで動的にHTMLを生成する場合、文字列としてタグを組み立てる必要があります
この場合、文字参照を使うこともできますが、通常は直接タグを記述する方が一般的です。

まとめ

・ブラウザはHTML内の文字参照を、対応する文字列に置き換えて表示します。
・文字参照は、特殊文字を安全に表示するための仕組みです。
・JavaScripなどで動的にHTMLを生成する場合は、また違った解釈になる。

mabomabo

Webアプリケーションとブラウザの文字エンコーディング

違いと関係性

項目 Webアプリケーションの文字エンコーディング ブラウザの文字エンコーディング
役割 サーバー側でデータを処理・
保存するためのエンコーディング
クライアント側でWebページを表示
するためのエンコーディング
指定方法 ソースコード
データベース設定
HTTPヘッダー
HTTPヘッダー
<meta> タグ
ブラウザ設定
UTF-8
Shift_JIS
EUC-JP
UTF-8
ISO-8859-1
Shift_JIS
影響範囲 サーバー側のデータ処理や保存 ブラウザでの表示

エスケープ処理の違い

エスケープ処理はブラウザが誤って解釈しないようにするための重要な手段

・HTMLのエスケープ
HTMLで特別な意味を持つ文字(<、>、&など)を、文字参照(<、>、&など)に置き換えることをエスケープと言う
これは、ブラウザがこれらの文字をタグとして誤って解釈しないようにするために行なう。

・JavaScriptのエスケープ
JavaScriptでは、文字列リテラル(""''で囲まれた文字列)の中で、特別な意味を持つ文字("'\など)を、バックスラッシュ(\)を使ってエスケープする。
これは、JavaScriptがこれらの文字を文字列の一部として正しく認識できるようにするため。
JavaScriptの文字列リテラル内では、特定の文字が特別な意味を持ち、その意味が展開されることがあある。エスケープ処理をしていない場合、メタ文字がメタ文字固有の意味の処理を実行する。

<script>要素の中にJavaScriptコードを書く場合、HTMLのエスケープではなく、JavaScriptのエスケープを行う必要がある。

【例】
HTMLで<p>タグを表示したい場合:HTMLでは<p>と書く必要がある。
JavaScriptで<p>という文字列を表示したい場合:JavaScriptでは"<p>"または'<p>'と書く。
つまり、<script>要素の中では、HTMLのルールではなく、JavaScriptのルールに従って記述する必要があるということ。

scriptタグ内にあるPHPコード

scriptタグ内に var='<?php ~' のように記述されている例は、PHP で生成された値を JavaScript の変数に代入するための一般的な方法。
これは、サーバーサイドで処理された PHP の結果をクライアントサイドの JavaScript で利用するために行われる。

仕組み
1. PHP の実行
<?php ~ ?> の部分がサーバーで実行され、PHP コードの結果が文字列として生成される。

2. HTML の生成
生成された文字列が HTML ドキュメントに埋め込まれる。

3. JavaScript の実行
ブラウザが HTML ドキュメントを解析し、script タグ内の JavaScript コードを実行する。
このとき、PHP によって生成された文字列が JavaScript の変数に代入される。

目的
動的なデータの受け渡し
データベースから取得したデータや、ユーザーの入力内容など、サーバーサイドで処理された情報を JavaScript で利用できる。

設定値の受け渡し
サーバー側の設定ファイルや環境変数などを JavaScript で利用できる。

ページごとに異なる JavaScript の動作
PHP で条件分岐を行い、ページごとに異なる JavaScript コードを生成できます。

mabomabo

JavaScriptのカスタムデータ属性(data-*属性)

HTML要素に独自のデータ(情報)を埋め込むための仕組み。
これは、HTML5で導入された機能であり、JavaScriptを使って動的にデータを操作する際に非常に役立ちます。

カスタムデータ属性の主な特徴

任意のデータを埋め込める
HTML要素に、JavaScriptから参照できる独自の情報を付加できます。

JavaScriptとの連携
JavaScriptから、datasetプロパティを通して簡単にデータの読み書きが可能です。

HTMLの構造とデータを分離
HTMLの構造を維持したまま、JavaScriptで必要なデータを要素に紐付けることができます。

CSSでの利用
CSSでも属性セレクタを用いることで、カスタムデータ属性の値に応じたスタイルを適用することが可能です。

カスタムデータ属性の書き方

属性名は、data-で始まり、その後に任意の名前を続けます
属性値は、文字列で記述します。

<div data-user-id="123" data-user-name="Taro">ユーザー情報</div>

JavaScriptでの利用方法

JavaScriptでは、datasetプロパティを使ってカスタムデータ属性にアクセスします。

const element = document.querySelector('div');
const userId = element.dataset.userId; // "123"
const userName = element.dataset.userName; // "Taro"

element.dataset.userId = "456"; // データの更新

※JavaScriptでカスタムデータ属性にアクセスする際、以下の規則に従って変換されます。
data-の削除
HTML属性のdata-プレフィックスは、JavaScriptのdatasetプロパティを通してアクセスする際には取り除かれます。
ハイフンからキャメルケースへの変換
ハイフン(-)で区切られた属性名は、キャメルケースに変換されます。
つまり、ハイフンを取り除き、ハイフンの後の単語の最初の文字を大文字にします。


data-user-id → dataset.userId
data-user-name → dataset.userName
data-article-id → dataset.articleId

カスタムデータ属性の利点

DOM操作の効率化
必要な情報をHTML要素に直接埋め込むことで、DOMを効率的に操作できます。

コードの可読性向上
HTMLとJavaScriptの連携が明確になり、コードの可読性が向上します。

柔軟なデータ管理
さまざまなデータを要素に紐付けることができ、柔軟なデータ管理が可能です。

カスタムデータ属性の注意点

データ型
カスタムデータ属性の値は常に文字列として扱われます。数値などを扱う場合は、JavaScript側で適切な型変換が必要です。

パフォーマンス
大量のデータをカスタムデータ属性に埋め込むと、パフォーマンスに影響を与える可能性があります。

mabomabo

エラーメッセージからの情報漏洩

① エラーメッセージに攻撃者にとって有益なアプリケーションの内部情報が含まれる
② 意図的な攻撃として、エラーメッセージに秘密情報(個人情報など)を表示させる

アプリケーションでエラーが発生した場合、画面に表示するのは、簡単な利用者向けメッセージにとどめ、エラーの詳細内容はエラーログに出力するようにする。

php.ini
display_errors = Off
mabomabo

SQLインジェクション

シングルクォートなどを用いてリテラルからはみ出した文字列をSQL文として認識させ、アプリケーションが呼び出すSQL文を変更する手法

https://www.shadan-kun.com/waf_websecurity/sql_injection/ より画像引用


https://activation-service.jp/iso/terms/2997 より画像引用


https://www.kagoya.jp/howto/it-glossary/security/sql-injection/ より画像引用

一般的な動作

https://web-scan.jp/article/1868/ より画像引用

対策がない場合の動作

https://web-scan.jp/article/1868/ より画像引用

SQLインジェクション脆弱性がある場合に受ける可能性がある影響
・データベース内のすべての情報が外部から盗まれる
・データベースの内容が書き換えられる
・認証を回避される(IDとパスワードを用いずにログインされる)
・その他、データベースのファイルの読み出し、書き込み、プログラムの実行などを行われる

確実な対策
◎静的プレースホルダを利用してSQLを呼び出すこと

※プレースホルダによるSQL文の組み立て
プレースホルダ:SQLでは変数などでユーザーからの入力された値を受け取る、パラメータの部分に埋め込んでおく「?」などの記号のこと。
この「?」などのプレースホルダへ実際の値を割り当てることをバインドする、と表現することから、プレースホルダのことを別名「バインド変数」と呼ぶこともある。
このプレースホルダは、パラメータのバインド処理をデータベースエンジン側で実行するのか、アプリケーション側のライブラリ内で実行するのかによって、静的プレースホルダ(Prepared Statement)と動的プレースホルダの2つに分類される。

静的プレースホルダ(Prepared Statement)

https://envader.plus/article/45 より画像引用

SQLクエリ内で使用されるプレースホルダー(仮の置き換え要素)の一種で、特にプリペアドステートメント(Prepared Statement)やパラメータ化されたクエリで使われる。

静的プレースホルダは、バインド処理をデータベースエンジン側で行なう。
プレースホルダのついたSQL文はそのままデータベースエンジンに送信され、コンパイルなどの実行準備が行われ、この時点でSQL文が確定する。SQL文が確定した後に、受け取った値をプレースホルダへ割り当ててSQL文を実行するため、不正なSQL文へ変更されてしまう可能性がなくなる。

SQLインジェクションによる情報漏洩

① エラーメッセージを用いる方法

② UNION SELECTを用いる方法
UNION SELECT:2つのSQL文の結果の和集合を求める演算
UNION SELECTを用いた攻撃が成立すると、一度の攻撃で大量の情報が漏洩してしまう。

https://www.scaler.com/topics/union-and-union-all-in-sql/ より画像引用

SQLインジェクションによる認証回避

ログイン画面にSQLインジェクション脆弱性があると、パスワードを知らなくてもログインできてしまう場合がある。

https://xtech.nikkei.com/it/article/COLUMN/20060530/239449/ より画像引用

SQLインジェクション攻撃によるデータ改ざん


https://xtech.nikkei.com/it/atcl/column/16/112500273/112500003/ より画像引用

その他の攻撃

データベースエンジンによって受ける可能性のある攻撃
・OSコマンドの実行
・ファイルの読み出し
・ファイルの書き出し
・HTTPリクエストにより他のサーバーを攻撃

SQLインジェクション攻撃により、データベースサーバー上のファイルの内容がデータベース経由で外部に漏洩する場合がある。

mabomabo

SQLインジェクション

脆弱性が生まれる原因

リテラルの扱い
◎パラメータとして指定した文字列の一部がリテラルをはみ出すことにより、SQL文が変更されること。

リテラル:SQL文中で決まった値を示すもの
シングルクォートなどを用いてリテラルからはみ出した文字列をSQL文として認識させ、アプリケーションが呼び出すSQL文を変更することによりSQLインジェクション攻撃が成立する。

文字列リテラルの問題

SQLの標準規格では、文字列リテラルはシングルクォートで囲む。
「シングルクォートをエスケープする」:SQLでは文字列リテラル中にシングルクォートを含めたい場合は、シングルクォートを2つ続けて記述する決まりとなっている。

SQLインジェクションの攻撃イメージ

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

数値項目に対するSQLインジェクション

Webアプリケーション開発によく用いられるスクリプト系言語(PHP、Perl、Rubyなど)は変数に型の制約がないため、数値を想定した変数に数値以外の文字が入る場合がある。

数値リテラルはシングルクォートで囲まないため、数値でない文字が現れた時点で数値リテラルは終了する。

対策

① プレースホルダによりSQLを組み立てる


https://www.itmedia.co.jp/enterprise/articles/1201/30/news003.html より画像引用

プレースホルダ
SQL文の中で実際の値が入る部分を仮の記号(例: ?:name)で置き換える仕組み。
変数や式など可変のパラメータの場所に埋め込んでおくもの。
プレースホルダを使うことで、SQL文の構造とデータを分離できる。

SELECT * FROM users WHERE id = ?;

? がプレースホルダで、後から実際の値(例: 1)がバインドされる。
バインド:SQL文内のプレースホルダ(仮の記号)に実際のデータ・値を紐づける・割り当てること

プリペアドステートメント
SQL文を事前にコンパイル(準備)し、プレースホルダに値をバインドして実行する仕組み
プリペアドステートメントでは、SQL文の中にプレースホルダを使用して、後から値をバインドする。

// プリペアドステートメントの作成
$stmt = $pdo->prepare("INSERT INTO users (name, age) VALUES (:name, :age)");

// プレースホルダに値をバインド
$stmt->bindValue(':name', 'John');
$stmt->bindValue(':age', 30);

// クエリを実行
$stmt->execute();

静的プレースホルダを指定する
PDO::ATTOR_EMULATE_PREPURES => false:静的プレースホルダ
PDO::ATTOR_EMULATE_PREPURES => true:動的プレースホルダ

※静的プレースホルダ

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

値のバインドをデータベースエンジン側で行なう。
プレースホルダの付いたSQL文は、そのままデータベースエンジンに送られ、コンパイルなどの実行準備が行われ、SQL文が確定する。
次に、バインド値がデータベースエンジンに送られ、エンジン側で値を当てはめた後にSQL文が実行される。
プレースホルダの状態でSQL文がコンパイルされるため、後からSQL文が変更される可能性が原理的にありえない。

※動的プレースホルダ

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

SQLを呼び出すアプリケーション側のライブラリ内で、パラメータをバインドしてからデータベースエンジンに送る方式。

② アプリケーション側でSQL文を組み立てる際に、リテラルを正しく構成するなど、SQL文が変更されないようにする

PDOの安全な利用法
PDOのコンストラクタの第4引数でオプションを指定する。

※PDO(PHP Data Objects)は、PHPでデータベースにアクセスするための軽量で一貫性のあるインターフェースを提供する拡張モジュール。PDOを使うことで、異なる種類のデータベース(MySQL、PostgreSQL、SQLiteなど)に対して、同じ方法でアクセスできるようになる。

PDOで例外処理を使用する
:PDO::ATTR_ERRMODEとしてPDO::ERRMODE_EXCEPTIONを設定
→ PDOの処理中にエラー発生した場合、例外をスローする設定。
→ これがないと、PDOデータはデータベース接続時のみ例外を発生する

複文の実行を禁止する
複文:複数のSQLの文をセミコロンで区切って一度に指定・実行すること
設定すると、SQLインジェクション攻撃の中で複文を使ったものを抑止することができる。

mabomabo

LIKE述語とワイルドカード

SQLインジェクションと混同されやすい現象。

LIKE述語の検索パターン指定では、「_」は任意の1文字にマッチ、「%」は0文字以上の任意の文字列にマッチする。
ワイルドカード文字:「_」や「%」のようなSQLのLIKE演算子と組み合わせて使う特別な記号で、パターンマッチングを行うための強力なツール

主要なワイルドカード

記号 意味 一致する例 一致しない例
% 任意の長さの文字列 (0文字以上) '山%' 山田, 山本, 山 田中, 大山
_ 任意の1文字 '山_' 山田, 山本 山, 山田太郎
[] 指定した文字のいずれか1文字 '[山田]本' 山本, 田本 本田, 本山
[^] 指定した文字以外の1文字 '[^山田]本' 本田, 石本 山本, 田本
基本的な使い方
SELECT * FROM テーブル名 
WHERE 列名 LIKE 'パターン';

LIKE述語を使って、「_」や「%」を文字として検査する場合、ワイルドカード文字をエスケープする必要がある。
エスケープに使用する文字は、ESCAPE句で指定する。

(例)name列に「%」という文字を含む行を検索したい場合
WHERE name LIKE '%#%%' ESCAPE '#'

先頭と末尾の「%」がワイルドカード、「#%」2文字で「%」1文字を意味する。
※エスケープ文字は任意の文字を指定することができる。

データベースエンジンごとのエスケープすべき文字

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

mabomabo

プレースホルダを用いた様々な処理

検索条件が動的に変わる場合

Webアプリケーションの検索画面には、多くの検索条件が入力できるものがあり、条件が入力された検索欄だけからSQLを組み立てる。そのため、あらかじめSQL文を固定化できず、ユーザ入力に応じてSQL文が変化することになる。
このような場合、プレースホルダの記号「?」を含んだSQL文を文字列連結により動的に組み立て、実パラメータはSQL呼び出しの際にバインドするようなスクリプトを記述する。

様々な列でのソート

SQLではORDER BY句により列を指定してソートできるが、不用意なプログラミングにより脆弱性が生まれる可能性がある。
対策としてソート列名の妥当性確認を行なう方法がある。

SQLインジェクションの保険的対策

詳細なエラーメッセージの抑止
SQLのエラーが表示されると、SQLインジェクションの存在が外部からわかりやすくなる。
そのため、詳細なエラーメッセージを抑止することで被害にあいにくくする。
なお、PHPの場合、php.ini に以下を設定する。

display_error = Off

入力値の妥当性検証
アプリケーションの要件に従った入力値検証を行なうと、結果として脆弱性対策になる場合がある。
ただし、SQLインジェクションの解消にはプレースホルダの利用を徹底すること。
入力値の妥当性を検証するだけでは、住所欄やコメント欄など、文字種の制限のないパラメータもあるため、SQLインジェクション脆弱性は解消しない。

データベースの権限設定
アプリケーションが利用するデータベースユーザに対しては、アプリケーションの機能を実現するために必要最小限な権限のみを与えておけば、攻撃を受けても被害を最小限にとどめられる場合がある。
また、SQLによるファイルの読み込みは、MySQLのFILE権限が必要。

◎1番いい方法は、静的プレースホルダを使用してSQLを呼び出すこと

プレースホルダが使えない場合の対策

既存アプリケーションの対策などで、プレースホルダによる実装に変更すると改修コストが大きくなりすぎる状況になるような場合、文字列の連結によるSQL文の組み立ての構造を生かしたまま、リテラルを構成することでSQLインジェクションを解決できる。

具体策

文字列リテラル内で特別な意味を持つ記号文字をエスケープする
SQLの文字列リテラルのエスケープには、SQL呼び出しライブラリにquoteというメソッドを用意していることがある場合があり、エスケープ文字を製品や設定に応じて調整してくれる。

数値リテラルは数値以外の文字が混入しないようにする
数値型にキャストする方法が確実。
桁数の多い10進数などプログラミング言語側に対応する型が用意されていない場合には、正規表現などによる数値としての検証で対応する。

mabomabo

「重要な処理」の際に混入する脆弱性

「重要な処理」の例
・利用者のクレジットカードでの決済
・利用者の口座からの送金
・メール送信
・パスワードやメールアドレスの変更 など

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

「重要な処理」の受付において、利用者の意図したリクエストであることを確認する必要があるが、この確認処理が抜けると、罠サイトを閲覧しただけで、利用者のブラウザから勝手に「重要な処理」を実行させられてしまう脆弱性のこと。ログイン中のユーザが狙われる。
ユーザーが操作していないリクエストを強制させる。


https://it-infra.techmatrix.jp/blog/check14 より画像引用

CSRFの仕組み

  1. ユーザーがログインした状態(例: 銀行サイト)で、悪意のあるサイトやリンクを開く。
  2. 攻撃者が用意した偽のリクエスト(例: 送金処理やパスワード変更)が、ユーザーのブラウザから自動的に送信される。
  3. ユーザーが意図せず操作を実行(例: 預金が勝手に送金される)。


https://www.qbook.jp/column/1909.html より画像引用

CSRF(Cross-Site Request Forgery)攻撃が成立する核心的な理由は、ブラウザが自動的にリクエストにクッキー(セッションIDなど)を添付する仕組みを悪用されることによる。

クッキーだけでリクエストが実行される理由

ブラウザの仕組みが原因
・クッキーは「ドメインごと」に管理され、リクエスト時に自動で送信される
(例)bank.com のクッキーは、bank.com へのリクエスト時に必ず添付される。
・罠サイトからbank.comへリクエストを送ると、ブラウザはbank.comのクッキーを自動的に付与する
ユーザーが意図しなくても、ログイン済みセッションとして処理されてしまう。

※CSRFではクッキー自体は盗まれず、ブラウザが自動送信する挙動を悪用する。クッキーを盗むのはXSS攻撃。

WebアプリケーションにCSRF脆弱性がある場合の影響例

・利用者のアカウントによる物品の購入
・利用者の退会処理
・利用者のアカウントによるSNSや問い合わせフォームなどへの書き込み
・利用者のパスワードやメールアドレスの変更

CSRF脆弱性の影響は、アプリケーションの「重要な処理」の悪用に限られる。
重要な対策:「重要な処理」を実行する前に、利用者の意図したリクエストであることを確認すること

攻撃手法と影響

入力 - 実行パターンのCSRF攻撃

(例)パスワード変更

https://shukapin.com/security/csrf より画像引用

CSRFによるパスワード変更が成立する条件

  1. パスワード変更機能にCSRF対策がされていないこと
    トークン検証なし・HTTPメソッドの不備
  2. ユーザがログイン済みであること
  3. ユーザが悪意のあるページ・リンクを開くこと
    偽造リンク・自動送信フォーム・画像タグ偽造
  4. サーバーがリクエストを正当とみなすこと
    CookieやセッションIDによる認証のみで、リクエストの出所を検証しない

攻撃の流れ

  1. 利用者が正規サイトにログイン
  2. 攻撃者が罠を用意
  3. 被害者が罠を閲覧
  4. 罠のJavaScriptにより、被害者のブラウザ上で攻撃対象サイトに対し、新しいパスワードが送信される
    ※クッキーとして、攻撃対象のサイトのセッションIDが付与されている
  5. パスワードが変更される

実際の攻撃では攻撃の様子を隠すため、iframe を使って罠をかける。
CSRF攻撃では、攻撃者が画面を参照できないため、情報を盗み出すことはできないが、CSRF攻撃でパスワードを変更できる場合は、そのパスワードを使用して不正にログインして、被害者の情報を盗み出すことができる。

CSRF攻撃とXSS攻撃の比較


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

①〜③は同じ経路を辿るが、その後が異なる。
CSRF
③のリクエストに対するサーバー側の処理を悪用する。
悪用内容は、もともとサーバー側で用意された処理に限定される。
「リクエストの強制」が目的で、情報の窃取は行なわない。

※注意すべき脆弱性
・設計段階から対策を盛り込む必要がある
・開発者の認知度がXSSに比べて低く、対策が進んでいない

XSS
③のリクエストに含まれるスクリプトはオウム返しに④のレスポンスとして返され、それがブラウザ上で実行されることで攻撃が起きる。
ブラウザ上では、攻撃者が用意したHTMLやJavaScriptが実行できるため、ブラウザ上でできることは何でも悪用可能。
また、JavaScriptを使ってサーバー側の機能を悪用することも可能。
悪意のあるスクリプトでdocument.cookieを読み取り、セッションIDを直接盗むことが可能。

確認画面がある場合のCSRF攻撃

入力画面と実行画面の間に確認画面がある場合の攻撃
確認画面があるとCSRF攻撃ができないわけではない。

確認画面から実行画面へのデータ(パラメータ)の受け渡し方法

① hiddenパラメータ(type属性がhiddenのinput要素)を使う方法

メールアドレス変更画面の画面遷移

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

確認画面がない場合と同じ
:実行画面が入力(HTTPリクエスト)としてメールアドレスを受け取っていることに変わりはないため

② セッション変数を使う方法


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

このパターンを採用しているアプリケーションに対しては、2段階の攻撃が必要になる
① 確認画面に対してメールアドレスをPOSTしてセッション変数にメールアドレスをセットする
② タイミングを見計らって実行画面を呼び出す
この攻撃のために iframe を2つ使う方法がある。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

iframe1 は罠サイトと同時に呼び出され、確認画面にメールアドレスをPOSTする。
その結果、セッション変数にメールアドレスがセットされた状態になる。

iframe2 は罠サイトが表示されてから10秒後にCSRF攻撃をかけ、実行画面を表示する。
この時点で、すでにメールアドレスはセッション変数にセットされているので、攻撃者が指定したメールアドレスに変更させられることになる。

ファイルアップロードフォームでのCSRF攻撃

HTMLフォームからのファイルアップロードでは、ファイル名やファイルの中身をHTMLファイルから指定することはできない。ファイルアップロードを伴うフォームに対してCSRF攻撃はできないように見えるが、決してそんなことはない。
クロスオリジンに対応したXMLHttpXMLHttpRequestによる攻撃が可能。

mabomabo

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


https://www.qbook.jp/column/1909.html より画像引用

脆弱性が生まれる原因

背景としてWebの性質がある。
① form要素のaction属性にはどのドメインのURLでも指定できる
・罠などのサイトからでも、攻撃対象サイトにリクエストを送信できる

② クッキーに保管されたセッションIDは、対象サイトに自動的に送信される
・罠経由のリクエストに対しても、セッションIDのクッキー値が送信されるので、認証された状態で攻撃リクエストが送信される

(例)HTTPリクエストの内容がほぼ同じだが、Refererヘッダのみ異なる。
意図したHTTPリクエスト

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

・Refererがパスワード入力画面のURLを指している。

CSRFによる意図しないHTTPリクエスト

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

・Refererが罠ページのURLを指している。

通常のアプリケーションでは、Refererの値をチェックしないため、CSRF脆弱性が混入する。

対策

「重要な処理」に対するリクエストが正規利用者の意図したものであることを確認する必要がある。

① CSRF 対策の必要なページを区別する

CSRF対策はすべてのページに実施するものではない。
パスワードの変更や個人情報変更などの確定画面といった、他のサイトから勝手に実行されると困るページに対して対策する必要がある。

開発プロセスの中で行なうべきこと
・要件定義工程で機能一覧を作成し、、CSRF対策の必要な機能にマークする
・基本設計工程で画面遷移図を作成し、CSRF対策の必要なページにマークする
・開発工程でCSRF対策を作り込む

② 正規利用者の意図したリクエストを確認できるよう実装する

CSRF対策として必要なことは、正規利用者の意図したリクエストであることの確認

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

※正規利用者の意図したリクエスト…対象のアプリケーション画面上で正規利用者が自ら「実行」ボタンを押した結果のリクエスト
※意図しないリクエスト… 罠のサイトからのリクエスト

意図したリクエストかどうかを判定する方法
① 秘密情報(トークン)の埋め込み
CSRF対策が必要な登録画面や注文確定画面などのページに対して、第三者が知り得ない秘密情報を要求するようにすれば、不正なリクエストを送信させられても、アプリケーション側で判別することができる。
アプリケーションフレームワーク側でトークンの生成とチェックの機能を持つものが増えてきており、こういった機能を有効活用することで対策が可能。
トークンは第三者に推測されにくい乱数を用いて生成する。

※PHPで利用できる暗号論的擬似乱数生成機
・/dev/urandomから読み込み
・openssl_random_pseudo_bytes
・random_bytes
トークンはセッション変数に記憶する。

第三者に予測不可能なトークンを要求することにより、CSRF攻撃を防ぐことが可能。
トークンが空でないことを確認すること。
入力 - 確認 - 実行形式の画面のように、3段階以上の遷移がある場合でも、トークンを埋め込むページは、実行ページの直前のページ
トークンを受け付けるリクエスト(「重要な処理」を受け付けるリクエスト)はPOSTメソッドにする必要がある。
→ GETメソッドで機密情報を送ると、Refererにより機密情報が外部に漏れる可能性があるため。

② パスワード再入力
CSRF対策以外のパスワード再入力の目的
・物品購入などに先立って、正規利用者であることを確認する
・共有PCで別人が操作している状況などがなく、本当に正規の利用者であることを確認する

パスワードを確認するタイミングは、最終の実行ページ
画面が3画面以上にまたがる入力 - 確認 - 実行形式の場合や、ウィザード形式の場合でもパスワードを確認するタイミングは最後の実行ページ。
対象ページ以外で確認を求めると煩雑で使いにくいアプリケーションになってしまう。

※ウィザード形式:ソフトウェアやWebサービスなどで、ユーザーが複雑な設定や操作を手順に従って簡単に行えるように設計されたユーザーインターフェースの一種のことで、視覚的なガイドがある。

https://gyazo.com/c4549ace589459e7e2f996f470ad4f3f より画像引用

③ Refererのチェック
「重要な処理」を実行するページでRefererを確認することで、CSRF対策になる。
正規のリクエストとCSRF攻撃によるリクエストでは、Refererフィールドの内容が異なっているため。
正規のリクエストでは、実行画面の1つ手前のページ(入力画面や確認画面など)に対するURLがRefererとしてセットされているはずなので、それを確認する。
Refererの確認によるCSRF対策は、「重要な処理」の実行ページだけの追加で済むため、他の対策のように2画面にまたがって処理を追加する必要はない。

※Refererのチェックは漏れが生じやすいので注意が必要。
Refererをチェックする場合は、前方一致検索で絶対URLをチェックすることと、ドメイン名の後のスラッシュ「/」まで含めてチェックすることが必須条件。

CSRF対策の比較

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

CSRF攻撃への保険的対策

「重要な処理」の実行後に、対象利用者の登録済みメールアドレスに対して、処理内容の通知メールを送信すること
CSRF攻撃を受けた際に、利用者が早期に気づくことができるため、被害を最小限にとどめることができる可能性がある。
※メールは平文で送信されるものであるため、通知メールには重要情報は含ませず、「重要な処理」が実行されたことのみにとどめること。

mabomabo

クリックジャッキング


https://smallit.co.jp/cloud-gunshi/clickjacking/ より画像引用

iframe要素とCSSを巧妙に利用することで、透明にした攻撃対象ページと罠サイトを重ね合わせ、利用者が気づかないうちに攻撃対象サイトでのクリックを誘導する攻撃手法
利用者にボタンなどをクリックさせることで「重要な処理」を実行させることはできるが、その結果の処理画面を攻撃者が知ることことはできない。

攻撃手法と影響

iframe要素を用いて罠と攻撃対象ページを重ねる。
CSSのz-indexを用いて、罠画像を奥側、攻撃対象ページを透明に設定する。

脆弱性が生まれる原因

アプリケーションのバグが原因ではなく、HTMLの使用を巧妙に悪用していることによる。

対策

アプリケーション単体では困難なためブラウザ側の支援が必要になる。
frameおよびiframeでの参照を制限するX-Frame-Optionsという仕様に対応することで対策が簡単にできる。

X-Frame-Optionsはレスポンスヘッダとして定義されており、DENY(拒否)あるいはSAMEORIGIN(同一生成元に限り許可)のいずれかの値をとる。
DENY(拒否)を指定したレスポンス:frameなどの内側で表示されなくなる。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

SAMEORIGIN(同一生成元に限り許可)を指定したレスポンス:アドレスバーに表示されたオリジンと同じオリジンである場合のみ表示される。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

frameやiframeを使わないサイトではDENYを指定、frameなどを使っているがホストが単一の場合はSAMEORIGINを指定することによって、frame類を使った攻撃に対する安全性を高めることができる。

PHPによりX-Frame-OptionsのSAMEORIGINを指定

header('X-Frame-Options: SAMEORIGIN');

Apacheの設定(mod_headersが導入されている必要がある)

Header always append X-Frame-Options SAMEORIGIN

nginxの設定

add_header X-Frame-Options SAMEORIGIN;

保険的対策

「重要な処理」の実行後に、登録済みメールアドレスに通知メールを送信する
クリックジャッキング攻撃を防ぐことはできないが、攻撃を受けた際に利用者が早期に気づき、被害を最小限にとどめられる可能性がある。

mabomabo

セッション管理の不備

Webアプリケーションでは、認証結果など現在の状態を記憶する手段として、セッション管理機構が使用される。現在主流のセッション管理機構は、クッキーなどににセッションIDという識別子を記憶させ、このセッションIDをキーとしてサーバー側で情報を記憶する方法が取られている。

セッションハイジャックの原因と影響

セッションハイジャック:第三者がセッションIDを悪用してなりすますこと

第三者がセッションIDを知る方法

① セッションIDの推測

連番になっているようなセッションIDは第三者が予測できるため、不適切
その他、日時やユーザーIDを元にして生成されたセッションIDも不適切

② セッションIDの盗み出し

セッションIDを盗み出す手法
・クッキー生成の際の属性の不備により漏洩
・ネットワーク的にセッションIDが盗聴される
・クロスサイト・スクリプティングなどアプリケーションの脆弱性により漏洩
・PHPやブラウザなどプラットフォームの脆弱性により漏洩
・セッションIDをURLに保持している場合は、Refererヘッダから漏洩する

セッションIDの盗み出しに悪用可能なアプリケーションの脆弱性の典型例
・クロスサイト・スクリプティング(XSS)
・HTTP・ヘッダインジェクション
・URLに埋め込まれたセッションID

③ セッションIDの強制

セッションIDを盗み出す代わりにセッションIDを利用者のブラウザに設定することができれば、攻撃者は利用者のセッションIDを「知っている」状態になり、セッションハイジャックが可能になる(セッションIDの固定化攻撃)。

セッションハイジャックの手法まとめ


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

mabomabo

推測可能なセッションID

推測可能なセッションIDによる脆弱性を作り込まないためには、セッション管理機構を自作せず、実績のある言語やミドルウェアが提供するセッション管理機構を使用すること。

攻撃手法と影響

推測可能なセッションIDに対する攻撃の3ステップ
① 対象アプリケーションからセッションIDを集める
② セッションIDの規則性の仮説を立てる
③ 推測したセッションIDを対象アプリケーションで試す

ありがちなセッションIDの生成方法
・ユーザIDやメールアドレス
・リモートIPアドレス
・日時(UNIXタイムの数値、あるいは年月日時分秒の文字列)
・乱数


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

推測可能なセッションIDに対する攻撃は、推測可能な情報を元にセッションIDが生成されていないか仮説を立て、先に収集したセッションIDを上記の図のようなモデルに当てはめて仮説と矛盾しないか検証することを繰り返す。

なりすましの影響

セッションハイジャックでは、利用者のパスワードまではわからない
そのため、重要な処理の前にパスワードの再入力(再認証)を要求すると、セッションハイジャックに対する保険的な対策になる。

認証なしにパスワードが変更できる場合、攻撃者はパスワードを変更することによって、パスワードも知りうる状態になる。この場合、攻撃の影響が大きい。

脆弱性が生まれる原因

アプリケーション側でセッション管理機構を自作していること

Webアプリケーション開発では、わざわざセッションIDの生成プログラムを開発する意味はない。
・主要なWebアプリケーション開発ツールはセッション管理機構を備えているため
・安全なセッションID生成プログラムを開発することは技術的難易度が高いため

対策

Webアプリケーション開発ツールが備えているセッション管理機構を利用すること

PHP7.0までは、ありがちなセッションIDの生成方法に該当し、極めて限定された条件でPHPのセッションIDが推測可能であるという論文(PHPのセッションIDは暗号論的に弱い乱数生成器を使っており、セッションハイジャックの危険性があるといったもの)が発表された。

これに対しては、php.iniの設定を追加することで、安全な乱数を元にセッションIDを生成するように改善できる。

/dev/urandom は、Linuxなど多くのUnix系OSで実装されている乱数生成器で、デバイスファイルとして使用できる。

※デバイスファイルとは、オペレーティングシステム (OS) がコンピュータに接続されたハードウェアデバイス (周辺機器など) を、ファイルシステム上のファイルのように扱うための仕組み。これにより、アプリケーションは、通常のファイルの読み書きと同じ方法でデバイスとのデータの入出力や制御を行なうことができる。
イメージとしては、ハードウェアデバイスを操作するための「窓口」や「入り口」となるファイル。

mabomabo

URL埋め込みのセッションID

セッションIDをクッキーに保存せず、URLに埋め込ませる場合がある。
セッションIDをURLに埋め込んでいると、Refererヘッダを経由して、セッションIDが外部に漏洩し、なりすましの原因になる場合がある。

対策として、URL埋め込みのセッションIDを禁止する設定 あるいは プログラミングをすることがある。

攻撃手法と影響

セッションIDがURL埋め込みになる条件

PHPは設定によってセッションIDをURLに埋め込むことが可能。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

この設定により、セッションIDをクッキー保存にするか、URL埋め込みか、以下のイメージのように設定される。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

session.use_trans_sidがOnの場合:セッションIDがURLに自動的に埋め込まれる
session.use_trans_sidがOffの場合:アプリケーション側で明示的にセッションID埋め込みの処理をしている場合のみ、セッションIDが埋め込まれる。

RefererによりセッションIDが漏洩する条件

① URL埋め込みのセッションIDを使える
② 外部サイトへのリンクがある、あるいは、リンクを利用者が作成できる

攻撃のシナリオ

RefererからのセッションIDの漏洩において、脆弱性を狙った攻撃の場合、外部から意図的に攻撃を仕掛けることができるのはリンクを作成できる場合に限られる。具体的には、Webメール、掲示板、ブログ、SNSなどがこの条件に該当する。

Webメールを例とすると、利用者がリンクをたどって攻撃者のサイトを閲覧すると、WebメールのURLに埋め込まれていたセッションIDが、攻撃者のサイトにRefererとして漏洩する。
これにより、攻撃者は受け取ったRefererを元に、利用者へのなりすましが可能になる。

攻撃ではなく事故としてセッションIDが漏洩するケース

利用者がURLを書き込めないサイトの場合、外部サイトへのリンクがあれば、それら外部サイトに対してセッションIDが漏洩することになる。外部サイトのサーバー管理者に悪意があれば、Refererログから発見したセッションIDをなりすましに悪用する可能性がある。

脆弱性が生まれる原因

セッションIDがURLに埋め込まれる直接の原因は、不適切な設定あるいはプログラミングによるもの。
セッションIDをクッキーに保存する方法が通常は最も安全。

対策

クッキーにセッションIDを保存するように設定する。

mabomabo

セッションIDの固定化


https://www.ubsecure.jp/blog/session_fixation より画像引用

セッションIDの固定化攻撃


https://www.ubsecure.jp/blog/session_fixation より画像引用

手順
① セッションIDを入手する
② 被害者に対して、①で入手したセッションIDを強制する
③ 被害者は標的アプリケーションにログインする
④ 攻撃者は被害者に強制したセッションIDを使って標的アプリケーションにアクセスする

影響
・なりすましによる情報漏洩
・被害者の権限によるアプリケーション機能の悪用
・データの投稿・変更・削除 など

対策
◎ログイン時にセッションIDを変更すること

攻撃手法と影響

URLにセッションIDを保持できるアプリケーションの方がセッションIDの固定化が容易。

攻撃者は罠にかかった利用者としてログインしている状態なので、当該利用者としてできる操作や情報閲覧はすべて可能になる。

ログイン前のセッションIDの固定化攻撃

ログイン前のページであっても、セッション変数を使用していると攻撃が成立する場合がある。
認証を必要としないページでセッション変数を利用していると、セッションIDの固定化攻撃が可能となる場合がある。

セッションアダプション(Session Adoption)

PHPが持つ未知のセッションIDを受け入れるという特性
攻撃者が勝手に作成したセッションIDであっても受け入れてしまう。
セッションアダプションがないミドルウェアで動作するアプリケーションに対してセッションIDの固定化攻撃を行なう場合、攻撃者はまずターゲットアプリケーションを閲覧して、有効なセッションIDを取得し、このセッションIDを被害者に強制するように罠サイトを設定する。

クッキーのみにセッションIDを保存するサイトのセッションIDの固定化

クッキーのセッションIDを外部から設定することは容易ではないが、ブラウザやWebアプリケーションに脆弱性があれば可能になる。
・クッキーモンスターバグ(ブラウザの脆弱性)
・クロスサイト・スクリプティング脆弱性
・HTTPヘッダ・インジェクション脆弱性

サイト全体がHTTPSで暗号化されている場合でも、平文のHTTPでクッキーを設定すれば、そのクッキーはHTTPSでも有効。通信路上に攻撃者が存在する場合、クッキーの改変を防ぐ方法がない。

脆弱性が生まれる原因

セッションIDを外部から強制できるところ

以下すべて実施することが対策になる
・セッションIDをURL埋め込みにしない
・クッキーモンスターバグのあるブラウザを使わない(使わせない)
・クッキーモンスターバグの発生しやすい都道府県型JPドメイン名と地域型ドメイン名を使わない
・クロスサイト・スクリプティング脆弱性をなくす
・HTTPヘッダ・インジェクション脆弱性をなくす
・その他、クッキーを書き換えられる脆弱性をなくす

セッションIDが外部から強制されることを許容し、セッションIDの固定化攻撃が行われても、セッションハイジャックは防ぐように対策することが一般的
そのために、認証に成功した際にセッションIDを変更することが有効

対策

Webアプリケーション側での対策
認証後にセッションIDを変更する

書式
bool session_regenerate_id([bool $delete_old_session = false])

PHPのsession_regenerate_id関数は省略可能な引数を1つとる。
この引数は、変更前のセッションIDに対応するセッションを削除するかどうかを指定するもので、常に true を指定する。

セッションIDの変更ができない場合はトークンにより対策する

Webアプリケーションの開発言語やミドルウェアによっては、セッションIDを明示的に変更できないものがある。このような場合は対策としてトークンを使用する。

ログイン時に乱数文字列(トークン)を生成し、クッキーとセッション変数の両方に記憶させる方法。
各ページの認証確認時にクッキー上のトークンとセッション変数のトークンの値を比較し、同一である場合のみ認証されていると認識される。同一でない場合は認証エラーと処理する。

トークンが外部に出力されるタイミングはログイン時のクッキー生成時のみであるため、トークンは攻撃者にとっては未知の情報で、知る手段はない。これにより、固定化攻撃を防御する。
トークンには予測困難性が要求されるため、暗号論的疑似乱数生成器を用いて生成されるべき。
ex. openssl_random_pseudo_bytes関数
認証後のページでは、トークン比較の関数 hash_equalsの使用が推奨される。

ログイン前のセッションIDの固定化攻撃の対策

ログイン前にセッション変数を使っていると、セッションIDの固定化攻撃に完全に対策することが困難。
ログイン前にはセッション管理機構をつかわず、hiddenパラメータで値を引き回すことが、現実的で効果的な対策になる。

やむを得ずログイン前にセッション変数を使用する場合には、秘密情報をセッション変数にセットするページで毎回セッションIDを変更することが対策になる。
しかし、セッションIDを変更したレスポンスをブラウザが受信できなかった場合に、セッションが維持できなくなるという副作用があるため、注意が必要。

セッション管理不備対策まとめ

セッション管理機構を自作せず、Webアプリケーション開発ツールのものを使う
クッキーにセッションIDを保存する
認証成功時にセッションIDを変更する
認証前にはセッション変数に秘密情報を保存しない

◎ 設計段階から計画的に対策すること

mabomabo

リダイレクト処理にまつわる脆弱性

Webアプリケーションには、ログインページのパラメータにURLを指定しておき、ログイン成功後にそのURLにリダイレクトするサイトのような、外部から指定したURLにリダイレクトするものがある。

リダイレクトに際して発生する代表的な脆弱性
・オープンリダイレクト脆弱性
・HTTPヘッダ・インジェクション脆弱性

PHPでは、header 関数を使ってリダイレクト処理を行なうことができる。
header 関数はHTTPヘッダを送信することができる関数

HTTPヘッダは、サイトを閲覧しているユーザーとサーバーとの間で、要求→応答の流れにおいて、どのような情報を要求し、どのような情報を受け取るのかを定義するもの


https://webukatu.com/wordpress/blog/39494/ より画像引用

オープンリダイレクト


https://atmarkit.itmedia.co.jp/ait/articles/1406/20/news007.html より画像引用

悪意のある第三者が、あるウェブサイトの特定のページを経由させて、ユーザーを意図しない別の悪質なサイトへ誘導する仕組みのこと。任意のドメインにリダイレクトできる脆弱性。
Webアプリケーションが外部サイトへのリダイレクト機能を不適切に実装している場合に発生する脆弱性。攻撃者が悪意のあるURLにユーザーを誘導できる状態を指す。

オープンリダイレクト脆弱性は利用者が知らないうちに別ドメインに遷移する場合、フィッシングという詐欺に悪用される可能性がある。
※フィッシング:著名なWebサイトなどを偽装したサイトに利用者を誘導して、個人情報などを入力させる手口。

利用者が信頼しているドメイン上にオープンリダイレクト脆弱性があると、利用者は自分が信頼するサイトを閲覧しているつもりで知らない間に罠のサイトに誘導される。
→ 注意深い利用者でも個人情報など重要情報を入力してしまいやすくなる。

プログラムやデバイスドライバをダウンロードするサイトにオープンリダイレクト脆弱性があると、そのサイトからマルウェア(不正プログラム)を配布される可能性がある。

対策は、外部からURL指定できるリダイレクト機能が本当に必要か見直し、可能であればリダイレクト先を固定すること。
リダイレクト先の固定化ができない場合は、リダイレクト先を許可されたドメインのみに制限することで対策できる。

攻撃手法と影響

主な攻撃手法
① フィッシング攻撃の補助
正規サイトのドメインを利用してユーザーを騙し、最終的に偽のログインページへ誘導
(例)https://正規サイト.com/redirect?url=https://偽サイト.com/phishing

② 信頼の悪用
ユーザーが信頼しているサイトのURLに見せかけてクリックさせ、悪意のあるサイトへリダイレクト

③ OAuthやSSOの悪用
認証後のリダイレクト先を攻撃者が制御できる場合、認証情報を盗む可能性

④ メールやSMSを使った誘導
短縮URLサービスと組み合わせて、一見安全そうなリンクを送付

具体的な影響
・フィッシング成功率の向上: 正規ドメインからのリダイレクトのため、ユーザーが警戒しにくい
・セッション情報の漏洩: Refererヘッダーを通じて機密情報が漏れる可能性
・SEOスパム: 悪意のあるサイトへのリダイレクトが検索エンジンにインデックスされる
・他の攻撃の足がかり: 他の脆弱性と組み合わせてより深刻な攻撃が可能に

(例)正規サイトからログイン
正規サイトからログインを試みるも失敗し、もう一度ログインしようとするその瞬間にはログイン失敗時のリダイレクトにより悪意のあるサイトに誘導され、そこで利用者がもう一度IDとパスワードを入力することで、攻撃者が利用者のIDとパスワードを盗み取る。

脆弱性が生まれる原因

リダイレクト先のURLを外部から指定できること
リダイレクト先のドメイン名のチェックがない

これらはAND条件、両方が当てはまる場合のみオープンリダイレクト脆弱性となるため、どちらか一方んの条件が当てはまらないようにすれば脆弱性はなくなる。

オープンリダイレクトが差し支えない場合

以下の2点が揃っている場合は脆弱性ではない。
① もともと外部のドメインに遷移する仕様であること
② 利用者にとって外部ドメインに遷移することが自明であること

例:バナー広告

対策

以下のいずれかを実施すること
① リダイレクト先のURLを固定する
アプリケーション仕様を見直し、リダイレクト先をURLを外部から指定するのではなく、固定のURLに遷移することを検討する。

② リダイレクト先のURLを直接指定せず番号指定にする
やむを得ずリダイレクト先を変更しなければならない場合、URLをそのまま指定するのではなく、「ペ=自番号」の形で指定する方法
ページ番号とURLの対応表は、外部から見えないスクリプトソースやファイル、データベースなどで管理する。

③ リダイレクト先のドメイン名をチェックする
リダイレクト先を番号指定できない場合、リダイレクト先のURLチェックにより、任意ドメインへの遷移を防止する。
※この方法は落とし穴が多いので、上記①か②のいずれかが好ましい。

◎ 外部から指定するリダイレクト先のURLは、必ず文字種とドメイン名をチェックすること

ネットワークパス参照//で始まるURL
ホスト名(FQDN)以下を指定するもの
ネットワーク上の別のコンピュータやサーバーにあるファイルやフォルダなどのリソースにアクセスするためのパス(場所の指定)のこと。「ネットワーク上のファイルの住所」のようなもの。

https?という正規表現は、httpとhttpsの両方にマッチさせることができる。

クッションページ

外部ドメインに対して直接リンクせず、クッションページをはさむことで、フィッシングサイトへの誘導を防止する。
オークションサイトやSNSなどで、利用者がURLを書き込むとリンクが生成されるサイトでは、このリンク機能を悪用して、フィッシングサイトに誘導する手口がある。

クッションページにより、外部ドメインに遷移することを利用者に告知することによって、フィッシング被害を防止しようとする。

仕様として外部ドメインへのリダイレクトを許可している場合でも、いきなりリダイレクトせず、クッションページをはさむことでフィッシング被害の防止に貢献できる。

mabomabo

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


https://www.ubsecure.jp/blog/http-header-injection より画像引用

リダイレクト処理以外にクッキー出力など、すべてのHTTPレスポンスヘッダの出力処理で発生する可能性のある脆弱性。

概要

リダイレクトやクッキー発行など、外部からのパラメータを元にHTTPレスポンスヘッダを出力する際に発生する脆弱性。
レスポンスヘッダを出力する際のパラメータ中に改行を挿入する攻撃によって、被害者のブラウザ上で
任意のレスポンスヘッダの追加
レスポンスボディの偽造
のどちらか、または両方が引き起こされる。

HTTPプロトコルが、「改行でヘッダを区切る」仕様であるが故、
不正な改行を挟むだけで、メッセージ構造自体が分断・乗っ取られてしまう。

HTTPレスポンスの構造は、
レスポンスヘッダ は上部に複数行あり、
\r\n\r\n(CRLFが2回)で ヘッダの終わり(空行)を示し、
その後に メッセージボディ(HTMLなど)が続く。
そのため、外部から受け取った値に \r\n(CRLFが2回) が含まれていた場合、それがヘッダの終わりや新しいヘッダの開始として解釈されてしまう。

発生する原因

レスポンスヘッダにおいて改行に特別な意味があるにもかかわらず、外部から指定された改行をそのまま出力すること。

影響

・任意のクッキーの生成
・任意のURLへのリダイレクト
・表示内容の改変
・任意のJavaScript実行によるXSSと同様の被害

対策

HTTPヘッダの出力部分を手作りせず、ヘッダ出力用のライブラリやAPIを利用すること。
レスポンスヘッダを構成する文字列中に改行コードが含まれていないかチェックし、改行コードが含まれている場合は、エラーとして処理を中止する。

攻撃手法と影響

※PHPはHTTPヘッダ・インジェクション脆弱性の対策が行われている。
%0D%0Aが改行を表す。

外部ドメインへのリダイレクト

ApacheがCGIプログラムから受け取ったヘッダ中にLocationヘッダが複数あると、Apacheは最後のLocationヘッダのみをレスポンスとして返す。
→ この性質を利用して、本来のリダイレクト先を消して、改行の後ろに指定したURLを有効にするような設定ができてしまう。

パラメータに改行を挿入することにより、新たなHTTPレスポンスヘッダを追加する攻撃がHTTPヘッダ・インジェクション攻撃。
※CrLfインジェクション攻撃やHTTPレスポンス分割攻撃と呼ぶ場合もある。

HTTPレスポンス分割攻撃


https://www.ipa.go.jp/security/vuln/websecurity/http-header.html より画像引用

HTTPヘッダ・インジェクション攻撃により複数のHTTPレスポンスを作り出し、キャッシュサーバー(プロキシサーバー)に偽のコンテンツをキャッシュさせるという攻撃手法
HTTP1.1では、複数のリクエストをまとめて送信することができ、この場合レスポンスもまとめて返される。この性質を利用し、攻撃者はHTTPヘッダ・インジェクションを行なうHTTPリクエスト(第一リクエスト)の後ろに、偽のコンテンツをキャッシュさせたいURLに対応したHTTPリクエスト(第二リクエスト)を付け加える。
このとき、第一リクエストのHTTPヘッダ・インジェクション攻撃により、偽のコンテンツをHTTPレスポンスに挿入させると、キャッシュサーバーが偽のコンテンツを第二リクエストに対するHTTPレスポンスと誤認してキャッシュする。キャッシュ汚染ともいう。

キャッシュ汚染の場合、影響を受ける利用者が多く、影響が長く続く。
原因と対策は、HTTPヘッダ・インジェクトションと同じ。

任意のクッキー生成


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

HTTPヘッダ・インジェクション攻撃により追加されたSet-Cookieヘッダが有効になっている。
これにより、クッキーがブラウザにセットされてしまう。

偽画面の表示

HTTPヘッダ・インジェクションによる画面改ざんには、XSSと共通の影響があり得る。

脆弱性が生まれる原因

HTTPレスポンスヘッダはテキスト形式で1行に1つのヘッダが定義できる。
→ ヘッダとヘッダは改行で区切られている。
リダイレクト先URLやクッキー値として設定されるパラメータ中に改行を挿入した場合に、改行がそのままレスポンスとして出力されることが、HTTPヘッダ・インジェクションの原因。


URLは仕様として改行文字を含めることができない。
クエリー文字列に改行を含める場合は、%0D%0Aとパーセントエンコードするが、
リダイレクト処理にURLを渡す時点ではパーセントエンコードは終わっているはずであるため、URLに改行が入っていること自体が異常。

クッキー値に改行を含めたいという状況はあり得る。
クッキー値には、改行のほか、空白やカンマ、セミコロンを含ませることができないため、クッキー値をパーセントエンコードする習慣がある。値をパーセントエンコードしていることで、改行は%0D%0Aという形にエンコードされるため、HTTPヘッダ・インジェクション脆弱性の余地はない。


対策

外部からのパラメータをHTTPレスポンスヘッダとして出力しないこと

● 対策1:外部からのパラメータをHTTPレスポンスヘッダとして出力しない

設計段階で外部からのパラメータをHTTPレスポンスヘッダとして出力しないように設計を見直すことで、多くの場合対策できる。

◎ リダイレクト先をURLとして直接指定せず、固定にするか番号などで指定する
◎ Webアプリケーション開発ツールの提供するセッション変数を使ってURLを渡す

どうしても外部からのパラメータをHTTPレスポンスヘッダとして出力しなければならない場合、対策2を講じる。

● 対策2:以下の両方を実施する

① リダイレクトやクッキー生成を専用APIにまかせる
CGIプログラムでは、print文などによりHTTPレスポンスヘッダを直接記述できるが、この方法ではHTTPやHTTPやクッキーなどの規格に従って記述する必要があり、規格から外れると脆弱性などバグの原因になる。
できるだけクッキー生成・リダイレクト機能を提供するライブラリ機能を利用し、これらがない場合のみ汎用のレスポンスヘッダ出力機能を使用するようにする。
各言語に用意されたHTTPレスポンスヘッダ出力機能は、クライアント(ブラウザなど)に対して、レスポンスの性質や追加情報を伝えるために使用される。これにより、クライアントはレスポンスの内容をどう扱うかを判断できるようになる。
たとえば、PHPやPython、Node.jsなどでは、標準出力(echoやprintなど)とレスポンスヘッダを明確に分ける必要があるため、専用の関数が提供されている。


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

これらのライブラリ機能だけでは不十分なため、以下の②も併用する必要がある。

② ヘッダ生成するパラメータの改行文字をチェックする
HTTPレスポンスヘッダに関数APIには改行をチェックしないものが多くある。
そのため、改行文字に対する処理方法には以下のようなものがある。
URL中の改行はエラーとする
クッキー値の改行はパーセントエンコードする
ただし、ライブラリ側でクッキー値をパーセントエンコードしている場合、アプリケーション側でパーセントエンコードする必要はない。
PHPのsetcookie関数はライブラリ側でクッキー値をパーセントエンコードする。

https://rbintelligence.blog.shinobi.jp/ロボット/プラットフォーム、フレームワーク、ミドルウェア、ライブラリの違い より画像引用

ライブラリを使用する場合は、クッキー値がパーセントエンコードされるかどうかを開発前に調査してから使うこと。
※PHPの改行チェックはバージョンや提供元によってできないため、当面の間、PHPのheader関数のチェックのみでリダイレクト処理を実装すると危険であると認識すること。

mabomabo

クッキー出力にまつわる脆弱性

クッキーにまつわる脆弱性

① クッキーを利用すべきでない目的でクッキーを使っている
② クッキーの出力方法に問題がある

クッキーはセッションIDの保管場所として利用すべきであり、データそのものをクッキーに保存するのはよくない。

クッキー出力時に発生する脆弱性

① HTTPヘッダ・インジェクション脆弱性
② クッキーのセキュア属性不備

mabomabo

クッキー出力にまつわる脆弱性

クッキーの不適切な利用

Webアプリケーションで、ページをまたがる情報を保存する方法として、PHPなどが提供するセッション管理機構がある。

セッション管理機構イメージ

https://fuka.hateblo.jp/entry/2022/04/26/144653 より画像引用

一般的に、セッション管理機構ではセッションIDのみをクッキーに保存し、データ自体はWebサーバーのメモリやファイル、データベースなどに保存する。
クッキーに保存すべきでないデータを保存してしまうと、脆弱性が発生してしまう可能性がある。

クッキーとセッションの保存場所の違い

https://gray-code.com/php/cookie-and-session/ より画像引用

クッキーに保存すべきでない情報


https://shukapin.com/infographicIT/session-management より画像引用
セッション変数は外部からの書き換えができない

クッキー値はアプリケーションの利用者によって書き換えができる
→ 書き換えられると困るユーザIDや権限情報のような情報をクッキーに保存すると脆弱性の原因になる。


クッキーの基本構造と保存場所

クッキーは、名前と値のペアで構成されている

Set-Cookie: user_id=12345; Path=/; HttpOnly; Secure

ブラウザはこれを受け取ると、ローカルに保存する。つまり、クッキーはユーザーのブラウザ内に保存されているということ。
保存されている情報
・名前(Name)
・値(Value)
・有効パス(Path)
・有効期限(Expires/Max-Age)
・セキュリティ属性(HttpOnly、Secure、SameSite など)

書き換え可能な理由

ユーザーのブラウザ内に保存されているということは、ユーザーが持っているPCやスマホ上のデータということになる。そのため、以下の手段を使えばユーザー自身でクッキーの内容を自由に閲覧・変更できる。
・開発者ツール(Chrome の DevTools など)
・JavaScript の document.cookie
・ブラウザ拡張機能(EditThisCookie など)

クッキーの構造との関係

クッキーには暗号化や改ざん防止の仕組みは元々備わっておらず、ただの「テキスト情報」であり、サーバー側で署名や暗号化をしていない限り、書き換え放題の構造になっている。
そのため、認証情報や重要なデータをそのままクッキーに入れるのは危険。

安全性を高める方法

・サーバー側でクッキーの値に署名をつけて、改ざんされたら無効とする(例:LaravelのSigned Cookie)。
・HttpOnly をつけて JavaScript からアクセスできないようにする。
・Secure をつけて HTTPS 通信でしか送信されないようにする。


クッキーにデータを保存しないほうがよい理由


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

クッキーにできてセッション変数にできないこと
・情報の寿命の制御
・異なるサーバーとの情報共有
※セッション変数の方が便利で安全なため、通常セッション変数を利用すべき
セッションやサーバーをまたがって情報を保存する必要性がある場合にはクッキーを利用する。

Webアプリケーションでは、機密性の高い情報を表示する場合にパスワードの再入力(再認証)を求めるように実装できる。また、セッションに保存されている情報はセッションタイムアウトすると表示されなくなる
→ このような制御はクッキー自体に情報を保存している場合は困難

mabomabo

クッキー出力にまつわる脆弱性

クッキーのセキュア属性不備


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

クッキーには Secure という属性(セキュア属性)があり、これを指定したクッキーはHTTPSの場合のみブラウザからサーバーに送信される。アプリケーションがHTTPS通信を利用していても、セキュア属性のついていないクッキーは平文で送信される場合があり盗聴される可能性がある。
クッキーにはセッションIDなどセキュリティ上重要な情報が格納されている場合が多いので、クッキーが盗まれるとなりすましの被害に直結する。

参考URL:https://itechinc.jp/2025/03/02/secure-cookie-management/

対策

クッキーのセキュア属性を設定すること
ただし、HTTPとHTTPSが混在するサイトでは、セッションIDに対してクッキーのセキュア属性を設定すると、アプリケーションが動かなくなる場合がある。この場合、セッションIDとは別に、トークンをセキュア属性つきクッキーとして発行して、ページごとに確認する方法がある。

セキュア属性

https://itechinc.jp/2025/03/02/secure-cookie-management/ より画像引用

Secure 属性を持つクッキーは、HTTPS通信時にしか送信されない。
これがないと、HTTP通信でもクッキーが送信されてしまう可能性がある。

HTTPOnly属性

https://itechinc.jp/2025/03/02/secure-cookie-management/ より画像引用

攻撃手法と影響

セッションハイジャック(Session Hijacking)
・ユーザーが HTTPS でログインし、クッキーにセッションIDが保存される。
・その後、ユーザーがHTTPのページ(たとえば http://example.com)にアクセスすると、クッキーが 暗号化されていないHTTP通信で送信される。
・攻撃者が通信を盗聴(スニッフィング)してセッションIDを取得。
・攻撃者がそのセッションIDを使って、被害者になりすましログイン状態を乗っ取る。
→ 個人情報の流出
→ なりすましによる操作(注文、書き込み、データ削除など)
→ サービスの不正利用

中間者攻撃(Man-in-the-Middle, MITM)
・公共Wi-Fiなどで攻撃者が中間に入り、HTTP通信を傍受
・Secure属性のないクッキーがHTTP経由で送信され、攻撃者が取得
→ セッションIDの窃取
→ パスワード再設定トークンなどの乗っ取り

影響
・暗号化されていない通信でセッションIDが盗まれる
・なりすましログイン・情報漏洩などのリスク

脆弱性が生まれる原因

セキュア属性をつけていないこと

クッキーにセキュア属性をつけることができないアプリケーション

WebアプリケーションにはショッピングサイトのようにHTTPとHTTPSの両方を使うものがある。
このようなアプリケーションにはセッションIDを保持するクッキーにセキュア属性を設定することは困難。セッションIDのクッキーにセキュア属性をつけると、HTTPのページではセッションIDのクッキーが受け取れず、セッション管理機構が使えなくなってしまう。


https://www.kyorin.co.jp/modules/products_servise/index.php?content_id=94 より画像引用

HTTP・HTTPS混在の画面遷移

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

この問題はサイト全体をHTTPSにする「常時TLS」にしたうえでクッキーにセキュア属性をつけることで解決できる。常時TLSへの移行が難しい場合はトークンを用いた対策がある。

対策

セッションIDのクッキーにセキュア属性をつける方法

PHPの場合、php.ini に以下の設定を行なう

セキュア属性の設定
session.cookie_secure = on

トークンを用いた対策

セッションIDを保持するクッキーにセキュア属性がつけられない場合、トークンを利用してセッションハイジャックを防止する方法がある。(※セッションIDの固定化の対策と同じ)

トークンを保持するクッキーにセキュア属性をつけることによって、HTTPのページとHTTPSのページでセッションを共有しつつ、仮にセッションIDを盗聴された場合でもHTTPSのページはセッションハイジャックを防止できる。

※hash_equals 関数はタイミング攻撃に耐性があり、予防的に使用することが推奨される。

トークンにより安全性が確保できる理由

トークンがブラウザとサーバーの双方向で確実に暗号化されること、HTTPSのページを閲覧するには第三者の知り得ないトークンが必要であることから、安全性が確保される。
① トークンは認証成功時に一度だけサーバーから出力される
② トークンはHTTPSのページで生成される(サーバー → ブラウザ)
③ トークンは確実に暗号化されてブラウザから送信される(ブラウザ → サーバー)
④ HTTPSのページを閲覧するにはトークンが必須

セキュア属性以外の属性値に関する注意

Domain属性
デフォルト状態が最も安全な状態
Domain属性を指定するのは、複数のサーバーでクッキーを共有する場合だが、通常セッションIDを複数サーバー間で共有する意味はない。特殊な理由がない限りDomain属性を指定する必要はない。

Path属性
PHPのセッションIDは、デフォルトでは「path=/」という属性で発行される。
通常はこれでいいが、ディレクトリごとに異なるセッションIDを発行したい場合にはPath属性の指定が有効。
ただし、Path属性を指定しても安全性が高まるわけではない点に注意

Expires属性
セッションIDのクッキーには通常Expires属性をつけず、ブラウザ終了と同時にクッキーが削除される状態にする。Expires属性を設定すると、ブラウザが終了した後も認証状態を維持することができる。

HttpOnly属性
HttpOnly属性をつけたクッキーはJavaScriptから参照できなくなる。セッションIDをJavaScriptから参照する意味はないので、HttpOnly属性は通常つけると良い。

mabomabo

メール送信の問題

メールヘッダ・インジェクション脆弱性
メールメッセージの宛先や件名などヘッダーフィールドに改行を挿入することにより、新たなフィールドを追加したり、本文を改ざんしたりする攻撃手法

※HTTP field (ヘッダーフィールド) とはHTTPメッセージやペイロードに関する情報を伝達する、キーとバリューのデータ(HTTPヘッダと言われて思い浮かべるアレ)

hiddenパラメータによる宛先保持
送信先メールアドレスなどは、hiddenパラメータに保持せず、サーバー上の安全な場所(ファイルやデータベースなどに)保持すべき

メールサーバーによる第三者中継
メールサーバーの設定に問題があると、そのメールサーバーの発信者でも受信者でもない、第三者のメールを中継する場合がある。このような設定のサーバーは、迷惑メールなどの送信に悪用される可能性がある。

※迷惑メールを中継するイメージ

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

最近のメールサーバーソフト(MTA)は、デフォルト状態で第三者中継を許さない設定になっており、正しい手順でメールサーバーを設定している限り問題はない可能性が高い。

mabomabo

メール送信の問題

メールヘッダ・インジェクション脆弱性

宛先(To)や件名(Subject)などのメールヘッダを外部から指定する際に、改行文字を使ってメールヘッダや本文を追加・変更する手法

影響
・件名や送信元、本文を改変される
・迷惑メールの送信に悪用される
・ウイルスメールの送信に悪用される

対策
・外部からのパラメータをメールヘッダに含ませないようにする
・外部からのパラメータには改行を含まないようにチェックする

攻撃手法と影響

(PHP)mb_send_mail: マルチバイト文字対応のメール送信関数
mb_send_mail() は、PHPスクリプトが動作しているサーバーから、指定されたメールサーバー(通常はSMTPサーバー)に対してメールを送信するための関数。この通信は、HTTPリクエストとは異なるプロトコル(SMTP)で行われる。

PHPでメールを送信する標準的な関数に mail() があるが、これはマルチバイト文字(日本語、中国語、韓国語など)を扱う際に文字化けを起こしやすいという問題がある。
→ mb_send_mail() は、この問題を解決するために設計された関数。マルチバイト文字を正しくエンコードして送信できるため、日本語のメールを送信する際にはほぼ必須と言える関数。

マルチバイト:文字を表現するのに2バイト以上必要

https://docs.oracle.com/cd/B14117_01/server.101/b10749/ch2charset.htm より画像引用

基本構文
bool mb_send_mail ( string $to , string $subject , string $message [, string $additional_headers = "" [, string $additional_parameter = "" ]] )

$to (宛先)
受信者のメールアドレスを指定する。
複数の宛先を指定する場合は、カンマ , で区切る。

$subject (件名)
メールの件名を文字列で指定する。
日本語などのマルチバイト文字を含む場合は、後述するエンコーディング設定が必要。

$message (本文)
メールの本文を文字列で指定する。
日本語などのマルチバイト文字を含む場合は、後述するエンコーディング設定が必要。
改行を含める場合は、\n を使用する。

$additional_headers (追加ヘッダー): (省略可能)
送信元 (From)、CC、BCC、Content-Type など、追加のメールヘッダーを指定する文字列。
複数のヘッダーを指定する場合は、改行 \n で区切る。
特に From ヘッダーや Content-Type ヘッダーで文字エンコーディングを指定することが重要。

$additional_parameter (追加パラメータ): (省略可能)
sendmail などのメール送信プログラムに渡す追加のコマンドラインパラメータを指定する文字列。
通常は省略可能。

脆弱性の原因は、このmb_send_mailは、改行で区切ることで複数のヘッダを指定可能であるにもかかわらず、アプリケーションではアプリケーションでは改行が入力される可能性は考慮されていないことにある。

攻撃1:宛先の追加

攻撃2:本文の改ざん

脆弱性が生まれる原因

理解するために、まずメールのメッセージ形式を知る必要がある。

※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

mabomabo

認証


https://sokowaku.com/blog/12086 より画像引用

認証とは、利用者が確かに本人であることをなんらかの手段で確認することを指す。
Webアプリケーションで用いられる認証には、HTTP認証、HTMLフォームでIDとパスワードを入力させるフォーム認証、TLSクライアント認証を用いるクライアント認証がある。

ログイン機能

ユーザーIDとパスワードをデータベースに照合して、一致したものがあれば認証したとみなす機能。

ログイン機能に対する攻撃

ログイン機能に対する攻撃が成立すると、不正ログインが可能になる。

SQLインジェクション攻撃によるログイン機能のバイパス
ログイン画面にSQLインジェクション脆弱性がある場合、パスワードを知らなくても認証機能をバイパスしてログインできる場合がある。

SQLインジェクション攻撃によるパスワードの入手
アプリケーションのどこかにSQLインジェクション脆弱性があると、データベースに保存してあるユーザーIDやパスワードなどを盗み出される場合がある。

ログイン画面に対するパスワード試行
ログイン画面から、さまざまなパスワードを繰り返す試す手法がある。
・ブルートフォース攻撃:パスワードの文字列の組み合わせをすべて試す方法
・辞書攻撃:パスワードに用いられやすい文字列の集合を辞書として用意しておき、辞書に保存されたパスワード文字列を順に試す方法

ソーシャルエンジニアリングによるパスワード入手
利用者や管理者を騙して重要情報を得る手法。

フィッシングによるパスワード入手
本物そっくりな画面を備えた偽サイトを仕立てて、利用者に重要情報を入力させる手口のこと。

不正ログインを防ぐ条件(フォーム認証)

SQLインジェクションなどセキュリティバグをなくす

ログイン機能で発生しやすい脆弱性
・SQLインジェクション
・セッションIDの固定化
・クッキーのセキュア属性不備
・オープンリダイレクト脆弱性
・HTTPヘッダ・インジェクション

パスワードを予測困難なものにする

一般的には、ユーザの利便性とセキュリティ強度は相反する傾向にある。


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

パスワードの文字種と桁数の要件

最も基本的な要件はパスワードに使える文字種と桁数。文字種の数と桁数によって、パスワードとして利用できる文字数の総数が決まる。
パスワードの組み合わせ総数 = 文字種の数 ^ 桁数

※利用者は覚えやすく入力しやすいパスワードを好む傾向にあることが統計でわかっているらしい。

パスワードに関するアプリケーション要件

アプリケーション側の最低限の要件は「利用者が安全なパスワードをつけることを邪魔しないこと」
= 文字種や桁数の制限を必要以上に厳しくしないこと

文字種と桁数の制限を緩めると、利用者がパスワードではなく、パスフレーズ(文の形をした長いパスワードのこと)を利用することができるようになる。

積極的なパスワードポリシーのチェック

パスワードに対する攻撃に備えてWebアプリケーションが積極的にパスワードをチェックするためのパスワードポリシー候補
・桁数に関するもの
・文字種に関するもの
・ユーザIDと同じパスワードの禁止
・パスワード辞書に載っているありがちな単語の禁止

mabomabo

認証

パスワード認証を狙った攻撃への対策

オンラインでのブルートフォース攻撃への対抗策として、アカウントロックが有効
(例)パスワードを3回間違えるとキャッシュカードが使えなくなる

ブルートフォース攻撃

https://www.syteca.com/en/blog/brute-force-attacks より画像引用

ユーザIDを固定して、パスワードの方を入れ替えながらログインを試す。

基本的なアカウントロック

実装内容
・ユーザIDごとにパスワード間違いの回数をカウントする
・パスワードの間違いの回数が上限値を超えると、アカウントをロックする。ロックされたアカウントはログインできなくなる
・アカウントロックが発生した場合はメールなどで対象利用者と管理者に通知する
・正常にログインした場合は、パスワード間違いのカウンタをクリアする

ロックされたアカウントの再有効化
・アカウントロックから30分経過した場合、自動的に再有効化される
→ 正当な利用者が閉め出される可能性を少なくするため
・管理者が、なんらかの方法で本人確認した後に再有効化する

必要に応じて、アカウント管理者は、アカウントロックの発生状況を調べた上で、攻撃がきているIPアドレスからの通信を遮断するなどの対処ができる。

パスワード認証に対する攻撃のバリエーションと対策

辞書攻撃
使用頻度の高いパスワード候補から順に試す方法
→ アカウントロックが有効

ジョーアカウント探索
ユーザIDと同じ文字列をパスワードに設定しているアカウントをジョーアカウントという。
アプリケーションがジョーアカウントを禁止していない場合、ジョーアカウントは一定の割合で存在する。

リバースブルートフォース攻撃

https://office110.jp/security/knowledge/cyber-attack/reverse-brute-force より画像引用

パスワードを固定して、ユーザIDを取り替えながらログインを試す。

パスワードスプレー攻撃
少数のパスワード候補をIDを変えながら試していく攻撃

パスワードリスト攻撃
攻撃対象サイトとは別のサイトから漏洩したIDとパスワード一覧を用いてログイン試行する攻撃。


※『体系的に学ぶ安全なWebアプリケーションの作り方 第2版(固定版) 脆弱性が生まれる原理と対策の実践』より引用

攻撃者は、攻撃対象のサイトとは別のWebサイトをSQLインジェクション攻撃などにより攻撃してIDとパスワードの一覧を得る。
攻撃者は攻撃対象サイトに対して、パスワードリストのIDとパスワードを用いてログインを試す。別のサイトのIDとパスワードだが、両方のサイトで同じIDとパスワードを設定している人がいるので、ある確率でログインに成功する。

パスワードを狙った攻撃への対策

決めてとなる対策がないのが現実。

2段階認証の実装
パスワードの検証が成功した後に、追加の秘密情報を要求することにより、認証を強化する方法。
追加の秘密情報を使用する。
(例)
・メールやSMSで送られる6桁程度の数字
・スマホアプリなどで生成される6桁程度の数字