前端跨域问题解决方案

188 阅读5分钟

同源和跨域

同源

  • 同源策略是 浏览器核心的基础安全策略 防止非法攻击(CSRF)
  • 同源策略的限制:

通过同源策略限制一个资源地址加载的文档或脚本与来自另一个资源地址的资源进行交互。

1、Cookie、LocalStorage、IndexedDB(浏览器数据库)等存储性内容

2、不允许进行DOM节点的操作

3、不能进行AJAX请求

跨域传输

  • 跨域 非同源策略请求

发起请求的域和该请求指向的资源所在的域不一致(协议域名端口不同)

跨域的危害

  1. 防止非法攻击(CSRF 跨站点请求伪造)

clipboard.png

  1. 防止读取或篡改信息
  • 部署到同一个web服务器上: 同源
  • 前后端分离的情况下使用nginx反向代理

跨域解决方案

  1. 修改浏览器安全设置(不推荐) blog.csdn.net/fhr9998/art…
  2. JSONP
  3. 跨域资源共享CORS
  4. iframe
  5. 代理
  6. window.postMessage
  7. WebSocket(但是只支持GET请求并且无法得到返回结果)

jsonp

script,img,link,iframe不被同源策略限制,可以跨域

利用这个特性,创捷script标签,通过他访问网站获取数据,并根据回调函数对数据处理

缺点:

  1. 而且要确定jsonp的请求是否失败不容易,错误处理机制不完善。
  2. 只支持get
为什么不能用post?
请求一段 JS 脚本,把执行这段脚本的结果当做数据,相当于动态执行了js代码,script的标签就是获取脚本并执行,src只能get无法定义其他的请求格式。
  1. 可能被注入恶意代码,篡改页面内容,造成XSS,可以采用字符串过滤来规避此问题
  2. JSONP劫持漏洞,由于对于来源域没有严格限制,因此来源于不安全的域的请求也会被响应

应用场景:需要兼容IE低版本浏览器

node 服务端

router.get("/jsonp", function(req, res, next) {
  var _callback = req.query.callback;
  var _data = { email: 'example@163.com', name: 'test' };
  if (_callback) {
    res.type('text/javascript');
    res.send(_callback + '(' + JSON.stringify(_data) + ')');
  }else {
    res.json(_data);
  }
});

前端

<script src="http://localhost:3000/jsonp?callback=alert(1)"></script>

CROS -跨域资源共享(Cross-origin resource sharing)

新的w3c标准允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持,浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

优点:主流浏览器对其兼容性都表现良好,而且支持所有的请求方式

缺点:

  1. 此方法IE8以下完全不支持,IE8-10部分支持;
  2. 复杂请求下会发两次请求

在HTTP首部添加Acess-Contril-Allow-Origin设置允许访问的域名

CORS请求默认不发送Cookie和HTTP认证信息

Access-Control-Allow-Credentials: true // 允许访问cookie

express有cors中间件

反向代理(前后端分离大多使用)

代理:在请求到达服务前部署一个服务,将接口请求进行转发

正向代理:代理服务器架设在客户端和目的主机之间

反向代理:代理服务器架设在目的主机上转发客户请求

优点:可以防止外网对内网服务器的恶性攻击、缓存以减少服务器的压力和访问安全控制;可以进行负载均衡,将用户请求分配给多个服务器 举例:

  1. webpack-dev-server(cdos)
  2. http-proxy-middleware(云盾)
  3. nginx反向代理:把请求转发给后面的服务器,决定哪台目标主机来处理当前请求(老监管) ngnix反向代理.png

postMessage

postMessage允许每一个Window(包括当前窗口、弹出窗口、iframe等)对象往其他的窗口发送文本消息,从而实现跨窗口消息传递,且这个功能不受同源策略影响。

发送

clipboard (1).png

监听

clipboard (2).png

优点:主流浏览器及IE8+支持,简单易用

缺点:存在安全问题:

  1. 是对于监听窗口来说,监听窗口作为数据的接收方会将数据进行二次处理或显示,如果直接使用获得数据,就会如同SQL语句之前没有过滤导致注入一样,会导致一些不可控的后果(比如XSS),所以监听窗口在防御上至少要做到以下两点:
  • 始终使用origin和source属性验证发件人的身份,防止攻击者伪造发送源发送恶意数据;
  • 要对接受到的message进行检查,即使是许可的源也有可能发送错误或恶意数据的,在使用之前要检查其合法性。
  1. 是对发送窗口来说,我们知道在发送数据之前需要声明一个window对象(在发送窗口的代码截图中可以看到),它指定了我们的数据发送到哪一个窗口,这里很多人认为既然已经指定了窗口,targetOrigin就可以不用设置。但实际上这里存在一个问题,比如当window所指定的窗口因为某种原因发生了跳转,前往了其他链接,如果不指定targetOrigin数据依然会被发送,这样就可能导致信息泄露。所以发送窗口在防御上要设置一个确切的targetOrigin,而不是空值。

iframe跨域

  1. document.domain:适用于同主域不同子域的情况下,将两个页面都指向主域
  2. window.location.hash:通过改变iframe的url发送数据,子页面监听hash的变化获取数据
  3. window.name: 同窗口下window.name不变,将数据传给window.name