跨域访问

跨域访问

1.Http请求

Host:目的域名和端口

Referer:当前请求页面的来源页面的地址,组成元素(协议+域名+查询参数)

Origin:这个请求原始从哪里发起的,包括当前请求的协议+域名;一般存在于CORS跨域请求(不符合同源策略的就是)

2.同源策略

即Same-Origin-Policy,SOP是一种约定,是浏览器内部的安全机制,用于限制浏览器中运行的JavaScript代码对不同源的访问;同源指两个或多个网页同时满足同域名、同协议、同端口

不同源的客户端脚本(js、ActionScrip)在没明确授权的情况下,不能读写对方的资源;

当前页面是来自 http://exmaple.com,同源策略允许加载来自同域名、同协议、同端口的资源

比如,浏览器在A网页设置的Cookie,B网页不能打开,除非同源

CSRF攻击就受到同源策略的限制

But——

在浏览器的下列标签,不受同源策略影响

<script src=”…”> 加载js到本地执行

<img src=””> 加载图片

<link href=”…”> css文件

<iframe src=””> 任意资源

再补充一点

受同源策略影响情况
  1. XMLHttpRequest 和 Fetch API:当使用XMLHttpRequest或Fetch API进行HTTP请求时,同源策略会限制跨源请求。
  2. Web Fonts、图像和媒体资源:浏览器允许加载来自其他域的Web字体、图像和媒体资源,但服务器必须支持跨域资源共享(CORS)或包含适当的CORS头部。
  3. Cookie 和存储:同源策略限制了对不同源的Cookie和本地存储的访问。
  4. 嵌入的内容:例如,使用<iframe>将来自不同源的网页嵌入到当前网页中,同源策略会对此进行限制。

3.跨域访问

做过开发的应该清楚,做项目时,前后端分离,前后端域名不同,端口也不同;请求时想获取数据就是POST/GET请求

4.ajax请求

同步请求是指当前发出请求后,浏览器什么都不能做, 必须得等到请求完成返回数据之后,才会执行后续的代码

AJAX 是一种用于创建快速动态网页的技术。它可以令开发者只向服务器获取数据

而ajax请求是指,在不需要重新刷新页面的情况下,Ajax通过异步请求加载后台数据,并在网页上加载出来

创建XMLHttpRequest对象,也就是创建一个异步调用对象。创建一个新的HTTP请求

如何跨域

1.JSONP

通常用于获取返回的数据是JSON格式的情况

JSONP的工作原理是通过在客户端创建一个<script>标签,该标签的src属性指向包含JSON数据的服务器资源。

服务器将JSON数据包装在一个JavaScript函数调用中,然后将其发送回客户端。

客户端收到响应后,可以直接执行包含JSON数据的JavaScript函数,从而获取数据

一、生成JSON响应
1.php代码
1
2
3
4
5
6
7
8
9
10
11
12
<?php

//连接数据库
$conn=new mysqli('127.0.0.1','root','root','pikachu') or die("数据库连接失败");
$conn->set_charset('urf8');
$sql="select id,username,password,level from users";
$result=$conn->query($sql);

//输出json数据到页面
$json =json_encode($result->fetch_all(MYSQLI_ASSOC));
echo $json;
?>
2.浏览器访问

http://localhost:81/7/list_json.php

二、在另一个页面用AJAX访问

list_json.html访问上述php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<html>
<script type="text/javascript">
var listurl="http://localhost:81/7/list_json.php";
//实例化XMLhttpRequest,用于发送Ajax请求
xmlhttp=new XMLHttpRequest();
var count=0;
//当请求的状态发生变化时,触发执行代码
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4&&xmlhttp.status==200){
//取得请求的相应,且通过正则获取token
var text=xmlhttp.responseText;
alert(text);

}
};
xmlhttp.open("GET",listurl,false);
xmlhttp.send();
</script>
<title>网页查看json数据</title>
<body>
....
</body>
</html>

PS:

XHR是一种用于在浏览器中发出HTTP请求的机制,它实际上是由浏览器提供的一种JavaScript对象

这里的ip地址要一致,如果你浏览器url是localhost,你代码就要填localhost,填的是主机地址,那代码也主机地址

浏览器访问

三、将list_json.php发到192.168.1.89的虚拟机去

将上面的html代码listurl改一下

http://192.168.1.89/list_json.php

访问 http://localhost:81/7/list_json.html

喏,跨域啦

但是嘞,在虚拟机里vim list-json.html

1
2
3
4
5
<html>
...
var listurl="http://192.168.1.89/list_json.php";
...
</html>

在主机去访问,是正常的,当然,我虚拟机没有这个数据库,无所谓了,反正是可以访问,也是同源

把虚拟机里的html,改成

1
2
3
4
5
<html>
...
var listurl="http://localhost:81/7/list_json.php";
...
</html>

主机去访问 http://192.168.1.89/list-json.html

也不行

四、Jsonp访问

基于回调函数的方式,为什么可以跨域?

将虚拟机里list_json.php内容改下

1
2
3
//echo $json;

echo $_GET['callback']."(".$json.")";

在主机看下这个效果就是 callback=test,将原json,用大括号括起来,并弄了参数 test($json),实际上这个test是种自定义方法啊,即 callback参数 是 函数名

1
2
3
4
5
6
<script>
function test(args){
alert(args);
}
</script>
<script src="http://192.168.1.89/list_json.php?callback=test"></script>

用test方法去弹出json内容

php有接收函数的参数

html有对应函数名的方法

哎,虚拟机里没数据库,建一个吧,刚好熟悉下了;

进入到mysql命令行,不谈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#建库
MariaDB [(none)]> create database pikachu;
#选择库
MariaDB [(none)]> use pikachu
Database changed
#建表,加字段
MariaDB [pikachu]> CREATE TABLE `users` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(30) NOT NULL, `password` varchar(66) NOT NULL, `level` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.04 sec)
#插入值
MariaDB [pikachu]> insert into users(id,username,password,level) values(123,'user0','dasd12321',3);
Query OK, 1 row affected (0.03 sec)

MariaDB [pikachu]> select * from users
-> ;
+-----+----------+-----------+-------+
| id | username | password | level |
+-----+----------+-----------+-------+
| 123 | user0 | dasd12321 | 3 |
+-----+----------+-----------+-------+
1 row in set (0.00 sec)

MariaDB [pikachu]>

好,在主机访问一下html

http://localhost:81/7/list_json.html

虽然看不出来,但起码弹窗了,说明跨域成功了

改改html代码,让json字符串化

1
2
3
4
function test(args){
//alert(args);
alert(JSON.stringify(args));
}

再访问一次

哇哦,成功了!!!!

总结

Jsonp的基于回调函数的方式,之所以能实现跨域;有两点:

1.script标签不受同源策略影响

2.再通过回调将值作为实参传给页面

在我的localhost,是一个非89的ip,成功访问到了一个ip为89的数据

客户端访问服务器(虚拟机)步骤:

  1. 自定义同名一个回调函数

  2. 创建一个script元素

  3. 这个script呢,指定了要请求的url,并将回调函数的名称作为参数传递过去

  4. 由于script插入到了当前网页,请求开始(向服务器请求资源)

  5. 服务器接收传递过来的参数,然后将回调函数和数据呢,以调用的方式输出

    $_GET['callback']."(".$json.")";

如果接收到callback=test

那么此时的形式为 test($json)

客户端写好了的,funciton test(args){…}

客户端会自己处理的

最后,script元素接收到响应中的脚本代码后,会自动执行它们

限制

只能处理GET请求,且 必须经过回调,在真实场景中受限

拓展

有关JSONP漏洞方面,请搜索 “JSONP漏洞”

2.CORS

跨域资源共享(Cross-Origin Resource Sharing),该标头内容限制了源域之外的域请求web资源;当网站请求跨域资源时,服务器端将返回此Allow-Origin,并由浏览器添加标头Origin

使用

1、在centos中,有以下代码,cors.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

//连接数据库
$conn=new mysqli('127.0.0.1','root','1234','pikachu') or die("数据库连接失败");
$conn->set_charset('urf8');
$sql="select id,username,password,level from users";
$result=$conn->query($sql);

//输出json数据到页面
$json =json_encode($result->fetch_all(MYSQLI_ASSOC));
echo $json;

#echo $_GET['callback']."(".$json.")";
$conn->close();
?>

2、在主机上实现以下html,去跨域访问虚拟机的cors.php

上次的jsonp是用xhr方式,这次用jquery

同文件夹下要有个jquery-3.4.1.min.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<head>
<script src="jquery-3.4.1.min.js"></script>
<script>
$.get('http://192.168.1.89/cors.php',function(data){
alert(data);
});
</script>
</head>
<body>

</body>
</html>

主机打开了phpstudy哈,访问

http://localhost:81/7/cors.html

3、同源策略的限制,主机访问不了虚拟机的文件

请求是发出去了的,但是没有收到服务器的响应

1
2
3
4
5
6
7
8
看一下对cors.php的请求标头
...
Host:
192.168.1.89
Origin:
http://localhost:81
Referer:
http://localhost:81/

4、去虚拟机的php文件中添加头部内容

1
2
3
4
...
header("Access-Control-Allow-Origin:*");
//*代表任意主机
...

主机再次访问,成功弹窗

f12可以看到php文件的响应标头

Access-Control-Allow-Origin: *

当然通常情况下不这样设置*,任意网站都能访问

5、辅助的响应头

1
2
3
4
5
6
Access-Control-Allow-Origin: *
Access-Contro1-A11ow-Methods: POST,OPTIONS,GET //请求的类型
Accgss-Contro1-ax-Age: 3600 //生命周期
Access-Contro1-Allow-Headers: accept, x-requested-with, Content-Type //可以接受的请求头
Access-Contro1-A11ow-Credentials: true //是否允许发送Cookie
Access-Contro1-A11ow-Origin: http://192.168.10.118:8070 //只允许哪个源访问
白名单防御

为了安全点

可以在虚拟机的php文件这样添加白名单

如果不是默认端口,需要额外加上端口

1
2
3
4
5
6
7
8
9
...
$list=array('http://xxx.ip','http://yyy.ip');
if(in_array($_SERVER['HTTP_ORIGIN'],$list)){
header("Access-Control-Allow-Origin:".$_SERVER['HTTP_ORIGIN']);
}
else{
die("CS disallowed!");
}
...
非简单请求的预检过程

https://www.cnblogs.com/wonyun/p/CORS_preflight.html

总结

3.WebSocket

总结

1、我一开始纠结的是

192.168.1.89/cors.php,为什么我可以访问,这只是一个单纯的url地址,没有跨域。

是用户在另一台主机上发送ajax请求,那么是因为从服务器A去访问服务器B,所以才会出现跨域的问题,浏览器才会去阻止

2、跨域,浏览器拦截了,但是请求是发出去了的哈,这是因为服务器没有响应

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2023-2025 是羽泪云诶
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信