前几天在帮后端排查一个cors的问题的时候发现的一些小坑特此记录json
**后端
cors的本质是出于安全缘由,浏览器限制从脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest和Fetch
API遵循同源策略。 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非使用CORS头文件。
跨域并不是必定是浏览器限制了跨站请求,也有多是跨站请求能够正常发起,可是返回结果被浏览器拦截了。最好的例子是 CSRF
跨站攻击原理,请求是发送到了后端服务器不管是否跨域!注意:有些浏览器不容许从 HTTPS 的域跨域访问 HTTP,好比 Chrome 和
Firefox,这些浏览器在请求还未发出的时候就会拦截请求。
**api
本case场景描述以下:
用户在a.com域名下跨域访问b.com域名下的api接口,使用了XMLHttpRequest的跨域头请求。域名b.com也容许了能够跨域 Access-Control-Allow-Origin 可是很奇怪在访问b.com的接口时有些api能访问成功,有些api访问失败。排查发现访问失败的api都是须要用户的登陆态的。可是用户已经在b.com登陆过了。把XMLHttpRequest请求换成jsonp请求则均可以请求成功(这好像是废话)。。。由此推测XMLHttpRequest 添加cors头的时候没有把b.com的 用户cookie信息带过去。跨域
翻看MDN文档https://developer.mozilla.org... 找到答案以下:浏览器
Fetch 与 CORS 的一个的特性是,能够基于 HTTP cookies 和 HTTP 认证信息发送身份凭证。通常而言,对于跨域 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。若是要发送凭证信息,须要设置 XMLHttpRequest 的某个特殊标志位。安全
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/credentialed-content/'; function callOtherDomain(){ if(invocation) { invocation.open('GET', url, true); invocation.withCredentials = true;//这个是重点 invocation.onreadystatechange = handler; invocation.send(); } }
将 XMLHttpRequest 的 withCredentials 标志设置为 true,从而向服务器发送 Cookies。服务器端的响应须要携带 Access-Control-Allow-Credentials: true ,浏览器才会把响应内容返回给请求的发送者。服务器
另外须要注意的是
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“”。 这是由于请求的首部中携带了 Cookie 信息,若是 Access-Control-Allow-Origin 的值为“”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。cookie
tips:
在跨域访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,若是要访问其余头,则须要服务器设置本响应头Access-Control-Expose-Headers 头让服务器把容许浏览器访问的头放入白名单,例如:cors
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
其余详细信息见个人博客jsonp