Webセキュリティ対策~XSS~

Webセキュリティ対策~XSS~

目次

はじめに
XSSとは
ウェブページへの出力処理に問題がある場合とは
対策
総評

はじめに

最近Webセキュリティについて学ぶことがあったので備忘録として記事にしておこうと思います。

XSSとは

XSSはCross Site Scriptingの略称でクロスサイトスクリプティングと呼ばれます。(以下、XSS)
XSSの説明はよく色々なサイトで説明されているかと思いますので、そのうちの一つを引用させていただきます。

ウェブアプリケーションの中には、検索のキーワードの表示画面や個人情報登録時の確認画面、掲示 板、ウェブのログ統計画面等、利用者からの入力内容や HTTP ヘッダの情報を処理し、ウェブページとし て出力するものがあります。ここで、ウェブページへの出力処理に問題がある場合、そのウェブページに スクリプト等を埋め込まれてしまいます。この問題を「クロスサイト・スクリプティングの脆弱性」と呼び、こ の問題を悪用した攻撃手法を、「クロスサイト・スクリプティング攻撃」と呼びます。


IPA情報処理推進機構「安全なウェブサイトの作り方  改訂 第7版」22ページ目より

この説明を見て分かる方はうんうんと頷けるかと思いますが、私は最初全然分かりませんでした。
ここで最も重要なことは「 ウェブページへの出力処理に問題がある場合 」ということです。

ウェブページへの出力処理に問題がある場合とは

例えば入力項目に悪意のあるスクリプトを埋め込まれたとしたとき、この時点ではXSS攻撃はまだ成立していません。
実際に悪意のあるスクリプトが入力内容としてDBに保存され、保存された入力内容がWebページ上で表示したときに初めてXSS攻撃が成立します。

なぜこのタイミングかと言いますとWebページに表示したとき、Webページに書かれているスクリプトをブラウザは実行します。
その時、入力内容として保存されていた文字をブラウザがスクリプトとして認識させられてしまい、Webページの製作者が意図していなかったスクリプトを実行されるためになります。

このときに被害を受けるのはスクリプトを実行したブラウザであり、そのブラウザを使ってWebページを見ていた利用者になります。

ここで問題なのは入力内容として保存されていた文字を、ブラウザがただの文字として扱うのではなくスクリプトとして認識してしまったことになります。
つまり入力内容として保存されていた文字がただの文字として認識されるように対策しているWebページは安全ということになります。
その対策が出来ていないWebページは「出力処理に問題がある」ということになります。

一例として、 PHPを使って動的にページに値を埋め込む掲示板サイトがあったとします。
掲示板なので利用者がコメントを入力でき、入力したコメントは誰もが見れるようになります。

その掲示板では入力されたコメントはGetパラメータで次のページに渡され、次のページでそのコメントが表示されるものとします。
次のページは以下のようになっているとします。

"匿名利用者さんより"
<br> 
<?php echo $_GET['comment'];>

この場合、入力されたコメントが通常のコメントであればよいですが、悪意のあるスクリプトを埋め込んだ場合に
phpの処理によってhtmlにスクリプトが埋め込まれ、そのままブラウザに渡されることになります。
ブラウザはそれをコメントとしてではなく、スクリプトとして認識し、悪意のあるスクリプトが実行されてしまいます。

対策

では「出力処理に問題がある」Webページは何をすればよいのかというお話になりますが
ここはネットで調べてみるとすぐに見つかるかと思いますが、「<」「>」「&」「”」「’」をエスケープしてWebページに表示させるということになります。

これだけだと他で紹介されているものと同じになるので各記号をエスケープする必要がある理由を説明していこうと思いましたが、経緯が分かりやすい記事がありましたのでこちらを紹介させていただきます。
参考 XSS対策:どの文字をエスケープするべきなのか
https://ockeghem.hatenablog.jp/entry/20070510/1178813849

結論だけ言いますと各記号は必ずエスケープするのではなく、表示される場所によってエスケープする必要のある記号は違います。(5文字全てエスケープしても問題ありませんが、、、)

HTML本文内:「<」「>」「&」をエスケープする
HTMLタグ内の属性値: 「<」「>」「&」 「”」をエスケープする

PHPにはXSSの文字をエスケープする関数「htmlspecialchars」が用意されているのでそれを使って下記のように修正すれば出来るかと思います。

"匿名利用者さんより"
<br> 
<?php echo htmlspecialchars($_GET['comment'], ENT_QUOTES, "UTF-8")>

よくある入力値のチェックですが、効果がないことがあります。
というのも実際にXSSの攻撃が成立するのは保存されたデータがHTML上に表示されるときなので
入力値のチェックをしていても入力値以外からデータを保存されると意味がなくなるからです。

他にもHTTPヘッダーに影響が出たりなどもあるのですが、その辺りは「安全なウェブサイトの作り方」を参考してもらえればと思います。

総評

「入力値のチェックだけでなく、表示時にしっかりエスケープすることで対応するようにしましょう」ということですね。
またフレームワークによっては自動でエスケープしてくれるものもあったりしますが、同じフレームワークでもある場合はエスケープしてくれるが、別の場合はエスケープしてくれないといったこともありますのでよく確認するようにしましょう。


参考資料:IPA情報処理推進機構「安全なウェブサイトの作り方  改訂 第7版 」
https://www.ipa.go.jp/security/vuln/websecurity.html
参考サイト:XSS対策:どの文字をエスケープするべきなのか
https://ockeghem.hatenablog.jp/entry/20070510/1178813849