この記事はMichael Okokoがこちらで公開した記事(英語)を日本語化したものです。
ウェブブラウザはデフォルトで同一オリジンポリシーを実装しており、スクリプトが異なるドメイン間でHTTPリクエストを行うことを防ぎます。 Cross-Origin Resource Sharing(CORS)は、自オリジンとは異なるオリジンからのリクエストを許可するか、または制限するかについて、ブラウザとサーバーサイドアプリケーション間で同意形成を行うためのメカニズムを提供します。
バージョン7から、Laravelフレームワークは、Middlewareを使用してCORSヘッダーを送信するためのファーストパーティサポートを備えています。
このチュートリアルでは、Laravelを使用したシンプルなVue.jsアプリを作成し、CORSについて学びます。CORS OPTIONSリクエストを処理するためにLaravelが必要とする様々な設定オプションを深く掘り下げ、これらのオプションがアプリケーションにどのような影響を与えるかをご紹介します。
必要なもの
このチュートリアルを完了するためには、以下の項目を満たしている必要があります。
- Laravelフレームワークに精通していること。
- Laravelフレームワークのバージョンが7.0以上のプロジェクトが手元にあること。
- Vue CLIがインストール済であること。
はじめに
Laravel APIとVueプロジェクトの両方を格納する新しいフォルダを作成し、Laravelプロジェクトを作成します。以下のコマンドを実行してください。
$ mkdir laravel-cors && cd laravel-cors
$ laravel new server
作成されたLaravelプロジェクトには、アプリケーションのニーズに合わせて微調整できる汎用的なCORS設定が$APP_FOLDER/config/cors.php
に含まれています。以下のコードは、新しいLaravelアプリケーション用に生成された設定ファイルのサンプルです(コメントは含まれていません)。
<?php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
VueのフロントエンドからAPIのレスポンスヘッダーを確認するには、以下のように`exposed_headers`配列を変更し、ワイルドカード文字を格納させます。
'exposed_headers' => ['*'],
次に、ダミーデータでリクエストに応答するようにAPIルートを設定します。routes/api.php
ファイルを開き、その内容を以下のコードブロックで置き換えます。
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('/items', function(Request $request) {
$data = [
[
"id" => 7,
"name" => "na like this",
"description" => "",
"created_at" => "2020-07-26T05:53:00.376501Z",
"updated_at" => "2020-07-26T05:53:00.376501Z"
], [
"id" => 5,
"name" => "write a book",
"description" => "hohoho",
"created_at" => "2020-07-26T05:47:00.908706Z",
"updated_at" => "2020-07-26T05:53:00.376501Z"
]
];
return response()->json($data);
});
Route::get('/items/{id}', function(Request $request) {
$data = [
'id' => 1,
'name' => "Swim across the River Benue",
'description' => "ho ho ho",
'created_at' => "2020-07-26T22:31:04.49683Z",
'updated_at' => "2020-07-26T22:31:04.49683Z"
];
return response()->json($data);
});
Route::post('/items', function(Request $request) {
$data = [
'id' => 1,
'name' => "Swim across the River Benue",
'description' => "ho ho ho",
'created_at' => "2020-07-26T22:31:04.49683Z",
'updated_at' => "2020-07-26T22:31:04.49683Z"
];
return response()->json($data, 201);
});
Vueフロントエンドの設定
laravel-cors
フォルダ内でvue create frontend
を実行して、Vueプロジェクトを作成してください。プリセットの設定を促されるので、デフォルトのオプションを選択してください。作成されたフロントエンドのフォルダー内で、HelloWorld.vue
(パス:src/components/HelloWorld.vue
)を開き、内容を以下のコードブロックに置き換えます。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>Open your Browser console to see the headers sent in by Laravel.</p>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
mounted() {
let req = new Request("http://localhost:8000/api/items", {
method: "get",
});
fetch(req).then((response) => {
for (let pair of response.headers.entries()) {
console.log(pair[0] + ": " + pair[1]);
}
});
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
上記のコードにより、Laravelアプリケーションで作成したAPIルートである/items
にHTTPリクエストを行い、受信したすべてのレスポンスヘッダーを記録します。
試しに、ターミナルからサーバーフォルダ内でphp artisan serve
を実行して、Laravelアプリケーションを動かしてみましょう。
サーバーを稼働させたら、フロントエンドディレクトリに移動して、yarn serve
を実行し、Vueアプリを起動してください。
yarn serve
を実行した際に表示されたローカルURLにブラウザでアクセスし、ページコンソールを開いてください。
以下のスクリーンショットのように、コンソールにレスポンスヘッダーが表示されます。
ルートプレフィックスのCORSを有効にする
pathsオプションでは、CORSヘッダーを送信するルートやリソースのパスを指定します。上記の設定では、「api」というプレフィックスを持つすべてのルートに対してCORSヘッダーが有効になっています。このプレフィックスを削除したり、別のものに変更したりすると(例:‘paths’ => [’endpoints/*’])、APIエンドポイントのCORSが無効になり、以下のようなエラーが発生します。
パスは、文字列の完全一致(例:/public/img/photo.img
) または、ワイルドカード(例:/public/*
または/api/*
)を使って指定します。さらに、public/**/*
を使用して、指定されたフォルダとそのサブフォルダのすべてのファイルに対してCORSを有効にすることができます。
許可されたHTTPメソッドを検索する
allowed_methods
は、リソースにアクセスする際に許可されるHTTPリクエストメソッドを指定します。ここで追加したメソッドは、クライアントがLaravelアプリケーションにPreflight request(プリフライトリクエスト)を行う際に、“Allowed-Methods”ヘッダーで返されます。Laravelはデフォルトで*
の値を使用してすべてのHTTPメソッドに対してCORSを有効にします。
たとえば、allowed_methods
に含まれるワイルドカード*
をPOST
に置き換えると、サーバーにGET
リクエストを送信しているためフロントエンドのコードが壊れてしまいます。
許可されたホストを制限する
allowed_origins
は、リソースへのアクセスを許可する「origins」を指定します(ここでいう「origins」とは、URLのスキーム、ドメイン、ポートの組み合わせを指します)。上記のオプションと同様に、ワイルドカードによるマッチングも可能です(例:*example.com
は、example.comおよびそのいずれのサブドメインに対しリソースへのアクセスを許可します)。デフォルトでは、すべてのオリジンを許可するように設定されています。
注: ワイルドカードを使用しない場合は、オリジンを全文で指定する必要があります(例:http://example.comは有効、example.comは無効)
正規表現を使って許可されたホストを制限する
allowed_origins_patterns
オプションを使うと、正規表現を使って許可されるオリジンを指定することができます。 allowed_origins
でサポートされているワイルドカード*
よりも複雑なマッチパターンが必要な場合に便利です。ここで指定する値は、有効なpreg_match()パターンでなければなりません。また、誤って正規表現が包括的になってしまわないように注意してください。たとえば、/https?:\/\/example\.com/
はhttps://example.comもhttps://example.com.hackersdomain.comにもマッチします。より良いパターンは、/https?:\/\/example\.com\/?\z/
で、example.comで終わるドメイン(最後にスラッシュがある場合も含む)に限定されます。
許可されたヘッダーを設定する
allowed_headers
オプションは、実際のCORSリクエストで許可されるHTTPヘッダーを定義します。この定義により設定されるAccess-Control-Allow-Headersは、Access-Control-Request-Headersを含むプリフライトリクエストに対する応答として送信されるsヘッダーです。デフォルトの設定ではすべてのHTTPヘッダーを許可するようになっています。
カスタムヘッダーを公開する
Excposed_headers
を使用すると、CORSによってデフォルトでsafe-listed(セーフリスト)されていないカスタムHTTPヘッダーに、APIクライアントがアクセスできるようになります。たとえば、LaravelのThrottle middlewareによって設定されるX-RateLimit-Remaining
とX-RateLimit-Limit
ヘッダーを公開し、与えられた時間内にあと何回クライアントがリクエストを実行できるかを示したい時などに使用できます。
CORSでセーフリストに登録されているHTTPヘッダーは7つしかないので(Cache-Control、Content-Language、Content-Length、Content-Type、Expires、Last-Modified、Pragma)、アプリケーションが公開しなければならないその他のヘッダーは、exposed_headers
に含める必要があります。
CORSレスポンスのキャッシュ
max_age
オプションの値は、クライアントがプリフライトリクエストのレスポンスをキャッシュできる期間(秒)を指定します。Laravelではデフォルトで0に設定されています。ブラウザ指定の最大期間よりも長い場合、max_age
は無視されます(Firefoxでは24時間、Chromium v76以上では2時間)。
CORSによるHTTPセッション
supports_credentials
を使用すると、Access-Control-Allow-Credentials
を設定し、CORSリクエストでCookieやCookieに依存するセッションの送信を許可できます。ただし、すべてのオリジンが許可されている場合(つまり、allowed_origins
がワイルドカード(*
)文字の場合)、Access-Control-Allow-Credentials
の設定はtrueにはなりません。
まとめ
CORSの設定は時に面倒なものです。Laravelでは、laravel-corsパッケージを利用することで、即時使用可能な設定を簡単に行うことができます。
CORSに関する一般的な知識を習得したい場合は、以下を参照してみてはいかがでしょうか。
- ブログ記事「On Web-Security and -Insecurity」は、CORSの設定ミスにまつわるセキュリティ上の問題点を明らかにしています。
- MDN docsには、CORSと、関連するHTTPヘッダーに関するページがあります。
Michael Okokoは、ナイジェリアのObafemi Awolowo大学に通うソフトウェアエンジニア兼コンピュータサイエンスの学生です。彼はオープンソースが大好きで、主にLinux、Golang、PHP、そしてファンタジー小説に興味があります。連絡先は以下の通りです:。
- Email: michaelsokoko@gmail.com
- Github: https://github.com/idoqo
- Twitter: https://twitter.com/firechael

In diesem Tutorial zeige ich, wie Sie mit der Twilio-API WhatsApp-Benachrichtigungen in Ihre Laravel-App implementieren können.

PHPアプリケーションでの環境変数の設定や取得をするための方法をご紹介します。

TwilioのProgrammable SMSとLaravelを使用してSMS通知ポータル(管理画面)を作成する方法をご紹介します。

In this, the second part in the series, you'll learn how to use Memcached with PHP to improve the application's performance.

Learn how to create a small weather station with a Raspberry Pi, PHP, Python, and DHT11 sensor, for under $100.00.

In this tutorial, you'll learn how to create and host a high-converting sales page, using PHP, Twilio Messaging, Google App Engine, and Stripe.