深度解析Web开发中的跨域问题

本文最后更新于:8 个月前

梦想再大也不嫌大,追梦的人再小也不嫌小,因为心中有梦,就有无限可能。

导言

正文

什么是跨域

问题背景

  • 以下是跨域的标准定义:
1
跨域指的是在浏览器中,当一个网页(或者Web应用)尝试访问不同域名、不同端口或不同协议的资源时,浏览器会限制该行为,防止潜在的安全风险。跨域问题是由浏览器的同源策略(Same-Origin Policy)所引起的。
1
同源策略是一种安全策略,是浏览器的一项重要基础安全机制。它要求网页只能与同一域名、协议和端口的资源进行交互。同源策略的存在是为了防止恶意网站获取用户的敏感信息或进行中间人攻击等安全问题。
  • 很显然,跨域就是在浏览器请求资源的过程中发生的
  • 浏览器请求资源时,如果请求的目标和当前页面的域名、端口或协议不一致,就会触发跨域问题
  • 具体来说,以下情况被认为是跨域访问:
    1. 不同域名:例如,www.example.com 和 api.example.com。
    2. 不同端口:例如,www.example.comwww.example.com:8080。
    3. 不同协议:例如,http://example.comhttps://example.com。
  • 现在的 Web 开发中都是前后端分离的开发模式,数据的获取并非同源,所以跨域的问题在我们日常开发中特别常见
  • 一般而言,跨域问题是在以下情况下产生的:
1
AJAX请求:当通过XMLHttpRequest对象发送异步请求时,如果请求的目标和当前页面的域名、端口或协议不一致,就会触发跨域问题。
1
资源加载:在网页中引入了来自不同域的外部资源,比如CSS、JavaScript、图片等文件时,如果资源服务器不允许跨域访问,也会产生跨域问题

广义的跨域

  • 其实浏览器加载的资源很多都是跨域的,只是有些资源的加载浏览器是允许的
  • 图片、CSS、Script 等资源是不受同源策略限制的,一般不会触发跨域跨问题

狭义的跨域

  • 这里的跨域主要说的是 ajax 请求无法完成
  • 跨域问题主要是在浏览器环境下出现的,当浏览器发现请求跨域时,会在请求头中加上一个 Origin 字段,目标服务器会返回一个 Access-Control-Allow-Origin 的响应头,确定是否允许跨域访问

跨域解决方案

古老的 JSONP

概念

  • JSONP(JSON with Padding)

原理

  • JSONP 的优点就是因为他够老,能兼容各种浏览器,无兼容问题,众生平等
  • 他发送的不是 ajax 请求,而是利用了 script 标签加载机制。他发送的不是 ajax 请求
  • 了解了相关机制,我们看一下具体实现:
  • 客户端代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function jsonp() {
var script = document.createElement("script");
script.type = "text/javascript";

// 传参并指定回调执行函数为backFn
script.src = "http://localhost:8100/getUserInfo?uid=100&callback=backFn";
document.head.appendChild(script);
}

// 回调执行函数
function backFn(res) {
alert(JSON.stringify(res));
}

document.getElementById("btn_get_data").addEventListener("click", () => {
jsonp();
});
  • 服务端代码
1
2
3
let uid = ctx.query.uid;
let callback = ctx.query.callback;
ctx.body = 'backFn({"code": 0, "user": "admin"})';

CORS 跨域解决方案

概念

  • CORS(Cross-origin resource sharing)即“跨域资源共享“
  • 在出现 CORS 标准之前, 我们还只能通过jsonp(jsonp 跨域请求详解)的形式去向“跨源”服务器去发送 XMLHttpRequest 请求,这种方式吃力不讨好,在请求方与接收方都需要做处理,而且请求的方式仅仅局限于 GET。所以 ,CORS 标准必然是大势所趋,并且市场上绝大多数浏览器都已经支持 CORS。

原理

  • 支持 CORS 请求的浏览器一旦发现 ajax 请求跨域,会对请求做一些特殊处理,对于已经实现 CORS 接口的服务端,接受请求,并做出回应
  • 有一种情况比较特殊,如果我们发送的跨域请求为“非简单请求”,浏览器会在发出此请求之前首先发送一个请求类型为 OPTIONS 的“预检请求”,验证请求源是否为服务端允许源,这些对于开发这来说是感觉不到的,由浏览器代理
  • 总而言之,客户端不需要对跨域请求做任何特殊处理
  • 有关 CORS 跨域解决方案的具体介绍,可以看这篇博客:
  • 彻底理解 CORS 跨域原理 - 喵小 Q - 博客园 (cnblogs.com)
  • 我们在开发过程中,只需作这两个步骤,即可解决跨域问题:

前端

1
2
3
4
5
// 创建 Axios 实例
const myAxios = axios.create({
baseURL: "http://localhost:8083/api", // 设置请求的基础URL(后端请求地址)
withCredentials: true,
});

后端

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 允许跨域请求
*
* @param registry registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("http://localhost:7070", "http://localhost:3000","http://120.55.62.195:7071") // 前端请求地址
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}

网络传输安全

防止窃听,机密性

  • 对称加密算法:通信双方使用唯一的密钥来加密通信数据。(2024/01/07 午)

问题:通信之前,如何把用来加密数据的密钥安全地传输给对方?无法保证。

  • 非对称加密算法:通信双方各持有一个密钥对,公钥是公开的,私钥自己持有。使用对方的公钥加密数据,只有对方才能用私钥解密

问题:非对称算法的运算速度很慢、性能很差,如果传输过程中频繁使用非对称加密算法加密数据,网络的传输效率是很低的

  • 混合加密:将对称加密算法和非对称加密算法结合,通信开始前使用双方使用非对称加密方式传输密钥,保证了密钥的安全传输,此后通信双方可以使用该密钥来加密通信数据,保证了通信数据的保密性。

防止篡改,完整性

  • 摘要算法:一种特殊的单向加密的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”。摘要和原数据是完全等价的,加密后的数据无法解密,不能从摘要逆推出原文。发送方把加密后的数据,使用摘要算法生成摘要,把加密数据和该摘要一同发往接收方。接收方使用同样的摘要算法对加密数据进行计算,比照生成的摘要和接受的摘要是否一致,保证了通信数据的完整性。

身份认证,真实性

  • 数字签名:发送方要保证通信数据是真实可信的,不是别人伪造的。使用自己的私钥对摘要加密,生成数字签名。数字签名和加密数据被一同发往接收方。接收方使用发送方的公钥解密,验证签名,拿到摘要,再比对原数据验证完整性。这样就可以像签署文件一样,证明消息确实是发送方发的。

  • 数字证书:接收方能够使用公钥验签,但是公钥是公开的。我们还缺少防止黑客伪造公钥的手段,也就是说,怎么来判断这个公钥就是发送方的公钥呢?CA(证书认证机构)具有极高的可信度,由它来为各个公钥签名,这样的公钥就是可信的。CA 对公钥的签名认证也是有格式的,不是简单地把公钥绑定在持有者身份上就完事了,还要包含序列号、用途、颁发者、有效时间等等,把这些打成一个包再签名,完整地证明公钥关联的各种信息,形成数字证书。

  • 通信双方的数据是加密传输的,保证了数据是保密的,没有被窃听;使用摘要保证了数据的完整性,没有被篡改;使用数字签名,保证了发送方的身份是可靠的,没有被伪造;使用数字证书,保证了接收方的身份是可信的。

总结

  • 总之,跨域问题在 Web 开发过程中很常见,只要搞清楚跨域产生的原因,解决跨域问题并不困难
  • 这里另外补充几种常见的跨域解决方法,稍作了解:
1
2
3
4
5
6
要解决跨域问题,可以采取以下常见方法:

JSONP(JSON with Padding):通过动态创建<script>标签,利用<script>标签没有跨域限制的特性,实现跨域请求。
CORSCross-Origin Resource Sharing):在服务器端设置响应头,允许指定的域名或所有域名进行跨域访问。
代理(Proxy):在自己的服务器上设置一个代理接口,将跨域请求转发到目标服务器上。
WebSocket:使用WebSocket协议进行双向通信,不受同源策略限制。

深度解析Web开发中的跨域问题
https://test.atomgit.net/blog/2023/07/15/深度解析Web开发中的跨域问题/
作者
Memory
发布于
2023年7月15日
更新于
2024年1月7日
许可协议