7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

CORS を設定して別サイトのセッションを取得する

Last updated at Posted at 2021-07-08

Web アプリケーションを開発していて、別ドメインのログイン状態を取得する際に CORS の仕組みについて勉強することができたので、設定ポイントをまとめておきます。

CORS とは

Cross-Origin Resource Sharing の頭文字をとった略語です。
通常、ブラウザでは異なるサイトへのリソースへのアクセスに制限をかけて、CSRF などの攻撃を防いでいます。 CORS とは、この制限に対し、適切な設定を行うことで異なるサイトのリソースを共有できるようにするものです。

オリジンとは

ブラウザは、同じサイトか異なるサイトかについて、オリジン (Origin) という単位で区別します。
同一スキーム、同一ホストおよび同一ポートのものが同一オリジン (Same-Origin) となります。
同じホストでも、スキーム (http/https) やポートが違っていれば異なるオリジンとなります。

以下は https://www.example.com までが同じなので、同じオリジンとなります。

https://www.example.com/foo/
https://www.example.com/bar/

同じホスト名であっても以下はスキーム (http/https) が違うので、これらは異なるオリジンです。

http://www.example.com/foo/
https://www.example.com/foo/

同じオリジンであれば、とくに制限なくリソースの共有ができます。
異なるオリジンの場合は、CORS の適切な設定が必要となります。

やりたいこと

ブラウザでは事前にサイト A にログイン。サイト A のセッションクッキーを持ちます。
サイト B のページにおいて、Ajax によりサイト A のログイン状態を取得し、
ログインしていればログインユーザー名などを表示します。

それぞれのオリジンを以下とします。

サイト名 URL
サイト A https://site-a.example.com/
サイト B https://site-b.example.com/

cors-session.png

HTTP ヘッダーの設定

Access-Control-Allow-Origin

サイト A 側では、サイト B からのアクセスを許可するために、以下のヘッダーを出力するようにします。

Access-Control-Allow-Origin: https://site-b.example.com/

画像ファイルなどの通常のリソースは、この Access-Control-Allow-Origin ヘッダーによる Origin の許可ができていれば共有できます。

Access-Control-Allow-Credential

しかしながら、サイト間の Ajax呼び出しで HTTPクッキーや HTTP認証といった 資格情報 は、デフォルトでは送信されません。
資格情報の取得を許可するには、 以下のように Access-Control-Allow-Credential ヘッダーを入れる必要があります。

Access-Control-Allow-Credential: true

それから、資格情報の場合は、Access-Control-Allow-Origin: では * (アスタリスク)によるワイルドカードは使用できません。明示的に Origin を指定する必要があります。

具体的な設定だと、
Apache なら、

httpd.conf
Header set Access-Control-Allow-Origin https://site-b.example.com/
Header set Access-Control-Allow-Credentials true

nginx なら、こんな感じです。

nginx.conf
add_header Access-Control-Allow-Origin "https://site-b.example.com/";
add_header Access-Control-Allow-Credentials true;

セッションクッキーの設定

サイト A 側で発行するセッションクッキーの設定にも気を配る必要があります。
セキュアクッキーであること、 SameSite が None であることが必要です。

PHPの場合は、 session_set_cookie_params でセッションクッキーの設定を行ってから session_start します。
最近の PHP(7.3.0以上)であれば、SameSite の指定がオプションパラメータの配列で指定できます。

    session_set_cookie_params([
        'lifetime' => $maxlifetime,
        'domain' => $_SERVER['HTTP_HOST'],
        'path' => '/',
        'httponly' => $httponly,
        'secure' => true, // セキュアクッキーであること
        'samesite' => 'None' // SameSite が Noneであること
    ]);
    session_start();

7.3.0 未満の古い PHP の場合、ドメイン・パスの後ろにセミコロンで区切って、SameSite の指定を直接入れてやります。

    session_set_cookie_params($maxlifetime, '/; SameSite=None', '', true);
    session_start();

Ajaxの呼び出し

サイト B からサイト A の Ajax呼び出しを行うときにも withCredentials の設定が必要です。

サイト B の JavaScript

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://site-a.example.com/login_user', true);
xhr.withCredentials = true;
xhr.send(null);

jQuery ならこんな感じ。

$.ajax({
  url: "https://site-a.example.com/login_user",
  xhrFields: {
    withCredentials: true
  }
}).success(function(res){
  // 処理
})

仕組みが理解できても、設定ポイントがいくつかあるので、漏れのないように設定するのがたいへんです。
本記事を参考にチェックしてみてください。

参考

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?