跨域问题

为什么会存在跨域问题

跨域问题的根本原因是:浏览器的同源策略

同源定义

如果两个URL的 protocol、port (en-US) (如果有指定的话)和 host 都相同的话,则这两个 URL同源。

企业微信截图_7b2ed3d8-3274-4bea-ab59-057f53fe5511.png

同源策略控制不同源之间的交互类型

  • 跨域写操作(Cross-origin writes)一般是被允许的。例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight。

  • 跨域资源嵌入(Cross-origin embedding)一般是被允许(后面会举例说明)。

1、<script src="..."></script> 标签嵌入跨域脚本。
语法错误信息只能被同源脚本中捕捉到。

2、<link rel="stylesheet" href="..."> 标签嵌入CSS。
由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的
HTTP 头部 Content-Type 。不同浏览器有不同的限制: 
IE, Firefox, Chrome, Safari (跳至CVE-2010-0051)部分和Opera。

3、通过 <img> 展示的图片。
支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...

4、通过 <video> 和 <audio> 播放的多媒体资源。

5、通过 <object>、 <embed> 和 <applet> 嵌入的插件。

6、通过 @font-face 引入的字体。
一些浏览器允许跨域字体( cross-origin fonts),
一些需要同源字体(same-origin fonts)。

7、通过 <iframe> 载入的任何资源。
站点可以使用 X-Frame-Options 消息头来阻止这种形式的跨域交互。
复制代码
  • 跨域读操作(Cross-origin reads)一般是不被允许的,但常可以通过内嵌资源来巧妙的进行读取访问。例如,你可以读取嵌入图片的高度和宽度,调用内嵌脚本的方法,或availability of an embedded resource.

同源策略的目的——安全

浏览器是从两个方面去做这个同源策略的,一是针对接口的请求,二是针对Dom的查询。

针对接口请求

举例:电商钓鱼网站

用户打开一个钓鱼网站,由于没有同源策略的限制,它可以向真正的电商网站发起请求。由于服务端验证通过后会在响应头加入Set-Cookie字段,然后下次再发请求的时候,浏览器会自动将cookie附加在HTTP请求的头字段Cookie中,这样一来,这个不法网站就相当于登录了你的账号,为所欲为。

针对Dom的查询

举例:银行钓鱼网站

// 真正银行的HTML
<iframe name="yinhang" src="https://juejin.cn/post/www.yinhang.com"></iframe>
// JS
// 如果没有同源策略的限制,钓鱼网站可以直接拿到别的网站的Dom
const iframe = window.frames['yinhang']
const node = iframe.document.getElementById('你输入账号密码的Input')

//如果打开了钓鱼网站,会泄露你的账号和密码
复制代码

同源策略确实能规避一些危险,但并不是说有了同源策略就绝对安全,只是说同源策略是一种浏览器最基本的安全机制,能提高一点攻击的成本。

如何跨域

JSONP

script、img这样的获取资源的标签是没有跨域限制的,可以利用这一点。但是JSONP只能发GET请求。

iframe+form

可以发post请求。

Cors

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)

CORS有两种请求,简单请求和非简单请求。

简单请求

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:
HEAD、GET、POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID

Content-Type:只限于三个值

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Nginx

请求的时候还是用前端的域名,Nginx帮我们把这个请求转发到真正的后端域名上,从而避免跨域。

Nginx配置:

server{
    # 监听9099端口
    listen 9099;
    # 域名是localhost
    server_name localhost;
    #凡是localhost:9099/api这个样子的,都转发到真正的服务端地址http://localhost:9871 
    location ^~ /api {
        proxy_pass http://localhost:9871;
    }    
}

复制代码

如果后端接口是一个公共的API,比如一些公共服务获取天气什么的,该方案不适用。

同源策略限制下Dom查询的正确打开方式

postMessage

window.postMessage() 是HTML5的一个接口,专注实现不同窗口不同页面的跨域通讯。

document.domain

这种方式只适合主域名相同,但子域名不同的iframe跨域。
比如主域名是crossdomain.com:9099,子域名是http://child.cros… = crossdomain.com就可以访问各自的window对象了。

canvas操作图片的跨域问题

解决canvas图片getImageData,toDataURL跨域问题

相关文章

不要再问我跨域的问题了

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享