Spring Security(学习笔记)--漏洞保护(csrf攻击与防御以及源码分析)!

news2024/11/23 6:28:59

重点标识

csrf 攻击防御演示!

源码分析!

CSRF攻击与防御

CSRF是什么 ,跨站请求伪造,简单解释一下,就是用户登录某个界面,如银行界面,进行转账,完了之后并没有注销登录,而是打开一新的页面,在页面上点击了某个攻击者设下的链接,那么这个链接,就可以带着浏览器存储的cookie,发送给银行服务器,由于已经认证过了,所以银行服务器以为是用户自己的操作,就达成了攻击者的目的。

csrf攻击演示

首先,创建一个Spring Boot工程,加入web和Security依赖:

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

然后,简单配置一下,生成一个账号,以及关闭Security自带的对CSRF的防御。


@Configuration
public class Security {


    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a->a.anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                .csrf(c->c.disable());

        return http.build();
    }


    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {

        return new InMemoryUserDetailsManager(
                User.withUsername("admin").password("{noop}123").roles().build()
               );
    }
}

再提供一个测试的接口和界面:


@RestController
public class WithDrawController {

    @PostMapping("/withdraw")
    public void withdraw(String from,String to,String amount) {
        System.out.println("执行了一次转账操作!");
        System.out.println("from:"+from);
        System.out.println("to:"+to);
        System.out.println("amount:"+amount);
    }
}

测试界面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/withdraw" method="post">

     <tr>
         <td>转出账户</td>
         <td><input type="text" name="from" value="zhangsan"></td>
     </tr>
    <tr>
         <td>转入账户</td>
         <td><input type="text" name="to" value="lisi"></td>
     </tr>   <tr>
         <td>转入金额</td>
         <td><input type="text" name="amount" value="1000"></td>
     </tr>

    <tr>

        <td><input type="submit" value="转账"></td>
    </tr>

</form>
</body>
</html>

然后,创建第二个攻击者的项目,这次只需要加一个web依赖就行,改一下端口号:

server.port=8081

然后,提供一个具备诱惑力的界面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="http://localhost:8080/withdraw" method="post">

     <tr>

         <td><input type="hidden" name="from" value="zhangsan"></td>
     </tr>
    <tr>

         <td><input type="hidden" name="to" value="lisi"></td>
     </tr>   <tr>

         <td><input type="hidden" name="amount" value="1000"></td>
     </tr>

    <tr>

        <td><input type="submit" value="我是一张非常有诱惑力的图片"></td>
    </tr>

</form>
</body>
</html>

启动项目,如此便可以测试了。

我们登录第一个项目,然后点击转账,后台会出现模拟转账的打印,然后,进入第二个项目的界面,直接点那张具备诱惑力的图片,然后,就会发现,项目一,依然打印了转账的操作日志,这个就是跨站请求伪造。

本质上,就是浏览器自动携带cookie信息,攻击者的界面携带者被攻击者已经认证过的cookie,j进行了一次伪造操作。

Security提供的csrf防御

如果使用Security默认的防御策略,则就是这个样子,403.
· .csrf(Customizer.withDefaults());·

在这里插入图片描述
他的解决思路,其实很简单,除了携带cookie之外,额外需要一个令牌,有令牌才通过,没有令牌就不通过。

在这里插入图片描述
可以看到,登陆界面,多了一个隐藏的csrf令牌。
这样的话,就可以保证它的安全性了,但是这样,又产生了一个新的问题,我们自己的页面,也无法转账了,这是因为没有这个csrf的值。

有两种方案将csrf放到我们的页面中,第一种

使用thymeleaf模板

加一下依赖:

   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

增加一个接口

@GetMapping("/02")
    public String index() {
        return "02";
    }

在templates下面,创建一个html和上一个相比,就多了个csrf令牌;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/withdraw" method="post">

     <tr>
         <td>转出账户</td>
         <td><input type="text" name="from" value="zhangsan"></td>
     </tr>
    <tr>
         <td>转入账户</td>
         <td><input type="text" name="to" value="lisi"></td>
     </tr>   <tr>
         <td>转入金额</td>
         <td><input type="text" name="amount" value="1000"></td>
     </tr>

    <tr>
       <input type="hidden" name="${_csrf.parameterName}" th:value="${_csrf.token}">
        <td><input type="submit" value="转账"></td>
    </tr>

</form>
</body>
</html>

在这里插入图片描述

模板会自动将csrf令牌渲染上去,这样,攻击者自然就拿不到了,这是第一种方法,但是,如果不想使用thymeleaf,也可以使用第二种。

令牌存储器

 @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a->a.anyRequest().authenticated())
                .formLogin(Customizer.withDefaults())
                //设置令牌存储方式,将令牌存储在cookie中    
                .csrf(c-> c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));

        return http.build();
    }


这样存储下,后,我们在启动就可以看到在请求头中就会多出这样一个东西
XSRF-TOKEN=3fb8cd4e-69dd-4a4f-8527-91b6405ed7b8

这个cookie就是为了防御csrf攻击生成的令牌,请求参数中要携带着它,才能正常访问。我们知道,csrf说白了,就是利用浏览器不区分cookie的特点,全部一股脑地,发送给服务器,开启了令牌存储,httponly只读设置为false,则就能从cookie中获取到令牌的信息的加以处理了。

至于令牌的信息会不会被盗用,这又是另一个漏洞。

源码分析

看一下CsrfFilter过滤器,在它的doFilterInternal中执行了具体的逻辑。

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
			//返回的数据加上csrf
		DeferredCsrfToken deferredCsrfToken = this.tokenRepository.loadDeferredToken(request, response);
		request.setAttribute(DeferredCsrfToken.class.getName(), deferredCsrfToken);
		this.requestHandler.handle(request, response, deferredCsrfToken::get);
		//查看当前请求是否满足csrf保护,我们知道GET请求是不涉及CSRF的  登录请求直接从这里就走了
		if (!this.requireCsrfProtectionMatcher.matches(request)) {
			if (this.logger.isTraceEnabled()) {
				this.logger.trace("Did not protect against CSRF since request did not match "
						+ this.requireCsrfProtectionMatcher);
			}
			filterChain.doFilter(request, response);
			return;
		}
//拿到令牌,进行验证!
		CsrfToken csrfToken = deferredCsrfToken.get();
		String actualToken = this.requestHandler.resolveCsrfTokenValue(request, csrfToken);
		if (!equalsConstantTime(csrfToken.getToken(), actualToken)) {
			boolean missingToken = deferredCsrfToken.isGenerated();
			this.logger
				.debug(LogMessage.of(() -> "Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)));
			AccessDeniedException exception = (!missingToken) ? new InvalidCsrfTokenException(csrfToken, actualToken)
					: new MissingCsrfTokenException(actualToken);
			this.accessDeniedHandler.handle(request, response, exception);
			return;
		}
		filterChain.doFilter(request, response);
	}

看下这个handle方法,很简单csrfRequestAttributeName 是不是空的,不是就用自定义的,没有自定义,则使用默认的,也就是this.csrfRequestAttributeName
private String csrfRequestAttributeName = "_csrf";

public void handle(HttpServletRequest request, HttpServletResponse response,
			Supplier<CsrfToken> deferredCsrfToken) {
		Assert.notNull(request, "request cannot be null");
		Assert.notNull(response, "response cannot be null");
		Assert.notNull(deferredCsrfToken, "deferredCsrfToken cannot be null");

		request.setAttribute(HttpServletResponse.class.getName(), response);
		CsrfToken csrfToken = new SupplierCsrfToken(deferredCsrfToken);
		request.setAttribute(CsrfToken.class.getName(), csrfToken);
		String csrfAttrName = (this.csrfRequestAttributeName != null) ? this.csrfRequestAttributeName
				: csrfToken.getParameterName();
		request.setAttribute(csrfAttrName, csrfToken);
	}

key为_csrf,value则为CsrfToken对象

public interface CsrfToken extends Serializable {

	/**
	 * Gets the HTTP header that the CSRF is populated on the response and can be placed
	 * on requests instead of the parameter. Cannot be null.
	 * @return the HTTP header that the CSRF is populated on the response and can be
	 * placed on requests instead of the parameter
	 */
	String getHeaderName();

	/**
	 * Gets the HTTP parameter name that should contain the token. Cannot be null.
	 * @return the HTTP parameter name that should contain the token.
	 */
	String getParameterName();

	/**
	 * Gets the token value. Cannot be null.
	 * @return the token value
	 */
	String getToken();

}

就是在这里渲染了csrf。

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

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

相关文章

Scrapy 爬虫教程:从原理到实战

Scrapy 爬虫教程&#xff1a;从原理到实战 一、Scrapy框架简介 Scrapy是一个由Python开发的高效网络爬虫框架&#xff0c;用于从网站上抓取数据并提取结构化信息。它采用异步IO处理请求&#xff0c;能够同时发送多个请求&#xff0c;极大地提高了爬虫效率。 二、Scrapy运行原…

蒸镀的氧化硅薄膜为什么有时候是绿色有时候是棕色的?

知识星球&#xff08;星球名&#xff1a;芯片制造与封测社区&#xff0c;星球号&#xff1a;63559049&#xff09;里的学员问&#xff1a;我们用热阻式蒸镀设备镀氧化硅薄膜&#xff0c;出来的颜色有时候会发生变化是什么原因呀&#xff1f;有时候薄膜是绿色有时候是棕色。 氧…

Excel 中用于在一个范围中查找特定的值,并返回同一行中指定列的值 顺序不一样 可以处理吗

一、需求 Excel 中&#xff0c;在一列&#xff08;某范围内&#xff09;查找另一列特定的值&#xff0c;并返回同一行中另一指定列的值&#xff0c; 查找列和返回列的顺序不一样 二、 实现 1、下面是一个使用 INDEX 和 MATCH 函数的例子&#xff1a; 假设你有以下数据&…

网络服务SSH-远程访问及控制

一.SSH远程管理 1.SSH介绍 SSH&#xff08;Secure Shell&#xff09;是一种安全通道协议&#xff0c;最早是由芬兰的一家公司开发出来&#xff0c;并且在IETF &#xff08;Internet Engineering Task Force&#xff09;的网络草案基础上制定而成的标准协议。主要用来实现字符…

深度学习pytorch实战-运动鞋识别P5周

向大佬学习大地之灯第P5周&#xff1a;Pytorch实现运动鞋识别http://t.csdnimg.cn/eVVAG >- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a…

MySQL8.0新特性

1、新增降序索引 MySQL 5.7&#xff1a;在语法上支持降序索引&#xff0c;但实际上创建的仍然是升序索引 MySQL 8.0&#xff1a;真正支持降序索引&#xff08;只有Innodb存储引擎支持降序索引&#xff09; # MySQL 5.7演示 mysql> create table t1(c1 int,c2 int,index i…

pytest教程-34-钩子函数-pytest_configure

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了pytest_addoption钩子函数的使用方法&#xff0c;本小节我们讲解一下pytest_configure钩子函数的使用方法。 pytest_configure(config) 是一个 pytest 钩子函数&#xff0c;它在 pytest 配置完…

资产管理软件价格 一套固定资产管理系统多少钱

固定资产管理系统作为一款帮助工厂、事业单位、政府机关等企业管理资产设备的管理工具&#xff0c;其实&#xff0c;一直在向企业提供着各种相关的服务&#xff0c;对于才接触固定资产管理系统的朋友们来说&#xff0c;首先想要了解的这个付费工具的收费问题&#xff0c;那这个…

关于谷歌浏览器对于https的证书不通过校验的无法跳转的问题

谷歌浏览器对于https的证书问题会出现如下提示: 解决方法: 直接在页面输入 thisisunsafe 就能跳转了.

精彩回顾|从 AI 到银幕:顶尖对话揭秘 AI 如何塑造影视新格局

4月17日&#xff0c;由万合天宜、三次元影业、NOVATECH、微软中国极客天团、微软 Reactor 共同推出的「从 AI 到银幕」顶尖对话在上海微软紫竹园区举办。中国内地著名导演、编剧、监制黄建新&#xff0c;微软&#xff08;中国&#xff09;有限公司首席技术官韦青&#xff0c;与…

孕线反转形态,Anzo Capital10年交易经验一眼看穿

很多投资者都知道Inside-bar孕线是一种很好的反转信号&#xff0c;但是不了解Inside-bar孕线如何一眼发现孕线反转形态&#xff0c;今天Anzo Capital昂首资本平台上的10年交易者进行免费分享&#xff0c;希望各位投资者能够一眼看穿孕线反转形态: 首先各位投资者发散一下思维&…

美国站群服务器上常见的操作系统选择指南

美国站群服务器上常见的操作系统选择指南 美国站群服务器的选择操作系统对于服务器的性能和功能至关重要。本文将为您介绍在美国站群服务器上常见的操作系统选择指南&#xff0c;以帮助您做出明智的决策。 在选择美国站群服务器时&#xff0c;选择合适的操作系统是至关重要的…

Qt QLineEdit详解

1.简介 QLineEdit是一个单行文本编辑器。 行编辑允许用户使用一组有用的编辑功能输入和编辑单行纯文本&#xff0c;包括撤消和重做、剪切和粘贴以及拖放。 通过更改行编辑的echoMode&#xff0c;它也可以用作“只写”字段&#xff0c;用于密码等输入。 文本的长度可以限制为ma…

【每日刷题】Day28

【每日刷题】Day28 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; ​ 1. 121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 2. 205. 同构字符串 - 力扣…

充电桩---ISO15118协议详细介绍

一、ISO15118介绍 1、发展背景 标准于 2010 年由国际标准化组织&#xff08;ISO&#xff09;和国际电工委员会&#xff08;IEC&#xff09;通过&#xff0c;电动汽车和充电站之间的通信&#xff0c;改善了不同品牌、型号和充电类型&#xff08;交流或直流&#xff09;之间的互…

React配置@别名路径配置

1. 背景知识 路径解析配置&#xff08;webpack&#xff09;&#xff0c;把 / 解析为 src/路径联想配置&#xff08;VsCode&#xff09;&#xff0c;VsCode 在输入 / 时&#xff0c;自动联想出来对应的 src/下的子级目录 2. 路径解析配置 配置步骤&#xff1a; 安装craco npm …

K8s: Prometheus 服务结构以及基础抓取数据服务部署

Prometheus 发布应用之后&#xff0c;就有持续运维的事情&#xff0c;就是平台监控Prometheus 是一个云原生的日志监控平台&#xff0c;是一个实时标准的一个技术它是著名的 cncf 里的一个重要的开源项目 上面整个图片是在云原生应用及K8s应用架构下的一个日志监控的一个标准的…

用数据说话,还你一个SSD和HDD的真相

【全球存储观察 &#xff5c; 热点关注】在全球数据存储领域&#xff0c;NAND盖楼大赛从来就没有消停过&#xff0c;为什么&#xff1f; 纵观全球NAND主流供应商&#xff0c;三星电子、铠侠、美光科技、SK海力士等&#xff0c;基于自己在闪存技术积累与创新&#xff0c;纷纷热…

nginx--安装

yum安装 官方包链接&#xff1a;nginx: Linux packages 官方yum源链接&#xff1a;nginx: Linux packages 配置yum源 [rootlocalhost ~]# yum install -y nginx [nginx-stable] namenginx stable repo baseurlhttp://nginx.org/packages/centos/$releasever/$basearch/ gp…

【论文阅读】ELAN-Efficient Long-Range Attention Network for Image Super-resolution

ELAN-Efficient Long-Range Attention Network for Image Super-resolution 论文地址简介1 引言2相关工作2.1 基于 CNN 的 SR 方法2.2 基于 Transformer 的 SR 方法 3 方法论3.1 ELAN 的整体流程3.2 Efficient Long-range Attention Block (ELAB) 4实验4.1实验设置4.2 与轻量级…