コンテンツにスキップ

CORS 環境の構築⚓︎

CORS (オリジン間リソース共有)とは⚓︎

CORS とは、いくつかの HTTP ヘッダーを使用することで、同一オリジンポリシーの制限を回避する仕組みです。

オリジンとは

オリジンとは、 URL のスキーム(プロトコル)、ホスト(ドメイン)、ポート番号の部分を指します( Origin (オリジン) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN )。

  • http://localhosthttps://localhost はスキームが異なるので異なるオリジン
  • https://www.example.comhttps://www2.example.com はホスト部分が異なるので異なるオリジン
  • https://localhost:4431https://localhost:4432 はポート番号が異なるので異なるオリジン
同一オリジンポリシーとは

ブラウザーは原則として「同一オリジンポリシー」で動作します( 同一オリジンポリシー - ウェブセキュリティ | MDN )。

同一オリジンポリシーは重要なセキュリティの仕組みであり、あるオリジンによって読み込まれた文書やスクリプトが、他のオリジンにあるリソースにアクセスできる方法を制限するものです。

つまり、 https://aaa.example.com から取得したリソース( HTML 文書や JavaScript )から、 https://bbb.example.net のリソース( Web API や HTML 文書)には原則としてアクセスできません。

本章で解説する CORS 環境とは、 CSR アプリケーションにおいて、フロントエンドアプリケーションとバックエンドアプリケーションの配置されるサーバーのオリジンが異なる環境を意味します。 CORS 環境で CSR アプリケーションを構築する場合、いくつかの考慮や追加の実装が必要です。

CORS の仕組みの詳細は「 オリジン間リソース共有 (CORS) - HTTP | MDN 」を参照してください。

バックエンドアプリケーション( Spring Boot )⚓︎

Spring Boot アプリケーションでは、 SecurityFilterChain CORS に関するポリシーを設定します。 AlesInfiny Maia OSS Edition (以降『 AlesInfiny Maia 』)では、許可するオリジンの一覧をアプリケーション設定ファイル application.properties から取得します。

許可するオリジンの追加⚓︎

本番環境で許可するオリジンの一覧を Web 層のアプリケーション設定ファイル application-prd.properties に記述します。 許可するオリジンが複数ある場合には、 , で区切ります。

application-prd.properties
1
cors.allowed.origins=https://frontend.example.com,https://sub.frontend.example.com

なお、開発時にのみ使用する設定は、 application-dev.properties に記述します。

application-dev.properties
1
cors.allowed.origins=https://dev.frontend.example.com

許可するオリジンの読み込み⚓︎

まず、 CORS による設定を有効化するために、@EnableWebSecurity を記述します。 また、application.properties で許可したオリジンを読み込むために、 @Value を利用します。 なお、@Value 内で記述したプロパティ名は application.properties で設定した名称と一致させる必要があります。

WebSecurityConfig.java
1
2
3
4
5
6
7
8
9
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class WebSecurityConfig {

  @Value("${cors.allowed.origins:}")
  private String[] allowedOrigins;

  ...
}

プロパティ名の後に : を記述して空の配列を設定

@Value 内に記述したプロパティ名が application.properties に記述されていない場合、エラーが発生します。 AlesInfiny Maia のサンプルアプリケーションでは、プロパティ名の後に : を記述することで初期値に空の配列を設定し、エラーを回避しています。

CORS ポリシーの設定⚓︎

Spring Boot では、 CORS に関する設定を SecurityFilterChain を利用して実装します。

以下は、サンプルアプリケーションにおける CORS の設定を実現する WebSecurityConfig.java の実装例です。

SecurityFilterChainCORS 設定例
WebSecurityConfig.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
package com.dressca.web.consumer.security;

import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;

/**
 * セキュリティ関連の実行クラスです。
 */
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
public class WebSecurityConfig {

  @Value("${cors.allowed.origins:}")
  private String[] allowedOrigins;

  /**
   * CORS の設定をします。
   * 
   * @param http http リクエスト。
   * @return フィルターチェーン。
   * @throws Exception 例外。
   */
  @Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .securityMatcher("/api/**")
        // CSRF トークンを利用したリクエストの検証を無効化( OAuth2.0 による認証認可を利用する前提のため)
        // OAuth2.0 によるリクエストの検証を利用しない場合は、有効化して CSRF 対策を施す
        .csrf(csrf -> csrf.ignoringRequestMatchers("/api/**"))
        .cors(cors -> cors.configurationSource(request -> {
          CorsConfiguration conf = new CorsConfiguration();
          conf.setAllowCredentials(true);
          conf.setAllowedOrigins(Arrays.asList(allowedOrigins));
          conf.setAllowedMethods(List.of("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"));
          conf.setAllowedHeaders(List.of("*"));
          // 注文情報の確定にLocationを利用するため公開ヘッダーとして設定
          conf.addExposedHeader("Location");
          return conf;
        }));

    return http.build();
  }
}

CORS のポリシー設定についての詳細⚓︎

上のコード例「 WebSecurityConfig.java 」における CORS の設定に関するメソッドについて説明します。

  • setAllowCredentials メソッド

    許可したオリジンのクライアントに Cookie 等の認証情報を送信することを許可します。 アプリケーションで Cookie や認証を使用する場合、このメソッドの呼び出しが必要です。

  • setAllowedOrigins メソッド

    CORS でリソースへのアクセスを許可するオリジンを設定します。 AlesInfiny Maia ではアプリケーション設定ファイルから値を取得して引数に渡します。

  • setAllowedMethods メソッド

    許可したオリジンのクライアントが使用可能な HTTP メソッドを設定します。アプリケーションで許可する HTTP メソッド名を指定してください。なお、 CORS 環境の場合プリフライトリクエストが使用する OPTIONS は必須です。詳細は Preflight request (プリフライトリクエスト) - MDN Web Docs 用語集: ウェブ関連用語の定義 | MDN を参照してください。

  • setAllowedHeaders メソッド

    許可したオリジンのクライアントに許可する HTTP リクエストヘッダーを設定します。

  • addExposedHeader メソッド

    許可したオリジンのクライアントに対して公開する必要がある HTTP レスポンスヘッダーを設定します。 アプリケーションで許可する HTTP レスポンスヘッダー名を指定してください。 addExposedHeader メソッドで設定していないレスポンスヘッダーはクライアントに公開されません。

Cookie を使用する場合の注意事項

CORS 環境においてアプリケーションで Cookie を使用する場合、 SameSite 属性に None を明示的に指定する必要があります。設定しない場合、別オリジンへ Cookie を送信できません。 なお、 Cookie の仕様上 SameSite 属性に None を設定する場合は必ず Secure 属性も設定する必要があります( HTTP Cookie の使用 - HTTP | MDN )。

Cookie に SameSite=None が付いた場合は、 Secure 属性も指定することになりました(安全なコンテキストが必要になりました)。

実装方法については、Cookie の設定 を参照してください。

フロントエンドアプリケーション( Vue.js )⚓︎

Web API 呼び出し時の HTTP ヘッダーの設定⚓︎

AlesInfiny Maia では Web API 呼び出しの共通処理用に ./src/api-client/index.ts という設定ファイルを作成する( 参照 )ので、ここで HTTP ヘッダーを設定します。

index.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import axios from 'axios';
import * as apiClient from '@/generated/api-client';

// (中略)

/** axios の共通の設定があればここに定義します。 */
const axiosInstance = axios.create({
  headers: {
    'Content-Type': 'application/json',
  },
  withCredentials: true,
});

const exampleApi = new apiClient.ExampleApi(createConfig(), '', axiosInstance);

export { exampleApi };

withCredentials: true

CORS 環境でのリクエストが Cookie 、認証ヘッダー、 TLS クライアント証明書などの資格情報を使用して行われるべきかを示します。既定値は false なので、 true を明示的に設定します。