同源策略
同源定义:协议+域名+端口号。同源表示三者均相等。
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询。
无同源策略的危害
- 接口请求:从其他网站发起请求从而导致的CSRF攻击。
- DOM查询:由于没有同源策略的限制,钓鱼网站可以直接拿到别的网站的Dom。从而更能轻易获取用户密码等隐私数据。
同源策略可以预防某些恶意行为,但实现合理的跨域请求对开发某些浏览器应用程序也是至关重要的。
跨域请求
JSONP
JSONP是JSON with padding(填充式 JSON 或参数式 JSON)的简写,JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。
1 | // 1. 客户端部分 |
其实JSONP也是需要服务端支持,服务端必须返回执行的代码,即Fn(param)
,所以一般后端使用cors机制处理跨域机制比较好。
空iframe+from
jsonp只能发送get请求,使用iframe+from可以发起post请求
1 | const iframePost = ({url, data}) => { |
缺点是获取请求返回的数据会遇到跨域DOM查询的问题
CORS
它允许浏览器向跨源服务器,发出
XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
简单请求与复杂请求
简单请求
- 请求方法是以下三种方法之一:
HEAD, GET POST
- HTTP的头信息不超出以下几种字段:
Accept, Accept-Language, Content-Language, Last-Event-ID, Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是
PUT
或DELETE
,或者Content-Type字段的类型是application/json
。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
“预检”请求用的请求方法是OPTIONS
,表示这个请求是用来询问的。头信息里面,关键字段是Origin
,表示请求来自哪个源。
服务器收到”预检”请求以后,检查了Origin、Access-Control-Request-Method和Access-Control-Request-Headers
字段以后,确认允许跨源请求,就可以做出回应。
实现一个CORS跨域请求
客户端发起ajax请求
默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。通过将withCredentials
属性设置为true
,可以指定某个请求应该发送凭据。如果服务器接受带凭据的请求,会用下面的HTTP头部来响应。Access-Control-Allow-Credentials:true
。
如果要发送Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie
也无法读取服务器域名下的Cookie。
客户端使用axios发起请求:
1 | axios({ |
服务器配置CORS
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin
就不能设为星号,必须指定明确的、与请求网页一致的域名。
1 | //服务器端设置响应头,各个服务器实现方法略有不同 |
以express为例:
1 | // allow custom header and CORS |
跨域DOM查询
postMessage
1 | window.postMessage() // 是HTML5的一个接口,专注实现不同窗口不同页面的跨域通讯。 |
参考文献
- Javascript高级程序编程第三版
- 跨域资源共享CORS详解–阮一峰
- 不要再问我跨域的问题了