CORS
同源策略
同源策略(Same-Origin Policy)是浏览器端独有的一套安全机制,当两个不同的源(即协议、域名、端口不同)进行通信时,同源策略会对此次通信做出不同程度的限制。它的主要目的是保护用户的数据不被恶意网站窃取。
定义
只有当两个 URL 具有相同的协议(scheme)、域名(host)和端口(port)时,它们才被认为是同源的。
影响
- XMLHttpRequest 和 Fetch:只能向同源的 URL 发送请求。
- DOM 访问:只能访问同源的页面 DOM。
- Cookie、LocalStorage 和 IndexedDB:只能在同源的上下文中访问。
- iframe 和嵌入:嵌入的内容如果不是同源的,访问受到限制。
使用 CORS 进行跨域
CORS(Cross-Origin Resource Sharing)是目前比较流行的一种绕过同源策略得机制;通过设置适当的 HTTP 响应头来允许来自特定源的请求。
原理:CORS 通过在 HTTP 请求和响应中包含一些特殊的头来工作,这些头使得服务器能够控制哪些源可以访问资源,允许的请求方法和头等。
请求头
Origin: 包含请求发起方的源(协议+域名+端口),用于告诉服务器请求来自哪个源。Access-Control-Request-Method:在预检请求中,用于告诉服务器将使用的 HTTP 方法(如 GET、POST 等)。Access-Control-Request-Headers:在预检请求中,用于告诉服务器将使用的自定义头。
响应头
Access-Control-Allow-Origin:指定允许访问资源的源。Access-Control-Allow-Methods:指定允许的 HTTP 方法。Access-Control-Allow-Headers:指定允许的自定义头。Access-Control-Allow-Credentials:指示是否可以在请求中使用凭据(如 Cookies 和 HTTP 认证信息)。Access-Control-Expose-Headers:允许浏览器访问的响应头。Access-Control-Max-Age:指定预检请求的结果可以缓存多长时间(秒)。
简单请求(Simple Request)
如果请求满足以下条件之一,浏览器会将其视为简单请求:
- 请求方法为
GET、POST、HEAD之一。 Content-Type为以下几个 MIME 类型之一:text/plain、multipart/form-data、application/x-www-form-urlencoded。- 不含自定义请求头,详情见 W3C。
若服务器允许该请求跨域,需要在响应头的 Access-Control-Allow-Origin 字段中包含该请求的 Origin ,如:
Access-Control-Allow-Origin: 客户端的 Origin预检请求(Preflight Request)
不符合简单请求的条件就是预检请求。此时浏览器会先向服务器发送一个 OPTIONS 预检请求,此次请求包含 Origin(源)、Access-Control-Request-Method(请求方法)、Access-Control-Request-Headers(请求头)。如:
OPTIONS /data HTTP/1.1
Origin: http://localhost:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-Custom-Header若服务器允许该 Origin 跨域,需要响应对应的字段,如:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8080
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600预检请求通过后,浏览器会发送实际请求。
注意事项
cookie
默认 AJAX 跨域时不会携带 cookie,若服务器需要获取请求的 cookie 就会得到空值,需在 XHR 或 Fetch 中进行配置。
// xhr
var xhr = new XMLHttpRequest()
xhr.withCredentials = true
// fetch
fetch(url, {
credentials: 'include',
})对于携带 cookie 的请求,服务器需要设置响应头 Access-Control-Allow-Credentials 为 true,否则此次跨域请求将会被拒绝。
设置允许客户端访问的响应头
AJAX 进行跨域时,客户端不能获取自定义的响应头,需要服务器设置 Access-Control-Expose-Headers 加入允许访问的响应头。
Access-Control-Expose-Headers: authorization, a, b