计算机网络:同源策略

1、介绍

  • 同源策略:禁止一个源(origin)的脚本和文档和另一个源的脚本和文档交互。
  • 什么是同源:两个URL的协议(protocol)、端口(port)和域名(domain)都相同,这就是同源。
  • 同源策略的目的:防止恶意的网站窃取用户的cookie,或者其他敏感信息。
  • 同源策略的实现:浏览器会在同源的情况下,允许脚本和文档进行交互。
  • 同源策略的限制:不能读取对方的cookielocalStoragesessionStorageindexedDBwebSocketEventSourceXMLHttpRequestlocationhistory 等等。

2、问题回答

  • 问1:如果两个源产生过多交互会有什么影响?

影响很大的就是恶意的网站窃取用户的cookie,或者其他敏感信息。这样数据就不安全了,所以同源策略是非常重要的。

  • 问2:应不应该允许网站提交cookie到不同源的服务器?

这个是不允许的,但是你自己配置了跨域是可以的。

  • 问3:为什么不禁用不同源的js?

因为有些js是第三方提供的,我们引用cdn的js,引用组件。

  • 问4:应不应该允许不同源的js修改dom?

这个是允许的,比如百度统计,百度地图等,如果不允许不同源的js修改dom,那么就无法统计用户的地理位置,无法使用百度地图等功能。

  • 问5:应不应该允许不同源的js获取远程图片内容?

这个是不允许的,如果能远程执行代码,那么就有可能获取到敏感信息和人家私密数据,这个肯定不行的。

  • 问6:应不应该允许网站提交数据到不同源的服务器?

这个是不允许的,如果能提交数据,那么就会被别人收集你的数据,然后提交到自己的服务器上,这等于抢劫,不劳而获,这个也肯定不行的。

3、跨域请求技术

  • Jsonp技术

    • Jsonp的原理:就是利用script标签的src属性没有跨域限制来实现的。

    • Jsonp的优缺点

      • 缺点:只能get请求
      • 优点:浏览器的兼容性好
    • Jsonp的实现及应用

    • 模拟服务端server.js ,启动方式: node server.js (需要安装node.js)

//模拟服务端
let http = require("http")
let url = require("url")

//模拟数据
let data;

http.createServer((req, res) => {
    let urlobj = url.parse(req.url, true)
    console.log("打印参数:id={} & cbk={}",[urlobj.query.id,urlobj.query.cbk]);
    switch (urlobj.pathname) {
        case "/api/jsonp":
            //返回结果格式:JSONP.callbacks[callbackId](json内容)
            //示例:JSONP.callbacks[1]({"name":"小猿编程秘籍","age":18})
            let returnData =data[urlobj.query.id]
            res.end(`${urlobj.query.cbk} (${JSON.stringify(returnData)})`)
            break;
        default:
            res.end("404")
    }
}).listen(8888, () => {
    console.log("start");
    //模拟数据初始化
    data = getData();
})

function getData() {
    return  {
        "1":{
            id: 1,
            name: '小猿编程秘籍',
            age: 18
        },
        "2": {
            id: 2,
            name: '小白',
            age: 18
        },
        "3": {
            id: 3,
            name: '小红',
            age: 18
        },
    }
}
  • 模拟客户端jsonp.html,启动方式:直接点击这个文件用浏览器打开就可以
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="utf-8">
    <title>JSONP测试</title>
</head>
<body>
<div style="text-align: center">
    <input type="text" id="idVal" style="margin-top: 30px;" />
    <button id="btn" onclick="selectData()">查询</button>
    <br/>
    <h4>JSONP客户端测试结果:</h4>
    <br>
    <textarea id="callback" cols="50" rows="10" name="returnData"></textarea>
</div>

<script >
    //创建JSONP函数
    function JSONP({
                       url,
                       params = {},
                       callbackKey = 'cbk',
                       callback
                   })
    {
        //1、定义唯一id
        JSONP.callbackId = JSONP.callbackId || 1;
        let callbackId = JSONP.callbackId;

        //2、避免污染
        JSONP.callbacks = JSONP.callbacks || [];
        JSONP.callbacks[callbackId] = callback;

        //3、添加参数
        params[callbackKey] = `JSONP.callbacks[${callbackId}]`;

        //4、等到最终参数字符串
        const paramString = Object.keys(params).map(key => {
            return `${key}=${encodeURIComponent(params[key])}`
        }).join('&')

        //5、创建 script 标签 添加到页面中
        const script = document.createElement('script');
        script.setAttribute('src', `${url}?${paramString}`);
        document.body.appendChild(script);

        // 6、保证唯一
        JSONP.callbackId++;

    }
    function selectData(){
        let id = document.getElementById('idVal').value;
        //使用JSONP函数
        JSONP({
            url: 'http://localhost:8888/api/jsonp',
            params: {
                id: id
            },
            callbackKey: 'cbk',
            callback (res) {
                document.getElementById('callback').innerHTML = JSON.stringify(res)
            }
        })
    }
</script>
</body>
</html>
  • 测试:先启动服务端,然后打开客户端

    • 服务端启动 服务端启动
    • 客户端打开,请求结果 客户端请求结果 服务端打印请求参数
  • 跨域资源共享(CORS)

    • 概念:跨域资源共用(Cross-Origin Resource Sharing)使用额外HTTP头允许指定的源和另一个源进行交互
    • 预检(preflight):客户端和服务端在正式通信前,浏览器会增加一次HTTP查询请求,这就是预检请求 预检
    • CORS请求跨域实现流程: CORS请求跨域实现流程
    • CORS与JSONP的对比,个人认为JSONP更好
  • 代理

    利用代理将不同源的资源代理到同源的资源 代理