先把数据结构搞清楚,程序的其余部分自现。
本文已被https://yourbatman.cn收录;公号后台回复“专栏列表”获取全部小而美的原创技术专栏

前言

你好,我是YourBatman

本系列前两篇文章用文字把跨域、Cors相关概念介绍完了,从下开始进入实战阶段。毕竟学也学了,看也看了,是骡子是马该拉出来遛一遛。

本文将实战Cors解决跨域问题中最为重要的响应头:Access-Control-Allow-Origin。它用于服务端告诉浏览器允许共享本资源的Origin,那么如何允许多个域名呢?

所属专栏

  • 点拨-Cors跨域

本文提纲

版本约定

  • JDK:8
  • Servlet:4.x
  • tomcat:9.x

正文

正如前文所述,响应头Access-Control-Allow-Origin 用于在跨域请求中告诉浏览器服务端允许的Origin,浏览器拿到这个头的值跟自己的Origin对比决定是否正常接收响应。

从命名上就有所察觉:Access-Control-Allow-Origin值是单数,否则就会叫Access-Control-Allow-Origins

(浏览器)官方对此响应头的可能值有明确规定:

也就说此响应头的取值只可能是上图中的3选1

null值的作用:让data:和file:打开的页面也能够共享跨域资源(因为这种协议下有Origin头,但是值是null,比较特殊)

那么问题来了,倘若服务端本资源需要允许多个域来共享,又该如何指定Access-Control-Allow-Origin 的值呢?这是一个开发中常见的场景,本文将继续深入讨论和介绍最佳实践。

环境准备

因为要构造不同的Origin来发送http://localhost:8080/multiple_origins_cors这个跨域请求,因此需要不同的域名,所以我需要在本机模拟出来。我的实践方案为:

  • 用本机Tomcat作为静态页面服务器,托管html页面
  • 修改本机host文件,达到支持多域名的目的

1. Tomcat托管静态html页面

之前我都是用的IDEA内建的静态服务器来托管html页面,但由于它不支持绑定多域名而无法模拟出本例需要的效果,因此我就不得不开辟新的方法喽。

做Java开发的小伙伴对Tomcat再熟悉不过,但由于Spring Boot的普及它屏蔽了开发者对Web Server的感知,所以可能虽然天天用但其实鲜有接触,特别是standalone的Tomcat服务器。

所以我这里稍微介绍下我的做法(关键步骤)。去到Tomcat的目录,仅需修改它的server.xml文件即可:

步骤一:修改端口为9090(因为我Server端服务器也是Tomcat,端口为8080,避免冲突)

步骤二:在host里托管Context上下文,关联到你的html文件夹(Tips:这只是托管的方式之一)

说明:docBase表示静态页面所在的文件夹(绝对路径),path表示对应的url访问路径

完成后,启动tomcat sh startup.sh后即可通过http://localhost:9090/static/xxx.html访问到静态页面啦。

2. 修改Host支持多域名

这个就比较简单了,无需多言,粘张图就懂。

这样通过如图中的3个域名就都可对页面进行正常访问啦

3. 书写前端html页面

multiple_origins_cors.html内容如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>多Origin响应CORS跨域请求</title><!--导入Jquery--><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body>
<button id="btn">多Origin响应CORS跨域请求</button>
<div id="content"></div><script>$("#btn").click(function () {// 跨域请求$.get("http://localhost:8080/multiple_origins_cors", function (result) {$("#content").append(result).append("<br/>");});});
</script>
</body>
</html>

4. 书写服务端代码

/*** 多Origin响应** @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a>* @site https://yourbatman.cn* @date 2021/6/9 10:36* @since 0.0.1*/
@Slf4j
@WebServlet(urlPatterns = "/multiple_origins_cors")
public class MultipleOriginsCorsServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String requestURI = req.getRequestURI();String method = req.getMethod();String originHeader = req.getHeader("Origin");log.info("收到请求:{},方法:{}, Origin头:{}", requestURI, method, originHeader);resp.getWriter().write("hello multiple origins cors...");setCrosHeader(resp);}/*** 写跨域响应头*/private void setCrosHeader(HttpServletResponse resp) {resp.setHeader("Access-Control-Allow-Origin", "http://localhost:9090");}
}

至此,环境已经准备好。此页面有三个地址/域名可以访问到(不包括localhost),也就是Origin可能有这三种情况:

  1. http://foo.baidu.com:9090
  2. http://bar.baidu.com:9090
  3. http://static.yourbatman.cn:9090

Access-Control-Allow-Origin支持多域名

现实场景中,服务端资源如若是完全公开的,那么可以使用Access-Control-Allow-Origin: *。但在现实场景中大多数资源并非完全public的,因此需要指定Access-Control-Allow-Origin具体值来达到控制的目的。

那么,如何让Access-Control-Allow-Origin支持多域名呢?下面示范一下常见的错误方式,最后给出最佳实践。

要实现Access-Control-Allow-Origin允许多个域名共享资源,按照“常规思维”,有好些个使用误区,这里我尝试罗列出来。

误区一:Access-Control-Allow-Origin值使用,分隔

,分隔在程序员的世界很常见,很多时候可表示多值。那在这里是否好使呢?试一试

private void setCrosHeader(HttpServletResponse resp) {resp.setHeader("Access-Control-Allow-Origin", "http://foo.baidu.com:9090,http://bar.baidu.com:9090");
}

点击按钮,发送跨域请求,失败详情:


可以看到不仅没实现多值,连foo.baidu.com:9090这个域名都不能访问啦~

误区二:写多个Access-Control-Allow-Origin响应头

这种方式也是“正常思维”之一。试一下:

private void setCrosHeader(HttpServletResponse resp) {resp.addHeader("Access-Control-Allow-Origin", "http://foo.baidu.com:9090");resp.addHeader("Access-Control-Allow-Origin", "http://bar.baidu.com:9090");
}

小细节:这里将setHeader改用为addHeader(xxx)了哟,你懂的

点击按钮,发送跨域请求,失败详情:


多说一句:在实际开发中这种出现两个Access-Control-Allow-Origin响应头的case还是比较常见的。根据经验一般原因是:Web Server设置了一个头,而Nginx(或者Gateway网关)又添加了一个头(一般值为*)。

强调:浏览器只要收到两个Access-Control-Allow-Origin响应头,不论值是什么(即使一模一样),都不会接受。

误区三:Access-Control-Allow-Origin值使用正则

当需要允许的多域名符合某个规律时,会想到使用简单的正则去匹配,那么是否支持呢?试一下:

private void setCrosHeader(HttpServletResponse resp) {resp.addHeader("Access-Control-Allow-Origin", "http://*.baidu.com:9090");
}

点击按钮,发送跨域请求,失败详情:


强调:浏览器拿Access-Control-Allow-Origin的值和Origin进行匹配的规则是完全匹配,通配符只认*

误区四:Access-Control-Allow-Origin值使用*通配符

这是一个特殊的使用“误区”:它能正常work,但并不能“很好的work”。试一下

private void setCrosHeader(HttpServletResponse resp) {resp.addHeader("Access-Control-Allow-Origin", "*");
}

点击按钮,发送跨域请求,正常响应


既然能够正常响应完成跨域请求,为何我会认为这么处理属于误区呢?

其原因主要为:使用*通配符属于暴力配置,表示任意源都可以访问此资源,对大部分场景来讲这违背了安全原则,存在安全漏洞,所以实际生产中并不建议这么做(除非是public资源)。

使用*通配符的漏洞

为何对使用*乐此不疲?答:因为简单,似乎能够解决“所有”跨域问题,且能一劳永逸。正所谓天下哪有那么多岁月静好,黑客们在那蠢蠢欲动。

在与浏览器“沟通”过程中,不恰当的使用Cors会造成一些可能的漏洞,比如最常见的便是当允许多个域名跨域请求时,很多同学为了方便就将Access-Control-Allow-Origin写为*,或者在Ng上直接赋值为$http_origin(效果完全同*)。这种暴力配置是很危险的,相当于任意网站都可以直接访问你的资源,那就失去跨域限制的意义了。

这么配置的话,在最基本的渗透测试中都是过不去的。如若你这么做且公司有安全部门,没过多久应该就会有人找你聊天喝茶了。

别问我为什么会知道,因为我就曾被安全部门同事招呼过

Cors跨域(三):Access-Control-Allow-Origin多域名?相关推荐

  1. CORS 跨域 实现思路及相关解决方案(转:http://www.cnblogs.com/sloong/p/cors.html)

    本篇包括以下内容: CORS 定义 CORS 对比 JSONP CORS,BROWSER支持情况 主要用途 Ajax请求跨域资源的异常 CORS 实现思路 安全说明 CORS 几种解决方案 自定义CO ...

  2. Cors跨域(二):实现跨域Cookie共享的三要素

    高考不努力,工地里当兄弟 前言 你好,我是YourBatman. 上篇文章(Cors跨域(一):深入理解跨域请求概念及其根因)用超万字的篇幅把Cors几乎所有概念都扫盲了,接下来将逐步提出解决方案等实 ...

  3. SpringBoot—CORS跨域问题详解和解决方案

    关注微信公众号:CodingTechWork,一起学习进步. 引言   在前后端开发过程中,遇到过一种错误,类似于报错: Access to XMLHttpRequest at 'http://127 ...

  4. Spring Boot CORS跨域资源共享实现方案

    同源策略 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能 同源策略限制cookie 等信息的跨源网页读取,可以保护本地用户信息 同源策略限制跨域 aja ...

  5. cors跨域_Spring Boot 中通过 CORS 解决跨域问题

    (给ImportNew加星标,提高Java技能) 转自:江南一点雨 今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的, ...

  6. CORS跨域漏洞的学习(防止CSRF漏洞导致的漏洞)

    0x00 从浏览器的同源策略说起 SOP,同源策略 (Same Origin Policy),该策略是浏览器的一个安全基石,如果没有同源策略,那么,你打开了一个合法网站,又打开了一个恶意网站.恶意网站 ...

  7. Cors跨域(一):深入理解跨域请求概念及其根因

    Talk is cheap. Show me the money. 前言 你好,我是YourBatman. 做Web开发的小伙伴对"跨域"定并不陌生,像狗皮膏药一样粘着几乎每位同学 ...

  8. CORS跨域资源共享(二):详解Spring MVC对CORS支持的相关类和API【享学Spring MVC】

    每篇一句 重构一时爽,一直重构一直爽.但出了问题火葬场 前言 上篇文章通过我模拟的跨域请求实例和结果分析,相信小伙伴们都已经80%的掌握了CORS到底是怎么一回事以及如何使用它.由于Java语言中的w ...

  9. 关于CORS跨域问题的理解

    起因 因为这段时间一个项目前后端分别部署在不同服务器的需要,抽空学习了一下CORS问题,不足之处,欢迎指教. 什么是CORS CORS是一个w3c标准,全称是"跨域资源共享"(Cr ...

  10. CORS跨域问题原因和解决方案

    Springboot跨域问题,是当前主流web开发人员都绕不开的难题.但我们首先要明确以下几点 - 跨域只存在于浏览器端,不存在于安卓/ios/Node.js/python/ java等其它环境 - ...

最新文章

  1. [译] ⚛ React 状态管理工具博物馆
  2. php 缩略图增加水印,PHP生成缩略图加图片水印代码
  3. c语言中最常用的四种数据类型,计算机中有哪几种常见数据类型
  4. 计算机专业使用的工具,电子投标工具使用手册计算机软件及应用it计算机专业资料.doc...
  5. 关于Facebook,Linkedin网的数据采集总结
  6. 3d max2012 安装加破解
  7. oracle数据库左链接,Oracle数据库中的左连接与右连接
  8. NFC技术——1、初始NFC
  9. C#导入.dll Please make sure that the file is accessible and that it is a valid assembly or COM compone
  10. QT串口助手(五):文件操作
  11. 利用函数wavread对语音信号进行采样_VoNR与VoLTE实现高清语音的奥秘,就是从小小的采样频率开始...
  12. Csdn视频第二十期 : 测试工具与流程讨论
  13. 电脑笑脸蓝屏问题 也许你可以尝试一下这个
  14. PHP MySQL 连接数据库
  15. NR PRACH(六) type 2(2-step) RA基本过程及时频域映射
  16. python 连接mysql_Python 连接MySQL
  17. about hashCode again understand
  18. 正则表达式,前后非空,中间可空
  19. 使用vuex对兄弟组件传值_vue组件之间相互传值的方式
  20. windows控制iPhone(不需要蓝牙)

热门文章

  1. camscanner(扫描全能王)功能解析与复现
  2. 有哪些需要不得不知的ASO的两种优化技巧
  3. Shifter - Responsive HTML5 高大上静态页面
  4. 关于网站中Logo部分的写法
  5. 网页标题logo添加与配置
  6. 几种常用的传感器(加速度传感器、重力传感器、方向传感器、陀螺仪)简介
  7. MDKA5D3x-EK开发板I2C扩展ADC_ADS1110,cortex a5 linux3.6.9,Device Tree(DTB,FTD)
  8. matlab检验相关性显著性检验,基于matlab的栅格数据相关分析及显著性检验
  9. matlab中单对数函数,matlab对数函数-对数函数,MATLAB
  10. Openlayers 自定义气泡框以及定位到气泡框