安全基础第五天:跨域

一、同源和非同源

  1. 含义:

协议相同、域名相同、端口相同

  1. 目的:

保证用户安全信息,防止恶意网站窃取数据

二、利用document.domain降域实现跨域

  1. 原理:

利用的是document.domain降域来实现cookie获取的限制

  1. 新建两个文件夹分别为cookie_origin和cookie_orign_sub,以及建立了两个网站(master.security.comslave.security.com页面)

  1. 配置虚拟主机(小皮)

  1. 打开D:\phpstudy_pro\Extensions\Apache2.4.39\conf\vhosts选择default-default.conf编辑以下内容

<VirtualHost *:80>
    DocumentRoot "D:/phpstudy_pro/WWW/cookie_origin"
    ServerName master.security.com
    FcgidInitialEnv PHPRC "D:/phpstudy_pro/Extensions/php/php5.6.9nts"
    AddHandler fcgid-script .php
    FcgidWrapper "D:/phpstudy_pro/Extensions/php/php5.6.9nts/php-cgi.exe" .php
    <Directory  "D:/phpstudy_pro/WWW/cookie_origin">
            Options FollowSymLinks ExecCGI
            AllowOverride All
            Order allow,deny
            Allow from all
            Require all granted
            DirectoryIndex index.php index.html
    </Directory>
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "D:/phpstudy_pro/WWW/cookie_origin_sub"
    ServerName slave.security.com
    FcgidInitialEnv PHPRC "D:/phpstudy_pro/Extensions/php/php5.6.9nts"
    AddHandler fcgid-script .php
    FcgidWrapper "D:/phpstudy_pro/Extensions/php/php5.6.9nts/php-cgi.exe" .php
    <Directory  "D:/phpstudy_pro/WWW/cookie_origin_sub">
            Options FollowSymLinks ExecCGI
            AllowOverride All
            Order allow,deny
            Allow from all
            Require all granted
            DirectoryIndex index.php index.html
    </Directory>
</VirtualHost>
  1. 打开D:\phpstudy_pro\Extensions\Apache2.4.39\conf的httpd.conf文件,去掉如下注释

LoadModule vhost_alias_module modules/mod_vhost_alias.so
  1. 打开C:\Windows\System32\drivers\etc的host文件,编辑一下内容

127.0.0.1 master.security.com //主页面
127.0.0.1 slave.security.com //子页面
  1. 在建立的cookie_origin文件下新建一个html网页

  1. 访问网站是否成功

  1. 在cookie_origin文件下写入以下内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>master</title>
</head>
<body>
    <h1>master</h1>
    <iframe src="http://slave.security.com" id="iFrame"></iframe>
</body>
<script>
    document.domain = 'security.com';
    let ifr = document.getElementById('iFrame');
    ifr.onload = function() {
        let win = ifr.contentWindow;
        alert(win.data)
    }
</script>
</html>

该代码的意思是利用iframe标签来嵌套一个子页面slave.security.com定义的唯一固定id为iFrame,之后利用document.domain给他们降级到同一个域级,这样他们之间就可以实现网页之间的互相访问,设置一个onload函数用来监听,起作用是等iframe访问完成后进行监听子网页,之后利用contentwindow来抓取子页面的内容,最后利用window的data属性弹窗出我们的data数据。

  1. 在cookie_origin_sub下写入以下内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>slave</title>
</head>
<body>
    <h1>slave</h1>
</body>
<script>
    document.domain = 'security.com';
    window.data = 'data:111';
</script>
</html>
  1. 最后检验我们的结果

三、利用location.hash配合iframe实现跨域(不推荐)

  1. 原理

#data就是location.hash,改变hash值不会导致页面刷新,所以可以利用hash值来进行数据的传递,所以我们利用ifrom这个标签来实现数据传输,子页面收到父页面的请求后修改父页面的hash值,但是由于两个页面不在同一个域下,所以浏览器不允许修改,需要子页面进行iframe请求父页面的同源页面c.html页面,之后将改变的hash值给我们的c.html,我们的c.html请求两次父页面就实现了跨域。

  1. 虚拟主机配置和上一个实验是一样的(主网页www.aaa.com子网页www.bbb.com

  1. 在cross_origin编写以下内容

!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>aaaaaaaaaa</title>
</head>

<body>
    <div>aaaaaaaaaaaaa</div>
</body>
<script>
    var ifr = document.createElement('iframe');
    ifr.src = 'http://www.bbb.com#data';
    ifr.style.display = 'none';
    document.body.appendChild(ifr);//请求跨域的操作

    function checkHash() {
        try {
            let data = location.hash ? location.hash.substring(1) : ' ';
            console.log('获得到的数据是:', data);
        } catch (e) {

        }
    }
    checkHash();
    window.addEventListener('hashchange', function (e) {
        console.log('获得的数据是:', location.hash.substring(1));
    });
</script>

</html>

该代码的意思是15-16行表示的是一个跨域的一个请求操作,之后进行一个哈希函数的的监听作用(checkhash),如果哈希值发生改变则会通过js.substring(1)从改变的第一个值进行截取,之后打印出改变的值,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>cccccccccccc</title>
</head>
<body>
    
</body>
<script>
    parent.parent.location.hash = self.location.hash.substring(1)
</script>
</html>

  1. 在cross_origin_sub编写一下内容

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>bbbbb</title>
</head>

<body>
    <div>bbbbbbbbbbbb</div>
</body>
<script>
    switch (location.hash) {
        case "#data":
            callback();
            break;
    }
    function callback() {
        const data = "some number: 1111"
        // parent.location.hash = data;
        try {
            parent.location.hash = data;
        } catch (e) {
            // ie, chrome 下的安全机制无法修改 parent.location.hash
            // 所以要利用一个中间的代理 iframe 
            var ifrproxy = document.createElement('iframe');
            ifrproxy.style.display = 'none';
            ifrproxy.src = 'http://www.aaa.com/c.html#' + data;     // 该文件在请求域名的域下
            document.body.appendChild(ifrproxy);
        }
    }
</script>
</html>

子页面的意思是当收到父页面的一个请求后,通过switch函数来判断是不是”#data“如果是就调用callback函数,我们利用parent.location.hash = data;把callback函数把父页面的哈希值变成了some number: 1111,之后父页面监听后,便将我们改变的值传递给父页面,之后父页面会打印出来,结果我们发现不行,原因是由于浏览器的安全机制我们无法修改父页面的哈希值,所以产生了我们的第三方代理页面(c.html)其要求是必须和父页面同源。我们的办法是增加一个catch函数,当我们的try函数判断受到了浏览器安全机制的限制时候我们进入到catch函数中,在这个函数中我们重新请求了一个iframe页面嵌套请求,请求我们的c.html,因为我们是在c.html里面进行请求的,相当于我们在父页面的子页面里面又嵌套了一个子页面,所以我们需要传输两次到我们的父页面。那么这个c.html相当于一个中转站,将我们的somenumber传两次传回到我们的父页面。

  1. 整体的过程

父页面aaa.com先进行请求子页面bbb.com,请求完成后,利用checkhash监听子页面的的哈希值有木有发生变化,子页面在接收到父页面的请求后判断是否有#data这个哈希值,入过有就会将其的data改为some number:1111,这时候返回给父页面,由于父页面有安全机制,就会显示不是同源,这时候返回给我们的子页面,之后子页面就会在去请求父页面同源下的一个c.html页面,我们利用c.html来将我们bbb.com页面修改的哈希值返回两次parent给我们的父页面,之后我们父页面识别是同源下的页面请求,并且监听到哈希值发生改变就打印出我们的内容

  1. 结果

  1. 缺点

(1)数据直接暴露在了url中

(2)数据容量和类型都有限

四、利用windows.name进行跨域

1.原理和location.hash一样,只是父页面指向子页面,子页面a又指向子页面b,利用的子页面a做的跳

转而已。

2.父页面的代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>window_name</title>
</head>

<body>
    <script>
        let data = '';
        const ifr = document.createElement('iframe');
        ifr.src = "http://www.aaa.com";
        ifr.style.display = 'none';
        document.body.appendChild(ifr);
        ifr.onload = function () {
            ifr.onload = function () {
                data = ifr.contentWindow.name;
                console.log('收到数据:', data);
            }
            ifr.src = "http://www.security.com/c.html";
        }
    </script>
</body>

</html>

我们可以在该页面下新建一个iframe,该iframe的src属性指向服务器地址(利用iframe标签的跨域能力),服务器文件b.html设置好window.name值。但是由于a.html页面和该页面iframe的src不同源的话,则无法操作iframe里的任何东西,所以就取不到iframe的name值,所以我们需要在b.html加载完之后重新换个src区指向一个同源的html文件,或者设置成about:blank都行,这时候我们只要在a.html相同的目录下件一个c.html空白即可。如果不重新指向src的话直接获取的window.name的话就会报错。

3. c.html

window.name = "hello";

五、postMessage跨域(重点推荐)

  1. 原理

www.security.comwww.aaa.com实现跨域操作,官方使用window.postmessage,其原理就是从源区域跨域的时候,通过postmessage的方法属性,对发送的页面进行监听,跨域的页面也进行postmessage属性的一个监听,从而来实现跨域的操作

  1. 在postmessage.html页面

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>postMessage</title>
</head>

<body>
    <iframe src="http://www.aaa.com"></iframe>
    <script>
        window.onload = function () {
            let targetOrigin = 'http://www.aaa.com';
            //想要操作当前iframe的时候,就像该ifranme中postMessage()一个东西。
            window.frames[0].postMessage('我要给你发消息了!', targetOrigin);
            //*表示任何域都可以监听。
        }
        //当我监听到message事件的时候,我就知道有人向我发送数据了,我获得了数据就可以做对应的事情。内部对消息做实现
        window.addEventListener('message', function (e) {
            console.log('security.com接收到的消息:', e.data);
        });
    </script>
</body>

</html>

首先security页面向aaa页面发送页面的请求,之后通过postmessage对该网页发送一些消息,于此同时我们也可以通过

  1. aaa.com页面创建一个页面用来监听来自security页面的消息

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>postmessag</title>
</head>

<body>
    <div>aaaaaaaaaa</div>
    <script>
        window.addEventListener('message', function (e) {
            if (e.source != window.parent) {
                return;
            }
            let data = e.data;
            console.log('aaa.com接收到的消息:', data);
            parent.postMessage('我已经接收到消息了!', e.origin);
        })
    </script>
</body>

</html>

该页面利用window.addeventlistener来监听来自sercurity的消息,主要靠的是监听message这个属性,如果不是来自security的消息就拒绝掉,如果是的话会通过event.data来获取这个消息的内容,并且告诉父元素其已经接收到该消息。

4.结果

六、postmessage的localstorage存储数据

  1. 原理:

通过postmessage方法进行对别的页面进行localstore的读写存储

  1. www.security.com页面建立一个对其他页面的存储请求

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>localstorage</title>
</head>

<body>
    <iframe src="http://www.aaa.com"></iframe>
    <script>
        window.onload = function () {
            let targetOrigin = 'http://www.aaa.com';
            //想要操作当前iframe的时候,就像该ifranme中postMessage()一个东西。
           // var win = document.getElementsByTagName('iframe')[0].contentWindow; 
            var obj = { name: 'oupeng','age': 10 };
             window.frames[0].postMessage(JSON.stringify({ key: 'storage', data: obj }), targetOrigin);
            //*表示任何域都可以监听。
        }
        //当我监听到message事件的时候,我就知道有人向我发送数据了,我获得了数据就可以做对应的事情。内部对消息做实现
        window.addEventListener('message', function (e) {
            console.log('security.com接收到的消息:', e.data);
        });
    </script>
</body>

</html>

通过iframe对www.aaa.com页面进行一个请求,之后对该窗口进行一个获取window的属性,建立一个obj的对象,在这个对象里加入我们需要存储的内容,之后通过json.stringify属性将这个数据转换为json对象,在通过postmessage方法将其传递到www.aaa.com页面

3.在ww.aaa.com页面

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>localstorage</title>
</head>

<body>
    <script>
        window.addEventListener('message',receiveMessage);
      function receiveMessage(event) {
            if (event.origin !== 'http://www.security.com') {
                return;
            }
            var payload = JSON.parse(event.data);
            localStorage.setItem(payload.key, JSON.stringify(payload.data));
        };
    </script>
</body>

</html>

www.aaa.com页面,通过监听window.message的属性从而来获取到来自www.security.com传递过来的数据,将其转换为字符串,然后通过localstorage.setitem将获取的obj方法存储到localstorage中。

4.结果

七、JSONP(极力不推荐,淘汰)

  1. 原理

通过建立一个<script>的请求,其不受跨源的要求,建立一个网页的请求,在建立的网页请求网址后面添加一个callback=foo的参数,并且通过拼接字符拿到foo这个函数中的内容。

2.在www.security.com建立一个请求拼接json的函数

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>jsonp</title>
</head>

<body>
    <script>
        function addScriptTag(src) {
            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.src = src;
            document.body.appendChild(script);
        }
        window.onload = function () {
            addScriptTag('http://www.aaa.com/index.html?callback=foo');
        }

        function foo(data) {
            console.log('Your public IP address is: ' + data.ip);
        };
    </script>
</body>

</html>

该代码的意思是建立一个函数进行<script>的标签请求,在请求的网址后面加入callback=foo这个参数,并且在后面拼接出得出服务器请求的json数据

3.在www.aaa.com中创建一个json数据库

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>aaaaaaaaaa</div>
    <script>
        function foo(data){
            console.info(data);
        }


        var obj = {'ip': '8.8.8.8'};
        foo(obj);
    </script>
</body>
</html>

其是指建立一个foo的json数据库,里面存放着我们需要请求的数据内容。

4.结果

八、WebSocket

  1. 原理

WebSocket 是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

  1. 在本地建立socket.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>nodesjs</title>
</head>
<body>
   <script>
    let socket = new WebSocket('ws://127.0.0.1:3000');
    socket.onopen = function () {
        socket.send('l love  you');
    }
    socket.onmessage = function (e) {
        console.log(e.data);
    }
   </script> 
</body>
</html>

该意思是利用websocket先进行ws的对websocket库进行一个请求,在通过socket.send方法对该库发送一条消息,之后在通过socket.onmessage方法对其进行一个数据的监听,从而获取数据。

3.建立socket.js库的相关配置

let express = require('express');
let app = express();
let WebSocket = require('ws');
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws){
    ws.on('message',function (data) {
        console.log(data);
         ws.send('i hate you')
    });
})

该库的意思是建立一个连接ws的3000端口请求,收到该请求后利用message来获取得到的数据,之后传递给请求页面一个l hate you的消息。

  1. 先在本地下载websocket服务器,之后node socket.js,最后访问www.security.com

  1. 结果

九、CORS(待补充,自己太菜了,弄不出来)

CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨域的服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值