什么是跨域?

简介: 什么是跨域?

什么是跨域?


1.什么是同源策略及其限制内容?

同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。


同源策略限制内容有:


Cookie、LocalStorage、IndexedDB 等存储性内容

DOM 节点

AJAX 请求发送后,结果被浏览器拦截了

但是有三个标签是允许跨域加载资源:


2.常见跨域场景

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。


特别说明两点:

第一:如果是协议和端口造成的跨域问题“前台”是无能为力的。

第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。


跨域有哪些方案?

这里只介绍几种开发中用的比较多的,几乎用不到的比如:


document.domain + iframe:适用主域名相同,子域名不同的跨域场景

window.name + iframe:利用name值最长可以 2M ,并用不同页面或不同域名加载后依然存在的特性

location.hash + iframe:适用通过 C 页面来实现 A 页面与 B 页面通信的场景

就不过多展开了


CORS

CORS 通信过程都是浏览器自动完成,需要浏览器(都支持)和服务器都支持,所以关键在只要服务器支持,就可以跨域通信,CORS请求分两类,简单请求和非简单请求

另外CORS请求默认不包含Cookie以及HTTP认证信息,如果需要包含Cookie,需要满足几个条件:


服务器指定了 Access-Control-Allow-Credentials: true

开发者须在请求中打开withCredentials属性: xhr.withCredentials = true

Access-Control-Allow-Origin不要设为星号,指定明确的与请求网页一致的域名,这样就不会把其他域名的Cookie上传


简单请求

需要同时满足两个条件,就属于简单请求:


请求方法是:HEAD、GET、POST,三者之一

请求头信息不超过以下几个字段:


Accept

Accept-Language

Content-Language

Last-Event-Id


Content-Type:值为三者之一application/x-www/form/urlencoded、multipart/form-data、text/plain

需要这些条件是为了兼容表单,因为历史上表单一直可以跨域


浏览器直接发出CORS请求,具体来说就是在头信息中增加Origin字段,表示请求来源来自哪个域(协议+域名+端口),服务器根据这个值决定是否同意请求。如果同意,返回的响应会多出以下响应头信息


Access-Control-Allow-Origin: http://juejin.com // 和 Orign 一致 这个字段是必须的

Access-Control-Allow-Credentials: true // 表示是否允许发送 Cookie 这个字段是可选的

Access-Control-Expose-Headers: FooBar // 指定返回其他字段的值 这个字段是可选的

Content-Type: text/html; charset=utf-8 // 表示文档类型

在简单请求中服务器至少需要设置:Access-Control-Allow-Origin 字段


非简单请求

比如 PUT 或 DELETE 请求,或 Content-Type 为 application/json ,就是非简单请求。


非简单 CORS 请求,正式请求前会发一次 OPTIONS 类型的查询请求,称为预检请求,询问服务器是否支持网页所在域名的请求,以及可以使用哪些头信息字段。只有收到肯定的答复,才会发起正式XMLHttpRequest请求,否则报错


预检请求的方法是OPTIONS,它的头信息中有几个字段


Origin: 表示请求来自哪个域,这个字段是必须的

Access-Control-Request-Method:列出CORS请求会用到哪些HTTP方法,这个字段是必须的

Access-Control-Request-Headers: 指定CORS请求会额外发送的头信息字段,用逗号隔开

OPTIONS请求次数过多也会损耗性能,所以要尽量减少OPTIONS请求,可以让服务器在请求返回头部添加


Access-Control-Max-Age: Number // 数字 单位是秒

表示预检请求的返回结果可以被缓存多久,在这个时间范围内再请求就不需要预检了。不过这个缓存只对完全一样的URL才会生效


2. Nginx代理跨域

配置一个代理服务器向服务器请求,再将数据返回给客户端,实质和CORS跨域原理一样,需要配置请求响应头Access-Control-Allow-Origin等字段


server { 
listen81; server_namewww.domain1.com; 
location/ { 
proxy_passhttp://xxxx1:8080; // 反向代理 proxy_cookie_domainwww.xxxx1.comwww.xxxx2.com; // 修改cookie里域名 indexindex.htmlindex.htm; 
// 当用webpack-dev-server等中间件代理接口访问nignx时,此时无浏览器参与,故没有同源限制,下面的跨域配置可不启用 add_headerAccess-Control-Allow-Originhttp://www.xxxx2.com; // 当前端只跨域不带cookie时,可为* add_headerAccess-Control-Allow-Credentialstrue; 
    } 
}


3. Node中间件代理跨域

在 Vue 中 vue.config.js 中配置


module.export= {
    ...
devServer: {
proxy: {
            [ process.env.VUE_APP_BASE_API ]: {
target: \'http://xxxx\',//代理跨域目标接口ws: true,
changeOrigin: true,
pathRewrite: {
                    [ \'^\' + process.env.VUE_APP_BASE_API ] : \'\'                }
            }
        }
    }
}
Node+expressconstexpress=require(\'express\')constproxy=require(\'http-proxy-middleware\')constapp=express()
app.use(\'/\', proxy({ // 代理跨域目标接口 target: \'http://xxxx:8080\', changeOrigin: true, 
// 修改响应头信息,实现跨域并允许带cookie onProxyRes: function(proxyRes, req, res) { 
res.header(\'Access-Control-Allow-Origin\', \'http://xxxx\')res.header(\'Access-Control-Allow-Credentials\', \'true\')    }, 
// 修改响应信息中的cookie域名 cookieDomainRewrite: \'www.domain1.com\' // 可以为false,表示不修改})); 
app.listen(3000);



4. WebSocket

WebSocket是HTML5标准中的一种通信协议,以ws://(非加密)和wss://(加密)作为协议前缀,该协议不实行同源政策,只要服务器支持就行


因为WebSocket请求头信息中有Origin字段,表示请求源来自哪个域,服务器可以根据这个字段判断是否允许本次通信,如果在白名单内,就可以通信


5. postMessage

postMessage是HTML5标准中的API,它可以给我们解决如下问题:


页面和新打开的窗口间数据传递

多窗口之间数据传递

页面与嵌套的 iframe 之间数据传递

上面三个场景之间的跨域传递

postMessage 接受两个参数,用法如下:


参数一:发送的数据

参数二:你要发送给谁就写谁的地址(协议 + 域名 +端口),也可以设置为*,表示任意窗口,为/表示与当前窗口同源的窗口


6. JSONP

原理就是通过添加一个


不过只支持GET请求且不安全,可能遇到XSS攻击,不过它的好处是可以向老浏览器或不支持CORS的网站请求数据


letscript=document.createElement('script')
script.type='text/javascript'script.src='http://juejin.com/xxx?callback=handleCallback'document.body.appendChild(script)
functionhandleCallback(res){
console.log(res)
}


服务器返回并立即执行

handleCallback({ code: 200, msg: ‘success’, data: [] })

跨域时 Cookie 要做何处理?

指的就是对第三方使用 Cookie 的设置,在 Cookie 信息中添加 SameSite 属性


Set-Cookie: widget_session=123456; SameSite=None; Secure

SameSite 有三个值:


strict:严格模式,完全禁止使用Cookie

lax:宽松模式,允许部分情况使用Cookie,跨域的都行,a标签跳转,link标签,GET提交的表单

none:任何情况下都会发送Cookie,但必须同时设置Secure属性,意思是需要安全上下文,Cookie 只能通过https发送,否则无效

Chrome 80之前默认值是none,之后是lax


不过在最新的 Chrome91 版本中这个已经被移除了,所以在 91之前的版本依然可以使用


如果 Chrome 或 Edge 版本大于91小于94的话,可以通过Chromium支持的command-line flag

右键 Chrome 或 Edge 浏览器,选择属性

在目标(Target)属性末尾加上


--disable-features=SameSiteByDefaultCookies,CookiesWithoutSameSiteMustBeSecure


并且官方说的到 94 版本会连 comman-line 也会移除

相关实践学习
基于函数计算快速搭建Hexo博客系统
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
2月前
“跨域”问题理解
“跨域”问题理解
14 0
|
7天前
|
安全
什么是跨域?
什么是跨域?
|
2月前
|
Web App开发 JavaScript 开发者
|
3月前
|
JSON 缓存 前端开发
什么是跨域
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
|
3月前
|
安全
什么是跨域,为什么会跨域?
什么是跨域,为什么会跨域?
76 1
|
4月前
|
Web App开发 前端开发 JavaScript
你能讲一下跨域吗
你能讲一下跨域吗
|
4月前
|
JSON 前端开发 安全
你了解跨域吗
你了解跨域吗
33 0
|
9月前
CorsConfig 跨域 初认识
CorsConfig 跨域 初认识
120 0
|
10月前
|
安全 应用服务中间件 nginx
跨域 #29
跨域 #29
53 0
|
移动开发 网络协议 中间件
三种跨域是这样的
《基础系列》
127 0