0%

浏览器的同源策略

跨域

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。

广义的跨域:

1
2
3
1.) 资源跳转: A链接、重定向、表单提交
2.) 资源嵌入: <link><script><img><frame>等dom标签,还有样式中background:url()、@font-face()等文件外链
3.) 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

同源政策

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

同源策略限制以下几种行为:

1
2
3
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) 不能发送网络(http)请求

常见跨域场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
URL                                      说明                    是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js 同一域名,不同文件或路径 允许
http://www.domain.com/lab/c.js

http://www.domain.com:8000/a.js
http://www.domain.com/b.js 同一域名,不同端口 不允许

http://www.domain.com/a.js
https://www.domain.com/b.js 同一域名,不同协议 不允许

http://www.domain.com/a.js
http://192.168.4.12/b.js 域名和域名对应相同ip 不允许

http://www.domain.com/a.js
http://x.domain.com/b.js 主域相同,子域不同 不允许
http://domain.com/c.js

http://www.domain1.com/a.js
http://www.domain2.com/b.js 不同域名 不允许

跨域解决方案

  1. jsonp

    jsonp的原理就是利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。

    1
    <script src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback'/>

    jsonp(只支持get请求,支持老的IE浏览器)适合加载不同域名的js、css,img等静态资源;

  2. document.domain+iframe适合主域名相同,子域名不同两个页面的跨域请求,可以在两个页面设置document.domain = “主域名” 。

    例如:http://A.h5course.com/a.html页面和http://B.h5course.com/b.html页面能够相互访问,可以在两个文件中设置document.domain = “h5course.com”,两个页面文档里通过iframe引入对方的文件。

    iframe元素:iframe 元素会创建包含另外一个文档的内联框架(即行内框架)。

  3. react项目在package.json中使用proxy(代理)配置可以解决跨域问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    "proxy": {
    "/api/admin": {
    "target": "http://localhost:12610",
    "pathRewrite": {
    "^/api/admin": "/"
    }
    },
    "/api": {
    "target": "http://47.74.215.209:9000"
    }
    }
  4. 设置webpack 的proxy 代理实现跨域

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    dev: {
    env: require('./dev.env'),
    port: 8080,
    autoOpenBrowser: true,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
    '/api': {
    target: 'http://www.abc.com', //目标接口域名
    changeOrigin: true, //是否跨域
    pathRewrite: {
    '^/api': '/api' //重写接口
    }
    },
    cssSourceMap: false
    }
  5. 使用 http-proxy-middleware 代理跨域

    a. 安装http-proxy-middleware

    1
    2
    $ npm install http-proxy-middleware --save
    $ # or$ yarn add http-proxy-middleware

    b. 创建 src/setupProxy.js

    c. 第三步 设置代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // setupProxy.js
    const { createProxyMiddleware } = require('http-proxy-middleware');
    module.exports = function(app) {
    app.use(
    '/api', //使用"/api"来代替"http://localhost:3000"
    createProxyMiddleware({
    target: 'http://localhost:3000', //源地址
    changeOrigin: true, //改变源
    pathRewrite: {
    '^/api': 'http://localhost:3000' //路径重写
    }
    })
    );
    app.use(
    '/apc',
    createProxyMiddleware({
    target: 'https://test.tosharing.com',
    changeOrigin: true,
    pathRewrite: {
    '^/api': 'https://test.tosharing.com'
    }
    })
    );
    };
  6. CORS跨域资源共享

      参考阮一峰老师的文章 http://www.ruanyifeng.com/blog/2016/04/cors.html