iframe,ajax,canvas跨域处理

425 阅读4分钟

因为浏览器的同源策略而产生跨域问题,跨域主要是为了用户的上网安全。下面例举了前端最常见的三个跨域,以及处理方式

iframe 跨域

iframe跨域主要是为了防止恶意网站获取其他网站的dom,拿去私密信息,如果没有跨域恶意网站可以嵌套其他网站,比如https://mail.qq.com/,当用户输入用户名密码时通过dom即可截取到。当然也有一些业务确实确实需要跟子页面通讯,下面列举了一系列iframe跨域的处理方式

子域跨域 document.domain

document.domain的作用就是获取/设置当前文档的原始域名,默认值就是当前域名。可设置的值为父域名|当前域名。比如a.demo.com可设置的值就是a.demo.com|demo.com。浏览器判断跨域时会使用document.domain来判断是否域名跨域。

所以我们子域名与子域名使用iframe跨域时,双方的document.domain都设置为父域名。父域名与子域名使用iframe跨域时,子域名将document.domain设置为父级域名。

window.name

window.name可读可写,值是跟着浏览器窗体走的,也就是说不是跟着页面走的,我们在使用iframe加载子页面时,子页面可以通过name来传递值给父级使用。

// 子页面
window.name = JSON.stringify({ title: "child" });
// 父页面
const $iframe = document.createElement("iframe");
$iframe.src = "";
$iframe.onload = () => {
  // '{"title":"child"}'
  console.log($iframe.contentWindow.name);
};
document.body.appendChild($iframe);

window.postMessage

window.postMessage方法可以安全的实现跨通讯,使用时在发送方明确接收方的协议、地址、端口号就可以发送,接收方使用message事件监听来自postMessage的事件。

// 子页面 b
parent.postMessage("toggleFullScreen", "http://a.demo.com");
// 父页面 a
window.addEventListener("message", (event) => {
  if (event.origin === "http://b.demo.com") {
    // event.data 发送的消息
    window[event.data]();

    // event.source 获取发送方的window
    event.source.postMessage(`${event.data}Success`, event.origin);
  }
});

AJAX 跨域

AJAX跨域主要是放置恶意网站请求其他网站,因为请求中会携带cookie服务器会误认为是“本人”操作而引发安全问题。比如用户登录了银行网站,然后访问恶意网站,恶意网站请求转账到指定账户,此时请求会携带上用户信息到银行服务器。当然也有一些业务确实跨域请求其他服务器,下面列举了一系列AJAX跨域的处理方式

JSONP

ajax请求收到同源策略影响,但是script标签的src属性不会,可以访问跨域的js脚本。我们可以利用这个特性,在服务端不返回JSON格式,而是返回某个函数执行代码。

const $script = document.createElement("script");
$script.src = `http://www.xxx.com/?callback=getData`;

const getData = (data) => {
  console.log(data);
};

document.body.appendChild($script);
// 服务端返回e
// getData({ ... })

JSONP只支持get而且需要后端配合

CORS

请求时,服务端在 HTTP 响应头设置Access-Control-Allow-Origin允许当前域跨域,浏览器就会允许跨域行为

Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>

携带凭证的 CORS

上方的请求是不携带凭证 (如 cookie) ,也就是说服务器无法认证你的信息,比如我们再 A 网站登录了,在 B 网站通过AJAX请求 A 网站是无法拿到需要凭证的信息的 (如用户信息), 如果需要带上cookie还需要做其他处理,参考我之前写过的文章

Proxy

在客户端浏览器发起一个非同源请求会产生跨域问题,但是服务端并没有同源策略,服务端向另一个服务器发起请求不会产生跨域问题。那我们可以将请求统一到同源的服务器,对于要跨域的请求加上特定标识的 url 前缀,在服务器上匹配如果是这个前缀的请求,则反向代理到跨域服务器。

我们在代理中还可以修改Cookiedomain信息,方便当前域Cookie的写入。

这是目前最常用的方式,本地开发的跨域可以在本地建立代理,如果是线上则在线上创建代理。

canvas 跨域

canvas提供了一个通过JavaScriptHTML元素来绘制图形的方式,canvas可以从其他站点加载其他站点的资源,比如图片。在跨站引入资源没有处理时,canvas会被污染,只要被污染的画布就无法获取画布数据,如toBlob、toDataURL、getImageData一类api,这就产生的跨域问题。

CORS、Proxy

canvas产生的跨域问题跟AJAX的处理方式差不多,可以借助Proxy,或者在 HTTP 响应头设置Access-Control-Allow-Origin。除此之外还需要对资源通过crossorigin属性声明不需要凭证信息。

属性值描述
anonymous对此元素的CORS请求将不设置凭证标志
use-credentials对此元素的CORS请求将设置凭证;这意味着请求将携带凭证
""设置空值,与设置anonymous效果一致
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');

const img = new Image()
img.crossOrigin = 'anonymous'
img.onload = function () {
    context.drawImage(this, 0, 0)
    context.getImageData(0, 0, this.width, this.height);
};
img.src = 'xxx'

携带凭证的CORS

如果需要携带凭证除了声明crossOrigin属性值为use-credentials外还需要做其他处理,参考我之前写过的文章

完结撒花