Spring Security - キャッシュコントロールヘッダ

Spring Security-キャッシュコントロールヘッダー

1. 前書き

この記事では、SpringSecurityを使用してHTTPキャッシングを制御する方法について説明します。

デフォルトの動作を示し、その背後にある理由についても説明します。 次に、この動作を部分的または完全に変更する方法を見ていきます。

2. デフォルトのキャッシュ動作

キャッシュコントロールヘッダーを効果的に使用することで、ブラウザーにリソースをキャッシュし、ネットワークホップを回避するよう指示できます。 これにより、待ち時間が短縮され、サーバーの負荷も軽減されます。

デフォルトでは、Spring Securityは特定のキャッシュ制御ヘッダー値を設定しますが、何も設定する必要はありません。

まず、アプリケーションのSpringSecurityを設定しましょう。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {}
}

何もしないようにconfigure()をオーバーライドします。これは、エンドポイントに到達するために認証される必要がないことを意味し、純粋にキャッシュのテストに集中できるようにします。

次に、簡単なRESTエンドポイントを実装しましょう。

@GetMapping("/default/users/{name}")
public ResponseEntity getUserWithDefaultCaching(@PathVariable String name) {
    return ResponseEntity.ok(new UserDto(name));
}

結果のcache-controlヘッダーは次のようになります。

[cache-control: no-cache, no-store, max-age=0, must-revalidate]

最後に、エンドポイントに到達するテストを実装し、応答で送信されるヘッダーをアサートしましょう。

given()
  .when()
  .get(getBaseUrl() + "/default/users/Michael")
  .then()
  .header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
  .header("Pragma", "no-cache");

基本的に、これが意味することは、ブラウザーがこの応答をキャッシュしないということです。

これは非効率に見えるかもしれませんが、実際にはこのデフォルトの動作には正当な理由があります–If one user logs out and another one logs in, we don’t want them to be able to see the previous users resources。 デフォルトでは何もキャッシュしない方がはるかに安全であり、キャッシュを明示的に有効にする責任は私たちにあります。

3. デフォルトのキャッシュ動作のオーバーライド

キャッシュしたいリソースを扱っている場合があります。 有効にする場合は、リソースごとに行うのが最も安全です。 これは、他のリソースはデフォルトではまだキャッシュされないことを意味します。

これを行うには、CacheControlキャッシュを使用して、単一のハンドラーメソッドでキャッシュ制御ヘッダーをオーバーライドしてみましょう。 CacheControlクラスは流暢なビルダーであり、さまざまなタイプのキャッシュを簡単に作成できます。

@GetMapping("/users/{name}")
public ResponseEntity getUser(@PathVariable String name) {
    return ResponseEntity.ok()
      .cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
      .body(new UserDto(name));
}

テストでこのエンドポイントに到達し、ヘッダーを変更したことを表明しましょう。

given()
  .when()
  .get(getBaseUrl() + "/users/Michael")
  .then()
  .header("Cache-Control", "max-age=60");

ご覧のとおり、デフォルトを上書きしました。これで、応答がブラウザによって60秒間キャッシュされます。

4. デフォルトのキャッシュ動作をオフにする

Spring Securityのデフォルトのキャッシュ制御ヘッダーを完全にオフにすることもできます。 これは非常に危険なことであり、推奨されません。 しかし、本当に必要な場合は、WebSecurityConfigurerAdapter:configureメソッドをオーバーライドして試すことができます。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.headers().disable();
}

それでは、エンドポイントにもう一度リクエストを送信して、どのような応答が得られるかを見てみましょう。

given()
  .when()
  .get(getBaseUrl() + "/default/users/Michael")
  .then()
  .headers(new HashMap());

ご覧のとおり、キャッシュヘッダーはまったく設定されていません。 繰り返しますが、this is not secure but proves how we can turn off the default headers if we want to.

7. 結論

この記事では、Spring SecurityがデフォルトでHTTPキャッシュを無効にする方法を示し、これはセキュアなリソースをキャッシュしたくないためであることを説明しています。 また、適切と思われる場合に、この動作を無効化または変更する方法も確認しました。

これらすべての例とコードスニペットの実装は、GitHub projectにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。