コンテンツにスキップ

Cookie の設定⚓︎

HTTP Cookie の仕様 - MDN Web Docs より Cookie の定義を以下に引用します。

Cookie(ウェブ Cookie、ブラウザー Cookie とも呼ぶ)は、サーバーがユーザーのウェブブラウザーに送信する小さなデータです。ブラウザーは Cookie を保存したり、新しい Cookie を作成したり、既存の Cookie を変更したり、後でリクエストされたときに同じサーバーにそれらを送り返したりすることができます。 Cookie により、ウェブアプリケーションは限られた量のデータを格納し、状態についての情報を記憶することができます。

Cookie を使用する際には、 CSRF 攻撃のような脆弱性を悪用した脅威に対しアプリケーション側で対策を施す必要があります。 AlesInfiny Maia OSS Edition での CSRF 攻撃への対策の方針については、こちら を参照してください。

本章では、上記方針に基づき Cookie を利用する場合の設定方法について解説します。

バックエンドアプリケーションの設定⚓︎

本章では、サンプルアプリケーションにて実装している、購入者 ID を Cookie へ付与する機能を設定例として解説します。

まず、 Cookie に付与する属性を application.properties に定義します。 以下は、クロスオリジンの場合の方針に基づき SecureHttpOnlySameSite = None を定義する例です。

Cookie の属性の設定を定義する application.properties の設定例
application.properties
1
2
3
4
# Cookie の設定
cookie.settings.same-site=None
cookie.settings.http-only=true
cookie.settings.secure=true

その後、 @ConfigurationProperties を利用して application.properties に記述した Cookie の設定値を読み込みます。 各フィールドには初期値が設定されていますが、 application.properties に記述された設定が優先されます。

Cookie の設定値を保持する CookieSettings.java
CookieSettings.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package com.dressca.web.consumer.security;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;

/**
 * Cookie の設定を格納するクラスです。
 */
@Component
@ConfigurationProperties(prefix = "cookie.settings")
@Data
public class CookieSettings {
  private String sameSite = "Strict";
  private boolean httpOnly = true;
  private boolean secure = false;
  private int expiredDays = 1;
}

次に、 Spring Boot で提供されている ResponseCookie を利用して Cookie に設定値を反映させます。

具体的には、以下のように設定した Cookie の情報(購入者 ID )と設定値を Set-Cookie のヘッダーに付与するフィルターを実装します。

ResponseCookie を利用したサンプルアプリケーションの実装例
BuyerIdFilter.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.dressca.web.consumer.filter;

import java.io.IOException;
import java.util.UUID;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import com.dressca.web.consumer.security.CookieSettings;

/**
 * 購入者 ID にフィルターをかけるクラスです。
 */
@AllArgsConstructor
public class BuyerIdFilter implements Filter {

  private static final String DEFAULT_BUYER_COOKIE_NAME = "Dressca-Bid";
  private static final String BUYER_ID_ATTRIBUTE_KEY = "buyerId";
  private final CookieSettings cookieSettings;

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {

    Cookie[] cookies = ((HttpServletRequest) request).getCookies();
    String buyerId = null;
    if (cookies != null) {
      for (Cookie cookie : cookies) {
        if (cookie.getName().equals(DEFAULT_BUYER_COOKIE_NAME)) {
          buyerId = cookie.getValue();
        }
      }
    }
    if (StringUtils.isBlank(buyerId)) {
      buyerId = UUID.randomUUID().toString();
    }
    request.setAttribute(BUYER_ID_ATTRIBUTE_KEY, buyerId);

    chain.doFilter(request, response);
    buyerId = request.getAttribute(BUYER_ID_ATTRIBUTE_KEY).toString();
    ResponseCookie responseCookie = ResponseCookie.from(DEFAULT_BUYER_COOKIE_NAME, buyerId)
        .path("/")
        .httpOnly(cookieSettings.isHttpOnly())
        .secure(cookieSettings.isSecure())
        .maxAge((long) cookieSettings.getExpiredDays() * 60 * 60 * 24)
        .sameSite(cookieSettings.getSameSite()).build();
    ((HttpServletResponse) response).addHeader(HttpHeaders.SET_COOKIE, responseCookie.toString());
  }
}

最後に、上記で実装したフィルターを Bean 登録します。

Cookie の設定を設定するフィルタークラスである DresscaWebConfig.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.dressca.web.consumer.config;

import com.dressca.web.consumer.filter.BuyerIdFilter;
import com.dressca.web.consumer.security.CookieSettings;
import jakarta.servlet.Filter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Dressca Web 用の設定クラスです。
 */
@Configuration
public class DresscaWebConfig {

  @Autowired
  private CookieSettings cookieSettings;

  /**
   * 購入者 ID のフィルターを設定します。
   * 
   * @return 購入者 ID のフィルター。
   */
  @Bean
  public FilterRegistrationBean<Filter> buyerIdFilter() {
    FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
    bean.setFilter(new BuyerIdFilter(this.cookieSettings));
    return bean;
  }
}

これにより、 Cookie に CSRF 対策を施すことができます。

フロントエンドアプリケーションの設定⚓︎

クロスオリジンの環境の場合、フロントエンドアプリケーションでは、リクエスト発行時に Cookie をヘッダーに含めることを許可する設定が必要となります。 実装例は CORS 環境の構築 を参照してください。