コンテンツにスキップ

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 APIHTML 文書)には原則としてアクセスできません。

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

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

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

ASP.NET Core Web API アプリケーションでは、 Program.csCORS に関するポリシーを設定します。 AlesInfiny Maris OSS Edition (以降、 AlesInfiny Maris )では、許可するオリジンの一覧をアプリケーション設定ファイル appSettings.json から取得します。

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

許可するオリジンの一覧をアプリケーション設定ファイル appSettings.json に記述します。

appSettings.json
1
2
3
4
5
"WebServerOptions": {
  "AllowedOrigins": [
    "https://frontend.example.com", "https://sub.frontend.example.com"
  ]
}

なお、開発時にのみ使用する設定は appSettings.Development.json に記述します。

appSettings.Development.json
1
2
3
4
5
"WebServerOptions": {
  "AllowedOrigins": [
    "https://dev.frontend.example.net"
  ]
}

構成オプション用クラスの追加⚓︎

appSettings.json の内容をコード上で扱いやすくするため、構成オプション用のクラスを作成します。クラス名、プロパティ名、プロパティの型は appSettings.json に追加した名称と一致させる必要があります。

1
2
3
4
5
6
7
public class WebServerOptions
{
    /// <summary>
    /// 許可するオリジンを取得または設定します。
    /// </summary>
    public string[] AllowedOrigins { get; set; } = [];
}

CORS ポリシーの設定⚓︎

ASP.NET Core Web API では、 CORS に関する設定を Program.cs 上で行う必要があります。builder.Services.AddCors メソッドで CORS を有効化し、 app.UseCors メソッドでポリシーを追加して CORS ミドルウェアを有効化します。

Program.cs
 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
var builder = WebApplication.CreateBuilder(args);

// アプリケーション設定ファイルから CORS の設定部分を取得し、サービスコンテナーに追加します。
// さらに DataAnnotation による検証を有効化します。
builder.Services
    .AddOptions<WebServerOptions>()
    .BindConfiguration(nameof(WebServerOptions))
    .ValidateDataAnnotations()
    .ValidateOnStart();

// CORS の使用を宣言します。
builder.Services.AddCors();

// 中略

var app = builder.Build();

// サービスコンテナーに追加したアプリケーション設定を取得します。
var options = app.Services.GetRequiredService<IOptions<WebServerOptions>>();

// アプリケーション設定ファイルにオリジンが記述されている場合のみ CORS ミドルウェアを有効化します。
if (options.Value.AllowedOrigins.Length > 0)
{
    app.UseCors(policy =>
    {
        policy
            .WithOrigins(options.Value.AllowedOrigins)
            .WithMethods("POST", "GET", "OPTIONS", "HEAD", "DELETE", "PUT")
            .AllowAnyHeader()
            .AllowCredentials()
            .WithExposedHeaders("Location");
    });
}

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

上のコード例「 Program.cs 」の 26-31 行目を以下に抜粋します。

1
2
3
4
5
6
policy
    .WithOrigins(options.Value.AllowedOrigins)
    .WithMethods("POST", "GET", "OPTIONS", "HEAD", "DELETE", "PUT")
    .AllowAnyHeader()
    .AllowCredentials()
    .WithExposedHeaders("Location");
WithOrigins メソッド

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

WithMethods メソッド

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

AllowAnyHeader メソッド

許可したオリジンのクライアントに任意の HTTP リクエストヘッダー使用を許可します。クライアントから送信される HTTP リクエストヘッダーを制限したい場合は代わりに WithHeaders メソッドを使用してください。

AllowCredentials メソッド

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

WithExposedHeaders メソッド

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

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

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

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

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

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

AlesInfiny Maris では 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 ( 11 行目)

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