Java: EasyBuggy - 30分でわかる！クロスサイト・スクリプティング(XSS)脆弱性

# 概要

[EasyBuggy](https://github.com/k-tamura/easybuggy/blob/master/README.jp.md)と[EasyBuggy Boot](https://github.com/k-tamura/easybuggy4sb/blob/master/README.jp.md)を利用して、クロスサイト・スクリプティング(XSS)脆弱性をシミュレートし、その修正を試みます。

環境構築はこちらの記事から。

https://qiita.com/flyaway/items/4922af5dbaafa1942e88

## 注意事項

本記事では脆弱性をついた攻撃手法について解説しています。

しかし、実際に第三者が運用しているWebサービスなどに対して、勝手に脆弱性の検査をおこなうのは違法行為となる可能性が非常に高いです。無害な検査用文字列を送信しているだけのつもりであっても、意図しない破壊を招いたり、監視システムによって攻撃と勘違いされる可能性があります。

絶対にやめましょう。

参考事例: [脆弱性検査について](https://www.whitehackerz.jp/blog/%E8%84%86%E5%BC%B1%E6%80%A7%E6%A4%9C%E6%9F%BB%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/)

# 脆弱性を確認する

EasyBuggyを起動し、`脆弱性 > XSS(クロスサイトスクリプティング)`を選択します。

![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3571/9e2928b8-03cd-0a5a-c67f-de4c3bf7e443.png)

画面の指示に従い`>tpircs/<;)eikooc.tnemucod(trela>tpIrcs<`を入力します。
すると、`<scrIpt>alert(document.cookie);</script>`としてHTMLに埋め込まれ、JavaScriptとして実行されます。

ただ、これだけだと、単に自分が入力したJavaScriptが実行されて、自爆しているだけにも思えます。
脆弱性の怖さがわかりません。

では、次の場合ではどうでしょうか。

## 攻撃シナリオの例

さきほどのページのURLの末尾に `?string=%3Etpircs%2F%3C%22%2Fmoc.atiiq%2F%2F%3Asptth%22%3Dnoitacol.tnemucod%3Etpircs%3C` を付与してみてください。

何が起きましたか？思ってもいなかった結果になったのではないでしょうか。

悪意のある攻撃者は、メールなどでターゲットユーザーにURLを送りつけます。
ターゲットは、見慣れた信頼性のあるドメインのURLであればアクセスしてしまうかもしれません。
その結果、思ってもいなかったJavaScriptコードが、ターゲットのブラウザで実行されてしまいます。

上記のURLはQiitaのトップページにリダイレクトするだけです。
しかし、たとえば、これに先ほどのセッションID(Cookie)を付与した上で、攻撃者が用意した罠サイトにリダイレクトすることもできます。

この場合、ターゲットがURLにアクセスすると、攻撃者はアクセスの記録からセッションIDを盗むことができます。入手したセッションIDを利用して、[セッションの乗っ取り（セッション・ハイジャック）](https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_4.html)がされてしまうことでしょう。

# 脆弱性を修正する

XSS脆弱性の根本的解決のためには、いくつかの方法があります。
そのうち、今回は「ウェブページに出力する全ての要素に対して、エスケープ処理を施す」という方法での修正を試みます。

https://www.ipa.go.jp/security/vuln/websecurity-HTML-1_5.html

## EasyBuggyの場合

XSSServletクラスに問題となる実装があります。
下記のような著名なライブラリを利用して、エスケープするのがよいでしょう。
（プロジェクト内で修正方法が指定されている場合は、それに従ってください）

Guava: `HtmlEscapers.htmlEscaper().escape(String string)`

https://guava.dev/releases/30.0-jre/api/docs/com/google/common/html/HtmlEscapers.html#htmlEscaper()

Apache Commons Text: `StringEscapeUtils.escapeHtml4(String input)`

https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StringEscapeUtils.html

EasyBuggyでは、これらのライブラリが入っていないので、Mavenを利用して依存関係を追加します。

- [Guava: Google Core Libraries For Java » 30.1-jre](https://mvnrepository.com/artifact/com.google.guava/guava/30.1-jre)
- [Apache Commons Text » 1.9](https://mvnrepository.com/artifact/org.apache.commons/commons-text/1.9)

Eclipseでmavenプロジェクトにライブラリの依存関係を追加する方法は、下記の記事を参考にしてみてください。

https://qiita.com/futo_creid/items/cfe730a4c35dd5f2be75#maven%E3%81%A7%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E8%BF%BD%E5%8A%A0

うまくライブラリが`Referenced Libraries`に反映されない場合は、`mvn eclipse:eclipse`コマンドの実行を試してみてください。

## EasyBuggy Bootの場合

先ほどのXSSServletクラスの実装は、XSSControllerクラスに移植されています。
一見、このクラスを修正すればいいように思いますが、それは適切ではありません。
EasyBuggy Bootでは、プレゼンテーション層(ユーザー・インターフェイス層)に[Thymeleaf](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf_ja.html)を利用しています。

エスケープ処理は、画面を描画する処理の直前におこなうのが鉄則です。
処理の途中でエスケープしてしまうと、プログラム中のほかの処理にて、誤った判定などをしてしまう可能性があるからです。

このため、Javaのソースコード内ではなく、Thymeleafのテンプレートファイル内にてエスケープをおこないましょう。
XSSControllerクラスの代わりに、`src/main/resouces/templates/xss.html`ファイルを修正します。

エスケープ(サニタイズ)する必要があるときは、`th:utext`ではなく`th:text`を利用します。
(Thymeleafでは、基本的に `th:text` を利用します)

https://qiita.com/NagaokaKenichi/items/c6d1b76090ef5ef39482#html%E3%82%BF%E3%82%B0%E3%82%92%E3%82%B5%E3%83%8B%E3%82%BF%E3%82%A4%E3%82%BA%E3%81%97%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B

# まとめ

ユーザーが入力した文字列をそのまま画面に表示する場合、XSS脆弱性が生じる可能性があります。HTMLエスケープにより修正する際には、以下の2点に注意しましょう。

1. 著名なライブラリやフレームワークを利用すること
1. 画面を描画する処理の直前におこなうこと

# 補足

今回は、HTMLに埋め込む場合のエスケープ処理について学習しました。
しかし、その他の埋め込みパターンでは、別の方式でエスケープする必要があります。

たとえば、Spring Frameworkをもとにして作成された[TERASOLUNA Server Framework](http://terasolunaorg.github.io/guideline/5.6.1.RELEASE/ja/index.html)では、XSS対策として3種類のエスケープを使い分けることを説明しています。

ぜひ、こちらも参考にしてみてください。

http://terasolunaorg.github.io/guideline/5.6.1.RELEASE/ja/Security/XSS.html