Snyk CodeでJavaアプリケーションのクロスサイトスクリプティング(XSS)を防止する
2023年4月25日
0 分で読めますJavaは強力なバックエンド向けプログラミング言語であり、WebアプリケーションのHTMLページの作成にも使用できます。ただし、こうしたページを作成する際には、クロスサイトスクリプティング(XSS)攻撃に伴う潜在的なセキュリティリスクを理解しておく必要があります。最新のテンプレートフレームワークの普及により、適切な入力検証やエンコードによってセキュリティ攻撃を防ぐことは容易になりました。一方、テンプレートフレームワークを使わずに独自のHTMLページを作成すると、脆弱性を持ち込むリスクが高まります。
たとえば、Spring MVCアプリケーションでHttpServletResponseオブジェクトを使い、レスポンスにコンテンツを直接書き込むと、悪意のあるユーザーがページにコードを挿入し、XSS攻撃を引き起こす可能性があります。そのため、HTMLページを作成する際には、XSS脆弱性を防ぐ適切な対策を実装し、Java Webアプリケーションのセキュリティを高い水準に保つことが重要です。
次のような方法を使えば、通常は特別な手順が必要となるフレームワークを使わずに、サーバーサイドレンダリングのページを簡単に実装できます。ただし、この方法には明らかなデメリットもあります。
テンプレートフレームワークを使わずにSpring MVCでHTMLを出力する
たとえば、Webアプリケーションで商品の名前を受け取り、HttpServletResponseオブジェクトを使ってWebページに表示するとします。Spring MVCのコントローラーでは、次のように実装できます。
上記のJavaコードに、どのようなセキュリティ脆弱性が潜んでいるか分かりますか?
Snyk CodeでXSSを検出する
上記の関数をよく見ると、XSS脆弱性が少なくとも1つ、場合によっては2つあることに気付くかもしれません。アプリケーションをSnyk Codeでスキャンすると、このメソッドにある2種類のXSSの問題が通知されます。
Snyk Codeの活用方法はいくつもあります。ここでは3つの例を見ていきましょう。開発者がSnyk Codeからフィードバックを得る最も手軽な方法は、IDEにプラグインをインストールすることです。さまざまなIDE向けのプラグインを用意しています。次の例では、IntelliJプラグインを使って開発中にXSSの問題を検出する方法をご紹介します。
IntelliJプラグインの出力:

Snyk CLIを使ってSnyk Codeを実行する方法もあります。ターミナルでsnyk code testコマンドを実行すると、次のような結果が表示されます。この方法は、ローカルマシン上でも、CI/CDパイプラインでの自動ビルドの一環としても利用できます。
CLIの出力:

3つ目にご紹介するのはWeb UIです。この出力を得るため、SnykのGit連携を使い、https://app.snyk.ioのダッシュボードからGitHubリポジトリをSnyk Web UIに接続しました。この方法では、リポジトリにコミットされたコードをスキャンし、セキュリティ脆弱性を検出します。
Web UIの出力:

3つのスキャン方法はいずれも、対処が必要なXSSのセキュリティ問題が2つあることを示しています。Snyk Codeなら、コード内の正確な場所も特定できます。それぞれの問題を詳しく見て、どのように軽減できるか確認しましょう。
リフレクティブXSS
リフレクティブXSSとは、ユーザーがWebアプリケーションに悪意のあるコードを挿入し、そのコードがレスポンスの一部としてユーザーに返されるタイプのXSS攻撃です。先ほどの例では、レスポンスに書き込む前にユーザー入力が適切に検証またはサニタイズされていないと、悪意のあるユーザーがスクリプトを挿入し、そのWebページを閲覧した他のユーザーのブラウザー上で実行させる可能性があります。この種のXSS攻撃は、ユーザーデータの窃取やWebサイトのコンテンツの改ざん、その他の悪意ある操作に利用されることがよくあります。
上記のコードは、HTTPリクエストパラメーターからユーザー名を取得し、次のようにHttpServletResponseオブジェクトに直接書き込みます。
このコードは、ユーザー入力を適切に検証またはサニタイズしていないため、XSS攻撃に対して脆弱です。たとえば、悪意のあるユーザーが「name」パラメーターにHTMLやJavaScriptのコードを挿入すると、そのWebページを閲覧した他のユーザーのブラウザー上で実行される可能性があります。
たとえば、.../direct?param=<script>alert(document.cookie);</script>によって、個人のCookie情報が漏えいする可能性があります。さらに、その情報をユーザーに気付かれないまま別のサーバーに送信することもできます。
Snyk Codeは、93行目にあるXSSを指摘し、この問題を検出しました。
ストアドXSS
一方、ストアドXSSとは、悪意のあるコードがサーバーに保存され、対象のページにアクセスするすべてのユーザーに配信されるタイプのXSS攻撃です。先ほどの例では、ユーザー入力が適切に検証またはサニタイズされず、データベースに保存されてしまうと、悪意のあるユーザーがスクリプトを挿入し、対象のページを閲覧するすべてのユーザーに配信させる可能性があります。この種のXSS攻撃は、多数のユーザーに影響し、最初の挿入箇所を修正した後も残る場合があるため、特に危険です。
上記のコードは、ProductServiceから商品を取得し、出力文字列の一部として各フィールドに表示します。しかし、データベース由来の入力を適切に検証またはサニタイズしていないため、ストアドXSS攻撃に対して脆弱です。データベースへの書き込み権限を持つユーザーが誰か分からない場合は、特にサニタイズが重要です。たとえば、悪意のあるユーザーがHTMLやJavaScriptのコードを含む商品説明を送信すると、データベースに保存され、商品ページを訪れたすべてのユーザーに配信される可能性があります。
Snyk Codeは103行目の潜在的なXSS問題を指摘しました。ここではproduct.descriptionを検証もサニタイズもせず、出力文字列に挿入しています。
Snyk CodeでXSS脆弱性を軽減する
XSS脆弱性を防ぐには、レスポンスに書き込む前にユーザー入力を適切に検証し、サニタイズすることが重要です。Snyk Codeは、考えられる解決策も提示してくれます。その方法の一つが、Apache Commons Textのようなライブラリを使って入力をエンコードし、悪意のあるコードが実行されないようにすることです。

escapeHtml4()関数を使えば、リフレクティブXSSとストアドXSSの両方に含まれるコードをエスケープし、ページの読み込み時に実行されないようにできます。
同様のエスケープ処理ができるライブラリはほかにもあります。Apache Commons Textに加えて、OWASP Encoderもご覧ください。Springを使っている場合は、SpringのHtmlUtils.htmlEscapeも利用できます。
Apache Commons Textを使って適切にエスケープすると、次のようになります。
テンプレートフレームワークにも注意する
Thymeleafなどのテンプレートフレームワークは、XSS脆弱性の防止に役立ちます。ThymeleafはJavaで広く使われているテンプレートエンジンで、HTMLエスケープ機能を標準で備えています。レンダリングされるHTMLに含まれるユーザー入力をエンコードすることで、XSS攻撃を防ぎます。
ただし、テンプレートの作成方法によって大きく異なります。たとえば、先ほどの例と同様に商品をレンダリングする場合、Thymeleafは次のように使えます。
この例では、th:text属性はエスケープされますが、th:utext属性はエスケープされません。このth:utext属性は、HTMLタグや特殊文字をエスケープせずにコメントテキストをレンダリングするため、XSSに対して脆弱になる可能性があります。特定のフレームワークを使う際は、各要素の動作を理解しておくことが重要です。
本番環境へのデプロイ前にXSSを検出する
XSS攻撃の防止は、Java Webアプリケーションを開発するうえで極めて重要な課題です。開発プロセスのできるだけ早い段階でXSS脆弱性を特定し、対処することが欠かせません。ユーザー入力のサニタイズはXSS攻撃の軽減に有効ですが、それだけでは不十分な場合もあります。
最新の脅威やXSS対策のベストプラクティスを把握するには、OWASP XSS Cheat SheetやSnyk LearnのXSSレッスンなどのリソースを活用しましょう。
さらに、本番環境に持ち込まれる前にXSSのミスやその他のセキュリティ問題を検出するため、適切なツールを活用することも重要です。Snyk Codeは、開発サイクルの早い段階で潜在的なセキュリティ脆弱性を特定できる、便利な無料ツールです。XSS対策に積極的に取り組み、適切なリソースやツールを活用することで、Java Webアプリケーションのセキュリティと完全性を維持できます。
Capture the Flagを始めよう
オンデマンドのバーチャル入門ワークショップを見て、Capture the Flagの課題の解き方を学びましょう。
