CSRF備忘録

CSRFとは?

CSRF (Cross Site Request Forgery)は、Cookieの認証情報を不正リンクによって悪用されること。

認証情報は一般的に、クッキー、ヘッダーに付与される。

例えば、銀行のサイトにログインすれば、ブラウザに銀行のサイトから発行された認証情報を含むCookieが付与されることとなる。

この状態で悪意のある不正なURLにアクセスすると、攻撃者(の作成したサイト)は、ブラウザに設定されたCookie情報(認証情報)を取得することができるため、ユーザーの認証情報を使用して、サイトに不正なリクエストを送信することができる。

CSRF対策

Cookieが悪用されるのは、上記で言うところの銀行のサイトのCookie管理が脆弱であった場合であり、発行するCookieにSameSite属性が設定されていれば、攻撃者のサイトはオリジン(URL)が異なるため、Cookieを取得することができない。

CSRF対策は上記の設定のみで防ぐことができるが、SameSite属性は古いブラウザでは機能しないことがある。そのため、サーバー側でCookieを発行する際にCSRF-TOKENを発行し、同一のトークンを持っているブラウザとしか通信しない、といった実装を行っていることが一般的である。

参考:クロスサイトリクエストフォージェリ (CSRF)

APIでのCSRF対策

Spring Securityの仕組みを使用して、WebSecurityConfig.javaを作成する。

参考:Spring Security クロスサイトリクエストフォージェリ (CSRF)

実装例:

■SecurityConfig.java

@Configuration
@EnableWebSecurity
public class SecurityConfig {
	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
		// ...
		.csrf((csrf) -> csrf
		.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())	// CookieのHttpOnly属性をfalseにする …※
		.exceptionHandling().accessDeniedHandler(new CsrfCustomHandler);	// CSRFチェックがNGだった場合のハンドラーを設定
		);
		return http.build();
	}
}

※ここで、CookieのHttpOnly属性をfalseにしないと、後述の、AngularでCookieの値を読み取る処理が動かないので、マストで設定する。

■CsrfCustomHandler.java ※CSRFエラーとなった場合の挙動をカスタマイズする

public class CsrfCustomHandler implements AccessDeniedHandler {
	@override
	public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
		// ロギング処理などあれば記載する
		system.out.println("csrf error");
		response.sendError(HttpStatus.FORBIDDEN.value(), HttpStatus.FORBIDDEN.getReasonPhrase());
	}
}

画面資源のCSRF対策

AngularではHttpClientにデフォルトで実装されており、Cookieに含まれるXSRF-TOKENは、HttpヘッダーのX-XSRF-TOKENとして自動で設定される。

参考:HttpClientのXSRF/CSRFセキュリティ

Cookieやヘッダーでのプロパティ名称をカスタムしたいときは、app.module.tsや、app.config.tsで、HttpClientXsrfModuleをインポートする。参考:HTTP client – Securit

Appendix

POSTMANでCSRFエラー

POSTMANなどでリクエスト送信する場合にCSRFエラーとなることがあるが、この場合は手作業でCookieに含まれるXSRF-TOKENをリクエストヘッダーのX-XSRF-TOKENとして詰め替える作業が必要になる。

前述の通り、Cookieからヘッダーへのトークンの詰め替えは、Angularが自動で行ってくれるが、POSTMANではこの処理を通過しないため、手動での対応が必要となる。

XSS(クロスサイトスクリプティング)との違い

XSSは、CSRF同様、攻撃者の用意したURLにユーザーがアクセスするところから始まる。

攻撃者は、事前に調べておいた脆弱性を持った既存のサービス(…①)のリンクに、悪意のあるスクリプトをパラメータとして付与したうえでユーザーに返却する。

ユーザーの端末でスクリプトが実行され、①のサービスの情報を外部に送信するなどの悪意のある操作が無意識に実行される。

スクリプトでなくても、単純に、攻撃者の用意した偽のパスワード画面に遷移させることで、情報を入力させるというような事例も考えられる。…②

参考

XSSの対策

上記②のケースは、アドレスバーや不自然なリダイレクトに注意していれば防げるが、①に関しては、既存のサービスに対してスクリプトが実行されるためユーザーは防ぎようがない。

①ではユーザーの不注意に加えて、サイト側の脆弱性という前提がある。

サイト側では、以下の対策が考えられる。

  • アプリケーションレイヤー:入力情報のデータは必ずサニタイズ(スクリプトに使用される特殊文字を、スクリプトではなく文字列として認識させる)する
  • インフラレイヤー:WAV(ファイアウォール)等でサニタイズする

コメント

タイトルとURLをコピーしました