SpringSecurity源码学习五:跨域与跨站请求伪造

目录

  • 什么是跨域
  • springboot是怎么解决跨域问题
  • 在springSecurity中怎么解决跨域问题
  • CORS源码
  • 跨域请求伪造CSRF
  • CSRF源码
  • 总结

什么是跨域

跨域是指在网络中,当一个网页的资源(如字体、脚本或样式表)尝试从不同的域名、端口或协议请求数据时,会遇到安全限制问题。这是由于浏览器的同源策略所导致的。同源策略要求网页只能从同一域名下加载资源,而跨域请求则违反了这个策略。

为了解决跨域问题,可以采取一些方法,如使用JSONP、CORS、代理服务器等。JSONP是通过动态创建

总结起来,跨域是指在网络中由于浏览器的同源策略而限制了不同域名、端口或协议之间的资源请求。通过使用适当的跨域解决方案,可以允许跨域请求并获取所需的数据。一般情况下我们呢都是使用CORS(跨域资源共享)来解决跨域问题。

springboot是怎么解决跨域问题

在Java中,可以使用CORS(跨域资源共享)来解决跨域问题。下面是一个Java代码示例,演示如何在Spring Boot应用程序中配置CORS。

首先,在Spring Boot应用程序的配置类中添加以下代码:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class CorsConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("http://example.com")  // 允许的跨域请求来源.allowedMethods("GET", "POST")  // 允许的请求方法.allowedHeaders("Origin", "Content-Type", "Accept")  // 允许的请求头.allowCredentials(true);  // 允许发送身份凭证}
}

在上述代码中,我们通过 addMapping() 方法指定了允许跨域请求的路径,使用 allowedOrigins() 方法指定了允许的跨域请求来源,使用 allowedMethods() 方法指定了允许的请求方法,使用 allowedHeaders() 方法指定了允许的请求头。最后,通过 allowCredentials(true) 方法允许发送身份凭证(如Cookie)。

以上只是个代码示例,实际使用时要根据具体情况做响应配置。

在springSecurity中怎么解决跨域问题

在Spring Security中,你可以使用 CorsConfigurationSource 接口来配置CORS(跨域资源共享)策略。下面是一个Java代码示例,演示如何在Spring Security中配置CORS。
首先,在你的Spring Security配置类中添加以下代码:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors();// ...}@Beanpublic CorsConfigurationSource corsConfigurationSource() {CorsConfiguration configuration = new CorsConfiguration();configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));configuration.setAllowedMethods(Arrays.asList("GET", "POST"));configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", configuration);return source;}
}

在上述代码示例中,我们通过调用 http.cors()> 方法来允许跨域请求。然后,我们定义了一个 CorsConfigurationSource 的Bean,用于配置CORS策略。在这个Bean中,我们设置了允许的跨域请求来源、允许的请求方法和请求头。

最后,我们使用 UrlBasedCorsConfigurationSource 类来注册CORS配置,并将其应用于所有的请求路径( /** )。

CORS源码

源码入口:

	public CorsConfigurer<HttpSecurity> cors() throws Exception {return getOrApply(new CorsConfigurer<>());}private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(C configurer)throws Exception {C existingConfig = (C) getConfigurer(configurer.getClass());if (existingConfig != null) {return existingConfig;}//执行configurerreturn apply(configurer);}

可以看到最终就是获取一个CorsConfigurer类,我们看CorsConfigurer类的逻辑。主要看CorsConfigurer类的configure()方法

	@Overridepublic void configure(H http) {ApplicationContext context = http.getSharedObject(ApplicationContext.class);//获取corsFilter过滤器CorsFilter corsFilter = getCorsFilter(context);Assert.state(corsFilter != null, () -> "Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");//把corsFilter过滤器添加到过滤器链中http.addFilter(corsFilter);}

获取corsFilter过滤器并把它添加到过滤器链中。看getCorsFilter(context)方法

	private CorsFilter getCorsFilter(ApplicationContext context) {if (this.configurationSource != null) {return new CorsFilter(this.configurationSource);}//corsFilter过滤器bean是否存在boolean containsCorsFilter = context.containsBeanDefinition(CORS_FILTER_BEAN_NAME);if (containsCorsFilter) {return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);}//corsConfigurationSource对象是否存在boolean containsCorsSource = context.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);if (containsCorsSource) {//把corsConfigurationSource对象塞进CorsFilter过滤器中CorsConfigurationSource configurationSource = context.getBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME,CorsConfigurationSource.class);return new CorsFilter(configurationSource);}boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, context.getClassLoader());if (mvcPresent) {return MvcCorsFilter.getMvcCorsFilter(context);}return null;}

可以看到,对应cors处理有两种情况,

  1. 没有配置corsConfigurationSource对象,直接使用默认的corsFilter过滤器
  2. 配置corsConfigurationSource对象,把配置corsConfigurationSource对象添加到默认的过滤器。

最后是调用的springWeb的CorsFilter,并把此过滤器加入到SpringSecurity过滤器链中。

跨域请求伪造CSRF

跨域请求伪造(Cross-Site Request Forgery,CSRF)是一种安全漏洞,攻击者利用该漏洞通过伪造请求来执行未经授权的操作。在CSRF攻击中,攻击者诱使受害者在已登录的状态下访问恶意网站,从而触发受害者在其他网站上的操作,如转账、更改密码等。

在前后端分离的架构中,可以使用CSRF令牌(CSRF Token)来验证请求的合法性。下面是一个使用Spring Security防止CSRF攻击的Java代码示例:

  1. 配置Spring Security启用CSRF保护:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http// 其他Spring Security配置.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());}
}
  1. 在前端页面中设置CSRF令牌:
html
<html>
<body><form method="post" action="/submit"><input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /><!-- 其他表单字段 --><button type="submit">提交</button></form>
</body>
</html>

在上述示例中,首先通过 csrf() 方法启用了CSRF保护,并使用 CookieCsrfTokenRepository 来存储CSRF令牌。然后,在前端页面的表单中,通过 ${_csrf.parameterName} 和 ${_csrf.token} 获取CSRF令牌,并将其作为隐藏字段传递给服务器。

这样,在每次提交表单时,CSRF令牌会被包含在请求中,服务器会验证请求中的CSRF令牌是否与服务器生成的令牌匹配,从而防止CSRF攻击的发生。

CSRF源码

代码入口:

	public CsrfConfigurer<HttpSecurity> csrf() throws Exception {ApplicationContext context = getContext();return getOrApply(new CsrfConfigurer<>(context));}private <C extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity>> C getOrApply(C configurer)throws Exception {C existingConfig = (C) getConfigurer(configurer.getClass());if (existingConfig != null) {return existingConfig;}//执行configurerreturn apply(configurer);}

主要是看CsrfConfigurer这个类

public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>extends org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer<CsrfConfigurer<H>, H> {//初始化CsrfTokenRepository,默认为LazyCsrfTokenRepositoryprivate CsrfTokenRepository csrfTokenRepository = new LazyCsrfTokenRepository(new HttpSessionCsrfTokenRepository());

默认是使用LazyCsrfTokenRepository,并使用HttpSessionCsrfTokenRepository初始化。接下俩看CsrfConfigurer的configure方法。

	@Overridepublic void configure(H http) {//初始化CsrfFilter过滤器CsrfFilter filter = new CsrfFilter(this.csrfTokenRepository);RequestMatcher requireCsrfProtectionMatcher = getRequireCsrfProtectionMatcher();if (requireCsrfProtectionMatcher != null) {filter.setRequireCsrfProtectionMatcher(requireCsrfProtectionMatcher);}AccessDeniedHandler accessDeniedHandler = createAccessDeniedHandler(http);if (accessDeniedHandler != null) {filter.setAccessDeniedHandler(accessDeniedHandler);}org.springframework.security.config.annotation.web.configurers.LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(org.springframework.security.config.annotation.web.configurers.LogoutConfigurer.class);if (logoutConfigurer != null) {logoutConfigurer.addLogoutHandler(new CsrfLogoutHandler(this.csrfTokenRepository));}org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer<H> sessionConfigurer = http.getConfigurer(org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer.class);if (sessionConfigurer != null) {sessionConfigurer.addSessionAuthenticationStrategy(getSessionAuthenticationStrategy());}filter = postProcess(filter);//加载到过滤器链中http.addFilter(filter);}

这段很简单,初始化CsrfFilter,并把CsrfFilter添加到过滤器链中。

在LazyCsrfTokenRepository中,就是对CsrfToken的操作

public interface CsrfTokenRepository {/*** Generates a {@link CsrfToken}* @param request the {@link HttpServletRequest} to use* @return the {@link CsrfToken} that was generated. Cannot be null.*/CsrfToken generateToken(HttpServletRequest request);/*** Saves the {@link CsrfToken} using the {@link HttpServletRequest} and* {@link HttpServletResponse}. If the {@link CsrfToken} is null, it is the same as* deleting it.* @param token the {@link CsrfToken} to save or null to delete* @param request the {@link HttpServletRequest} to use* @param response the {@link HttpServletResponse} to use*/void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response);/*** Loads the expected {@link CsrfToken} from the {@link HttpServletRequest}* @param request the {@link HttpServletRequest} to use* @return the {@link CsrfToken} or null if none exists*/CsrfToken loadToken(HttpServletRequest request);}

具体的实现类就不展开说,感兴趣的可自行查看代码。

总结

  1. 跨域问题:当前端应用和后端API不在同一个域下时,浏览器会限制跨域请求。为了解决跨域问题,可以在后端配置允许跨域请求的头信息,如Access-Control-Allow-Origin。
  2. CSRF保护:跨站请求伪造(CSRF)是一种安全漏洞,攻击者利用用户在其他网站上的身份信息发起恶意请求。为了防止CSRF攻击,可以在Spring Security中启用CSRF保护。通过生成和验证CSRF令牌,确保请求的合法性。
    • 在后端配置中启用CSRF保护,并指定CSRF令牌的存储方式,如CookieCsrfTokenRepository。
    • 在前端发起请求时,将CSRF令牌作为请求的参数或头信息的一部分发送给后端。
    • 后端服务器验证请求中的CSRF令牌是否与服务器生成的令牌匹配,以确保请求的合法性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/114080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HOT100自查题集

前言 遗忘是人类的本能&#xff0c;经常自查是必不可少的。现在面试手撕已经是必备项目&#xff0c;手撕题目大部分来自于力扣 HOT100 以及对应方向的一些编码题。我对 HOT 100 的题目以及Java相关的一些编码题目进行了分类整理&#xff0c;并提供解题思路&#xff0c;用作复习…

Git的介绍和命令汇总

目录 一、git介绍 1、git的工作区域 2、git中文件的四种状态 二、常用命令 1、基础命令 2、提交类命令 3、删除类命令 4、分支类相关命令 5、 查看类相关命令 6、撤销类命令 一、git介绍 1、git的工作区域 在Git中&#xff0c;有四个工作区域&#xff1a;工作区域&am…

ubuntu20.4 执行sudo apt-get update出现错误 libnettle.so.6 动态链接库错误

一、错误描述 sudo apt-get update 报错提示 libnettle.so.6 动态链接库错误 $ sudo apt update /usr/lib/apt/methods/https: error while loading shared libraries: libnettle.so.6: cannot open shared object file: No such file or directory /usr/lib/apt/methods/ht…

【计算机网络】(面试问题)路由器与交换机的比较

路由器与交换机比较 内容主要参考总结自《计算机网络自顶向下第七版》P315 两者均为存储-转发设备: 路由器: 网络层设备 (检测网络层分组首部) 交换机: 链路层设备 (检测链路层帧的首部) 二者均使用转发表: 路由器: 利用路由算法(路由协议)计算(设置), 依据IP地址 交换机…

CorelDRAW Graphics Suite2024完整版最新功能介绍

CorelDRAW平面设计软件通常也被叫做CDR&#xff0c;CDR广泛应用于排版印刷、矢量图形编辑及网页设计等领域。通过CorelDRAW体验极具个性的自由创作&#xff0c;大胆展现真我&#xff0c;交付出众的创意作品。CorelDRAW拥有矢量插图、页面布局、图片编辑和设计工具&#xff0c;无…

迅为RK3568开发板RTMP推流之视频监控

1 搭建 RTMP 媒流体服务器 nginx-rtmp 是一个基于 nginx 的 RTMP 服务模块&#xff0c;是一个功能强大的流媒体服务器模块&#xff0c; 它提供了丰富的功能和灵活的配置选项&#xff0c;适用于构建各种规模的流媒体平台和应用。无论是搭建实时视频直播平台、点播系统或多屏互…

深、浅拷贝之间的关系

深、浅拷贝之间的关系 什么是赋值 赋值是将某一数值或对象赋给某个变量的过程&#xff0c;分为下面 2 部分 基本数据类型&#xff1a;赋值&#xff0c;赋值之后两个变量互不影响引用数据类型&#xff1a;赋址&#xff0c;两个变量具有相同的引用&#xff0c;指向同一个对象&…

leetcode 114. 二叉树展开为链表

2023.10.22 本题第一反应就是将 原二叉树的节点值 用先序遍历的方式保存到一个集合数组中。然后再重新构造出新的二叉树。 java代码如下&#xff1a; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode rig…

我国跨境电商行业研究报告(2022)

我国跨境电商行业研究报告 我国跨境电商规模突飞猛进&#xff0c;2022年进出口规模超2万亿元&#xff0c;2023年上半年跨境电商出口8210亿元&#xff0c;增长19.9%。全国跨境电商主体已超10万家&#xff0c;近年来涌现出一批上市公司&#xff0c;以及广州希音等全球独角兽企业。…

Ubuntu安装git方法

Ubuntu安装git方法 1、更新软件包列表 sudo apt-get update目的&#xff1a;更新本地的软件源头&#xff0c;以便于从最新的软件源头下载最新的软件包 2、安装git sudo apt-get install gitubuntu会检查所需要的软件包及其依赖项&#xff0c;并自动下载安装他们。 3、验证Gi…

curl命令服务器上执行http请求

1. 现在本地使用postman生成curl命令 注意: 将ip改成127.0.0.1,端口是实际服务运行的端口 curl --location --request POST http://127.0.0.1:63040/content/course/list?pageNo1&pageSize2 \ --header Content-Type: application/json \ --data-raw {"courseName&q…

GO学习之 goroutine的调度原理

GO系列 1、GO学习之Hello World 2、GO学习之入门语法 3、GO学习之切片操作 4、GO学习之 Map 操作 5、GO学习之 结构体 操作 6、GO学习之 通道(Channel) 7、GO学习之 多线程(goroutine) 8、GO学习之 函数(Function) 9、GO学习之 接口(Interface) 10、GO学习之 网络通信(Net/Htt…

JavaSE入门---掌握面向对象三大特性:封装、继承和多态

文章目录 封装什么是封装&#xff1f;如何实现封装&#xff1f; 继承什么是继承&#xff1f;继承的语法父类成员访问子类访问父类的成员变量子类访问父类的成员方法 认识super关键字认识final关键字子类的构造方法super VS this在继承关系中各代码块的执行顺序是怎样的&#xf…

数据可视化与GraphQL:利用Apollo创建仪表盘

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

YOLO目标检测——人脸识别数据集【对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;安全监控、智能驾驶、人机交互、人脸门禁、人脸支付、人脸搜索数据集说明&#xff1a;人脸识别数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;含有人脸图片标签说明&#xff1a;使用lableimg标注软件标注&#xff0…

OSG嵌入QT的简明总结2

正文 我之前在这篇博文《OSG嵌入QT的简明总结》中论述了OSG在QT中显示的可视化问题。其中提到官方提供的osgQt项目&#xff08;地址&#xff1a;https://github.com/openscenegraph/osgQt &#xff09;很久前已经更新了。但是我一直没有时间同步更新&#xff0c;最近重新尝试了…

PHP 基础

PHP 基础 概述 在PHP 文件中&#xff0c;可以与HTML 和JavaScript 混编。 开始标记<?php 表示进入PHP 模式&#xff0c;结束标记?>&#xff0c;标识退出PHP 模式。 PHP 模式之外的内容会被作为字符输出到浏览器中。 PHP 在服务端执行&#xff0c;HTML 和 JS 在浏览…

vim的使用以及配置

vim的使用以及配置 vim的介绍vim的使用vim的三种模式vim的三种模式的转换方式三个模式的运用命令模式插入模式底行模式 vim的配置vim一键配置命令 vim的介绍 百度官方介绍&#xff1a; Vim是一个类似于Vi的著名的功能强大、高度可定制的文本编辑器&#xff0c;在Vi的基础上改进…

【iOS】UITableView总结(Cell的复用原理、自定义Cell、UITableViewCell协议方法)

UITableView 列表的特点&#xff1a; 数据量大样式较为统一通常需要分组垂直滚动通常可视区只有一个 -> 视图的复用 UITableViewDataSource UITableView作为视图&#xff0c;只负责展示&#xff0c;协助管理&#xff0c;不管理数据 需要开发者为UITableView提供展示所需…

登上抖音热搜榜:如何让你的内容火爆全网

在当今信息爆炸的时代&#xff0c;抖音已经成为了很多人获取信息、娱乐和社交的重要平台。每一天&#xff0c;都有大量的短视频在抖音上诞生&#xff0c;然而&#xff0c;只有少数幸运儿能够登上抖音热搜榜&#xff0c;成为万人瞩目的焦点。那么&#xff0c;如何让你的内容火爆…