跨源资源共享和Cookie问题整理
浏览器的同源策略 = 协议 + 域名 + 端口相同
1. 跨源资源共享 CROS
简单请求不会触发CROS预检请求。
预检请求(非简单请求)使用OPTIONS发送一个预检请求到服务器。
预检请求不能包含凭据。预检请求的 响应 必须指定 Access-Control-Allow-Credentials: true
来表明可以携带凭据进行实际的请求。
在响应附带身份凭证的请求时:
- 服务器不能将
Access-Control-Allow-Origin
的值设为通配符“*
”,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://example.com
。 - 服务器不能将
Access-Control-Allow-Headers
的值设为通配符“*
”,而应将其设置为首部名称的列表,如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
- 服务器不能将
Access-Control-Allow-Methods
的值设为通配符“*
”,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers
和Access-Control-Allow-Methods
用于预检请求。
Access-Control-Expose-Headers
头让服务器把允许浏览器访问的头放入白名单
对于附带身份凭证的请求(通常是 Cookie
),服务器不得设置 Access-Control-Allow-Origin
的值为“*
”。
Nginx配置OPTIONS
if ($request_method ~* "OPTIONS"){
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'User-Agent,Keep-Alive,Content-Type';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
return 204;
}
PHP服务端
header('Access-Control-Allow-Origin:' . $origin);
header('Access-Control-Allow-Credentials:true');
//预检请求由nginx处理,实际请求只需要返回以上两项
//header('Access-Control-Allow-Headers:Origin, Content-Type, Cookie, X-CSRF-TOKEN, Accept, Authorization, X-XSRF-TOKEN');
//header('Access-Control-Allow-Methods:GET, POST, PATCH, PUT, OPTIONS');
laravel框架使用 fruitcake/laravel-cors中间件,预检请求和实际请求由中间件处理。
config/cors.php配置
<?php
return [
/*
|--------------------------------------------------------------------------
| Laravel CORS Options
|--------------------------------------------------------------------------
|
| The allowed_methods and allowed_headers options are case-insensitive.
|
| You don't need to provide both allowed_origins and allowed_origins_patterns.
| If one of the strings passed matches, it is considered a valid origin.
|
| If ['*'] is provided to allowed_methods, allowed_origins or allowed_headers
| all methods / origins / headers are allowed.
|
*/
/*
* You can enable CORS for 1 or multiple paths.
* Example: ['api/*']
*/
'paths' => ['api/*'],
/*
* Matches the request method. `['*']` allows all methods.
*/
'allowed_methods' => ['*'],
/*
* Matches the request origin. `['*']` allows all origins. Wildcards can be used, eg `*.mydomain.com`
*/
'allowed_origins' => ['*.gophper.com','*.gophper.com:8080','http://localhost:8080'],
/*
* Patterns that can be used with `preg_match` to match the origin.
*/
'allowed_origins_patterns' => [],
/*
* Sets the Access-Control-Allow-Headers response header. `['*']` allows all headers.
*/
'allowed_headers' => ["*"],
/*
* Sets the Access-Control-Expose-Headers response header with these headers.
*/
'exposed_headers' => [],
/*
* Sets the Access-Control-Max-Age response header when > 0.
*/
'max_age' => 0,
/*
* Sets the Access-Control-Allow-Credentials header.
*/
'supports_credentials' => true,
];
2. Cookie
Cookie 策略受 SameSite 属性控制,限制第三方Cookie。大多数浏览器设置Lax为默认值。
http://a.dev.gophper.com:8080
访问 http://b.dev.gophper.com
接口,可以设置Cookie。
http://a.dev.gophper.com:8080 访问 https://b.dev.gophper.com接口,不可以设置Cookie。
协议相同,主域名相同,端口允许不同。
Cookie的作用域仅仅由domain和path决定,与协议和端口无关。
3. 参考
https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Expose-Headers https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Set-Cookie/SameSite