什么是 CORS ?一文搞懂 CORS 跨域原理!零基础入门到精通,收藏这一篇就够了

632 篇文章 30 订阅
335 篇文章 0 订阅

在做 Web 开发时,CORS 跨域是我们经常遇到的问题,这篇文章,我们将一起分析什么是 CORS?CORS 的原理是什么?为什么需要 CORS?

1. 什么是 CORS?

CORS,全称为“跨域资源共享”(Cross-Origin Resource Sharing),是一种机制,它使用额外的 HTTP 头来告诉浏览器允许一个网页从另一个域(不同于该网页所在的域)请求资源。这样可以在服务器和客户端之间进行安全的跨域通信。

当一个网页向不同源发出请求时,CORS 会通过以下几个步骤来处理:

  • 预检请求(Preflight Request):对于某些类型的请求(如使用 HTTP 方法 PUT、DELETE,或者请求带有非简单头部),浏览器会首先发送一个 OPTIONS 请求,这个请求称为“预检请求”。服务器收到这个请求后,会返回一个响应头部,指明实际请求是否被允许。

  • 实际请求(Actual Request):如果预检请求通过,浏览器会继续发送实际的请求。

  • 响应头部(Response Headers):服务器在响应中会包含一些特定的 CORS 头部,如 Access-Control-Allow-Origin,以指示哪些域名可以访问资源。

2. 什么是 Origin?

Origin,翻译为 源(域),在 CORS 上下文中 Origin 由三个元素组成:

Origin = 协议 + 域名 + 端口   

协议:例如 http:// 或 https:// 域名:例如 www.yuanjava.com 端口:例如 80(默认 HTTP 端口)、443(默认 HTTPs 端口)

只有上述三个元素都匹配时,我们才会认为两个 URL 具有相同的来源,否则,有任何一个不相同都认为不同源。

3. 同源策略

同源策略(Same-Origin Policy, SOP)是浏览器的一种安全机制,用于防止恶意网站通过脚本对其他网站的内容进行访问。

所谓“同源”,是指协议、域名和端口都相同。比如,以下 URL 属于同源地址:

  • https://yuanjava.com/categories 和 https://yuanjava.com/archives

  • https://yuanjava.com:443 和 https://yuanjava.com:443/interview

4. 跨域请求

跨域请求是指从一个域向另一个域发起的HTTP请求。

在现代 Web 应用中,跨域请求非常常见,比如,从前端应用向不同的后端 API 服务器请求数据,或从一个 Web 服务请求另一个 Web 服务的资源,因为,同源策略默认会阻止这些请求,所以需要 CORS 机制来显式允许跨域访问。

以下 URL 则被认为是跨域请求:

  • http://yuanjava.com 和 https://yuanjava.com(协议不同)

  • http://yuanjava.com 和 http://blog.yuanjava.com(域名不同)

  • http://yuanjava.com:80 和 http://yuanjava.com:8080(端口不同)

下图显示了 CORS 流的主要参与者:

下图展示了浏览器默认允许同源请求,而跨域请求则被阻止:

5. CORS 工作流程

CORS 通过在 HTTP(s) 请求和响应中使用特定的头部字段来实现跨域资源共享,具体来说,CORS 分为两种类型的请求处理方式:简单请求和预检请求。

  • 简单请求:对于某些简单的 HTTP 请求(如GET、POST请求且不包含自定义头部),浏览器会直接发送请求,并在响应中检查 CORS 头部。

  • 预检请求:对于复杂请求(如使用PUT、DELETE方法,或包含自定义头部),浏览器会首先发送一个OPTIONS请求,称为预检请求(Preflight Request),以确定服务器是否允许实际请求。

简单请求

简单请求是指满足以下条件的 HTTP 请求:

  • 使用GET、POST、HEAD方法

  • 请求头部仅包含以下字段:Accept、Accept-Language、Content-Language、Content-Type(且值为application/x-www-form-urlencoded、multipart/form-data或text/plain)

对于简单请求,浏览器会直接发送请求并在响应中检查以下 CORS 头部:

  • Access-Control-Allow-Origin:指示允许访问资源的源。

  • Access-Control-Allow-Credentials:指示是否允许发送凭据(如Cookies)。

  • Access-Control-Expose-Headers:指示哪些头部可以作为响应的一部分被访问。

比如,下面一个示例:

客户端请求:

GET /api/data HTTP/1.1   Host: www.yuanjava.com   Origin: https://yuanjava.com   

服务器响应:

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   Content-Type: application/json      {"message": "Hello, CORS!"}   

预检请求

对于复杂请求,浏览器会首先发送一个 OPTIONS 请求,包含以下头部字段:

  • Origin:指示请求的源。

  • Access-Control-Request-Method:指示实际请求将使用的方法。

  • Access-Control-Request-Headers:指示实际请求将包含的自定义头部。

服务器收到预检请求后,会返回一个响应,包含以下头部字段以指示是否允许请求:

  • Access-Control-Allow-Origin:表明允许访问资源的源,可以是具体的源或通配符 *;

  • Access-Control-Allow-Methods:表明允许的方法,如 GET, POST, PUT, DELETE;

  • Access-Control-Allow-Headers:表明允许的自定义头部;

  • Access-Control-Allow-Credentials:表明是否允许发送凭据(如 Cookies);

  • Access-Control-Expose-Headers:表明哪些头部可以作为响应的一部分被访问;

  • Access-Control-Max-Age:表明预检请求的结果可以被缓存的时间,单位是秒;

如果预检请求通过,浏览器会继续发送实际请求。

比如,下面一个示例:

预检请求:

OPTIONS /api/data HTTP/1.1   Host: api.yuanjava.com   Origin: https://yuanjava.com   Access-Control-Request-Method: PUT   Access-Control-Request-Headers: Content-Type   

预检响应:

HTTP/1.1 204 No Content   Access-Control-Allow-Origin: https://yuanjava.com   Access-Control-Allow-Methods: GET, POST, PUT   Access-Control-Allow-Headers: Content-Type   Access-Control-Allow-Credentials: true   Access-Control-Max-Age: 3600   

实际请求

PUT /api/data HTTP/1.1   Host: api.yuanjava.com   Origin: https://yuanjava.com   Content-Type: application/json      {"data": "example"}   

实际响应:

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   Content-Type: application/json      {"message": "Data updated"}   

6. 如何实现 CORS?

客户端处理

客户端可以向远程服务器发送签名请求。

如下示例代码:在 CORS 请求中以 Authorization 标头的形式发送凭据:

function sendAuthRequestToCrossOrigin() {       var xhr = new XMLHttpRequest();       xhr.onreadystatechange = function() {           if (this.readyState == 4 && this.status == 200) {             document.getElementById("demo").innerHTML = this.responseText;           }       };       xhr.open('GET', "https://yuanjava:8000/categories", true);       xhr.setRequestHeader('Authorization', 'Bearer rtikkjhgffw456tfdd');       xhr.withCredentials = true;       xhr.send();   }   

服务器端处理

方法1:直接采用 SpringBoot 的注解 @CrossOrigin

如下示例代码如下,可以把 @CrossOrigin 加在每个 Controller 上,也可以加在它们的公共父类上:

@CrossOrigin   @RestController   public class TestController extends BaseController {          //  其他逻辑   }   

方法2: 采用过滤器(filter)的方式

如下示例代码:增加一个 CORSFilter 类,并实现 Filter 接口即可。

 `@Component   public class CORSFilter implements Filter {           @Override       public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)               throws IOException, ServletException {           HttpServletResponse res = (HttpServletResponse) response;           res.addHeader("Access-Control-Allow-Credentials", "true");           res.addHeader("Access-Control-Allow-Origin", "*");           res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");           res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");           if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) {               response.getWriter().println("ok");               return;           }           chain.doFilter(request, response);       }       @Override       public void destroy() {       }       @Override       public void init(FilterConfig filterConfig) throws ServletException {       }   }`

方法3: 配置 Configuration

如下示例代码:增加一个配置类继承 WebMvcConfigurerAdapter 或者实现 WebMvcConfigurer 接口,项目启动时,会自动读取配置。

import org.springframework.context.annotation.Configuration;   import org.springframework.web.servlet.config.annotation.CorsRegistry;   import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;   @Configuration   public class CorsConfig extends WebMvcConfigurerAdapter {       static final String ORIGINS[] = new String[]{"GET", "POST", "PUT", "DELETE"};          @Override       public void addCorsMappings(CorsRegistry registry) {           registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS).maxAge(3600);       }   }   

另外,在服务器,可以通过设置响应头部来细粒度配置 CORS,具体的如下:

1.允许所有源访问

HTTP/1.1 200 OK   Access-Control-Allow-Origin: *   

2.允许特定源访问

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   

3.允许凭据请求访问

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   Access-Control-Allow-Credentials: true   

4.允许特定方法和头部

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   Access-Control-Allow-Methods: GET, POST, PUT, DELETE   Access-Control-Allow-Headers: Content-Type, Authorization   

5.设置预检请求的缓存时间

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   Access-Control-Allow-Methods: GET, POST, PUT, DELETE   Access-Control-Allow-Headers: Content-Type, Authorization   Access-Control-Max-Age: 3600  // 3600秒   

通常来说,在服务器解决 CORS是一种比较常见和彻底的方式,我们可以在服务器灵活的设置允许跨域访问的域名或者地址。

7. 常见问题及解决方案

问题1:No ‘Access-Control-Allow-Origin’ header is present on the requested resource

问题描述:当浏览器发起跨域请求时,未在响应中找到 Access-Control-Allow-Origin 头部。

解决方案:确保服务器端正确设置了 Access-Control-Allow-Origin 头部。例如:

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   

问题2:The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’

问题描述:当请求包含凭据时,Access-Control-Allow-Origin 头部不能设置为通配符 *。

解决方案:明确指定允许的源,并确保设置了 Access-Control-Allow-Credentials 头部。例如:

HTTP/1.1 200 OK   Access-Control-Allow-Origin: https://yuanjava.com   Access-Control-Allow-Credentials: true   

问题3:CORS preflight channel did not succeed

问题描述:预检请求失败,可能是由于服务器未正确处理 OPTIONS 请求。

解决方案:确保服务器正确处理 OPTIONS 请求并返回相应的 CORS 头部。例如,在 Node.js/Express 中:

app.options('/api/data', (req, res) => {     res.header('Access-Control-Allow-Origin', 'https://yuanjava.com');     res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');     res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');     res.header('Access-Control-Allow-Credentials', 'true');     res.sendStatus(204);   });   

8. 总结

CORS 是现代 Web 开发中不可或缺的机制,它允许 Web 应用在安全的前提下进行跨域资源请求,通过理解 CORS 的工作原理和配置方法,可以帮助我们有效地解决跨域请求的问题。

`黑客&网络安全如何学习

今天只要你给我的文章点赞,我私藏的网安学习资料一样免费共享给你们,来看看有哪些东西。

1.学习路线图

攻击和防守要学的东西也不少,具体要学的东西我都写在了上面的路线图,如果你能学完它们,你去就业和接私活完全没有问题。

2.视频教程

网上虽然也有很多的学习资源,但基本上都残缺不全的,这是我自己录的网安视频教程,上面路线图的每一个知识点,我都有配套的视频讲解。

内容涵盖了网络安全法学习、网络安全运营等保测评、渗透测试基础、漏洞详解、计算机基础知识等,都是网络安全入门必知必会的学习内容。

(都打包成一块的了,不能一一展开,总共300多集)

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

3.技术文档和电子书

技术文档也是我自己整理的,包括我参加大型网安行动、CTF和挖SRC漏洞的经验和技术要点,电子书也有200多本,由于内容的敏感性,我就不一一展示了。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

4.工具包、面试题和源码

“工欲善其事必先利其器”我为大家总结出了最受欢迎的几十款款黑客工具。涉及范围主要集中在 信息收集、Android黑客工具、自动化工具、网络钓鱼等,感兴趣的同学不容错过。

还有我视频里讲的案例源码和对应的工具包,需要的话也可以拿走。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

最后就是我这几年整理的网安方面的面试题,如果你是要找网安方面的工作,它们绝对能帮你大忙。

这些题目都是大家在面试深信服、奇安信、腾讯或者其它大厂面试时经常遇到的,如果大家有好的题目或者好的见解欢迎分享。

参考解析:深信服官网、奇安信官网、Freebuf、csdn等

内容特点:条理清晰,含图像化表示更加易懂。

内容概要:包括 内网、操作系统、协议、渗透测试、安服、漏洞、注入、XSS、CSRF、SSRF、文件上传、文件下载、文件包含、XXE、逻辑漏洞、工具、SQLmap、NMAP、BP、MSF…

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取

CSDN大礼包:《黑客&网络安全入门&进阶学习资源包》免费分享

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值