導入
情報処理安全確保支援士の勉強をするにあたって、クロスサイトスクリプティング(XSS)の型の違いがよくわからなかったのでメモ。
間違いがあったらコメントください。
XSSとは
クロスサイトスクリプティング(以下、XSS)とは、一言で言うと
「WebページやURLに悪意あるスクリプトを仕込んで、他の人のブラウザで勝手に実行させる攻撃」
ただ、この”スクリプトを仕込む”方法が3通りあって初心者にはわかりづらい。
3通りのXSSはそれぞれ
・反射型(Reflected)
・保存型(Stored)
・DOMベース型(DOM-Based)
と言う名前。
先にまとめ
・どの型も「悪意のあるスクリプトを実行するのはWebブラウザ側」
・型ごとに「悪意のあるスクリプトをWebブラウザに提供するルートが違う」
・対策はWebサーバ側で行う。
色々対策はあるが、エスケープ処理とCSPを覚えていれば良さそう。
反射型(Reflected)
特徴:
攻撃スクリプトがURLやフォーム入力に含まれ、レスポンスでそのまま返される。
攻撃例:
攻撃者はメールやWebサイトに
http://example.com/search?q=<script>alert('XSS')</script>
のようなURLを掲載する。
なお、このURLの意味は
http://example.com/ のサイト内検索で、
<script>alert('XSS')</script>"
と入力したときの検索結果を表示するURL。
もしWebサイト側がなんの対策もしていないと、
ユーザーが上記URLを開いた瞬間にWebサイトはスクリプトを含んだ検索結果ページをレスポンスするので、
スクリプトが実行されてしまう。
対策
メインは2つ。すべてWebサーバー側で行う対策。
1.エスケープ処理
結局のところ、
ブラウザからWebサーバに送った内容(?q=以降) = 攻撃者が仕込んだ内容
をそのまま検索結果のページに表示しようとするのがダメなんだと言う考え方で対策する方法。
ブラウザからの送信内容のうち、特別な処理をしてしまう文字を安全な文字に置き換える。
< → <
> → >
" → "
' → '
& → &
これで、
<script>alert('XSS')</script>"
は
<script>alert('XSS')</script>"
とスクリプトとしての体裁をなさなくなるので、表示されても安全。
2.Content-Security-Policy(CSP)
知らないスクリプトの実行は認めないよ。と言う対策。
httpレスポンス(検索結果の表示)において、HTTPヘッダーに例えば
Content-Security-Policy: script-src 'self' https://cdn.example.com
と設定。
このヘッダーを設定するとスクリプトの実行が制限される。
スクリプトの種類 | 実行 | 例 |
---|---|---|
インライン | されない | <script>alert('XSS')</script>" |
外部のスクリプト | されない | https://atack.com/script.js |
自サイトのスクリプト | される | https://example.com/script.js |
ヘッダーに設定したドメインのスクリプト | される | https://cdn.example.com/script.js |
ヘッダーに設定していないドメインのスクリプト | されない | https://sub.example.com/script.js |
インラインが実行されないので、検索などでスクリプトを入力されても実行されない。
また、知らないドメインのスクリプトを呼び出そうとしても実行できない。
自サイトおよびヘッダーで許可したドメインのスクリプトのみ実行できる。
なお、注意点としては
・スキーム(httpやhttps)
・ドメイン
・ポート番号
の全てが一致する場合のみ、同一オリジン(スクリプトの実行が可能)と判断される。
なので、例で言うと
http://example.com/script.js
はスキームが違うのでダメ。
保存型(Stored)
特徴:
反射型はブラウザからのリクエストに攻撃が仕込まれていましたが、保存型はWebサーバ側に攻撃が仕込まれる。
そして、そのWebサーバのページを表示した瞬間に攻撃が実行される。
攻撃例:
攻撃者は掲示板サイトのコメントに
<script>alert('XSS')</script>"
と攻撃スクリプトを投稿する。
そのあと、ユーザが掲示板サイトを表示すると攻撃スクリプトが実行される。
対策
反射型と同じ。
投稿コメントを表示する際に、危険な文字は安全な文字に書き換えてあげればいいし、
知らないスクリプトは実行できないように制限をかければいい。
DOMベース型(DOM-Based)
特徴:
攻撃スクリプトがサーバには一切送られず、クライアントのJavaScriptの処理によって、DOM上でXSSが成立する攻撃。
攻撃例:
攻撃者はメールやWebサイトに
https://example.com/index.html#<script>alert('XSS')</script>
のようなURLを掲載する。
ユーザーが上記URLを開こうとするとスクリプトが実行される。
なお、反射型との違いは以下。
型 | 攻撃 |
---|---|
反射型 | スクリプトがサーバに送信され、スクリプトを含んだレスポンスをされることで攻撃される。 |
DOM Based型 | スクリプトがサーバに送信されず、ブラウザが#以降を処理しようとして攻撃される。 |
対策:
1.信頼できない値は innerHTMLに入れない
※そもそもinnerHTMLとは
HTMLの中で、JavaScriptを使って画面の中身(文字やタグ)を動的に書き換えるための方法
#以降は基本Webサーバに送信されない。
しかし、Webサーバを表示したときに「このスクリプトを実行してね」と”本来正常な”スクリプトをWebサーバから受け取ることがある。そのスクリプトの中に
XXX = location.hash;
という記述があると、#以降の値をスクリプト内に埋め込むことができる。
このとき、#以降に攻撃スクリプトが含まれていると、それが実行されてしまう。
document.getElementById("output").innerHTML = location.hash;
なお、#以降をの値をWebサイトで利用したい場合はtextContentを利用すれば、そのまま文字列として処理されるので安全。
document.getElementById("output").textContent = location.hash;
要は、「 外部から入力される文字列にはinnerHTMLを使うな。」
2.CSP(Content Security Policy)
前述の通り。
おまけ
URLの?とか#って何?
私は知らなかったのでメモ。
クエリ文字列(?)
URLの?以降はクエリ文字列と呼ばれるもの。
サーバに送る追加の情報(パラメータ)であり、検索ワードやページ番号がセットされる。
Webサーバに?以降も送られる。
フラグメント識別子(#)
ページ内の特定の場所や状態を示すためのもの
ページ内の特定の場所にスクロールした状態で表示してくれる。
Webサーバに#以降は基本送られない。
※Webサーバ側がlocation.hashで取得することは可能。
HTTPのリファラに格納されるURLには#以降も含まれる。