2-SpringSecurity:CSRF攻击

简介: 2-SpringSecurity:CSRF攻击

背景


本系列教程,是作为团队内部的培训资料准备的。主要以实验的方式来体验SpringSecurity的各项Feature。


实验0:SpringSecurity默认开启CSRF防护


现在我们在springboot-security项目的HelloController.java中新增一个POST接口:/ok

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        return "hello springsecurity";
    }
    @PostMapping("/ok")
    public String ok(){
        return "ok";
    }
}

当然这个POST接口无法直接在浏览器中发起请求,我们需要借助PostMan来实现POST请求的发送。把浏览器中的Cookie复制到PostMan中。


  • 先发GET /hello,正常

image.png

  • 再发POST /ok,403了。。

image.png

那么,问题来了,两个请求都是在登录状态下进行的,为什么GET成功,POST返回403了?


其实SpringSecurity默认就开启了CSRF防护,这在上一篇及官网中关于SpringBoot自动配置项那里可以看到。并且SpringSecurity默认忽略"GET", "HEAD", "TRACE", "OPTIONS"等请求,源码如下:

/**
 * Specify the {@link RequestMatcher} to use for determining when CSRF should be
 * applied. The default is to ignore GET, HEAD, TRACE, OPTIONS and process all other
 * requests.
 *
 * @param requireCsrfProtectionMatcher the {@link RequestMatcher} to use
 * @return the {@link CsrfConfigurer} for further customizations
 */
public CsrfConfigurer<H> requireCsrfProtectionMatcher(
        RequestMatcher requireCsrfProtectionMatcher) {
    Assert.notNull(requireCsrfProtectionMatcher,
            "requireCsrfProtectionMatcher cannot be null");
    this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
    return this;
}
private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
    private final HashSet<String> allowedMethods = new HashSet<>(
            Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
    /*
     * (non-Javadoc)
     *
     * @see
     * org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.
     * servlet.http.HttpServletRequest)
     */
    @Override
    public boolean matches(HttpServletRequest request) {
        return !this.allowedMethods.contains(request.getMethod());
    }
}


实验1:CSRF GET攻击


CSRF: Cross-Site Request Forgery 跨站请求伪造。一些网站比如知乎、简书中的外部链接,点击之后会有提示(免责声明),此操作有风险是否继续,这便与CSRF密切相关。

image.png

结合上篇文章,新建一个SpringBoot项目,起名spring-security-csrf,核心依赖为WebThymeleaf,模拟一个钓鱼网站。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

建好项目后,创建一个简单的HelloController.java,包含一个/GET请求,返回一个页面index.html:


  • 后端接口
@Controller
public class HelloController {
    @RequestMapping("/")
    public String hello(){
        return "index";
    }
}
  • 前端模板
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
Fishing: <img src="http://hello:8080/hello">
</body>
</html>

Note:


  • 以下步骤在Firefox浏览器完成;


  • 修改springboot-security的后端接口,增加输出打印,方便后续确定请求是否进入后端;
@RestController
@Slf4j
public class HelloController {
    @GetMapping("/hello")
    public String hello(){
        log.info("Hello ");
        return "hello";
    }
    @PostMapping("/ok")
    public String ok(){
        log.info("ok");
        return "ok";
    }
}
  • 前提:为了模拟不同域名下的请求(即CSRF),我们在本地的hosts文件添加如下内容:
127.0.0.1 hello
127.0.0.1 world

实验步骤:


  1. 启动两个项目:springboot-security在8080端口、spring-security-csrf在8081端口;


  1. 打开浏览器,访问http://hello:8080,并完成登录,访问http://hello:8080/hello接口,观察项目springboot-security后台打印输出;


  1. 在同一个浏览器,访问http://world:8081,默认进入index.html,同时观察项目springboot-security后台打印输出;


实验结果:


  1. 在同一个浏览器(此处为Firefox,Chrome内核的浏览器未成功)的不同Tab下,在world域名下请求hello域名下的GET接口/hello:<img src="http://hello:8080/hello">,请求成功到达源站后端,实现了CSRF:跨站请求伪造。


  1. 验证了SpringSecurity虽然默认开启CSRF防护,但是幂等请求诸如"GET", "HEAD", "TRACE", "OPTIONS"被忽略。


实验2:CSRF POST攻击


spring-security-csrf项目中模拟一个按钮操作,发起POST请求,这里采用原生JavaScript发起AjaxPOST请求:http://hello:8080/ok

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
Fishing: <img src="http://hello:8080/hello">
<script language="JavaScript">
    function click() {
        let xhr = new XMLHttpRequest();
        xhr.open("POST", "http://hello:8080/ok", true);
        xhr.onload = function (e) {
            console.log("response: ", e.target);
        }
        xhr.onerror = function (e) {
            console.log("error: ", e)
        }
        xhr.send(null);
    }
    click();
</script>
</body>
</html>

实验步骤:


  1. 启动两个项目:springboot-security在8080端口、spring-security-csrf在8081端口;


  1. 打开浏览器,访问http://hello:8080,并完成登录,PostMan访问http://hello:8080/ok接口,观察项目springboot-security后台打印输出;


  1. 在同一个浏览器,访问http://world:8081,默认进入index.html,同时观察项目springboot-security后台打印输出;


image.png

实验结果:


  1. 在同一个浏览器(此处为Firefox,Chrome内核的浏览器未成功)的不同Tab下,在world域名下请求hello域名下的POST接口/ok:http://hello:8080/ok",Ajax请求受浏览器同源策略限制,被拦截。CSRF攻击失败。


  1. 即使通过PostMan访问:http://hello:8080/ok",附带Cookie,结果也是被拦截,返回403;


  1. 验证了SpringSecurity默认开启CSRF防护,对于非幂等请求诸如"POST", "PUT", "DELETE"等请求进行拦截。


因此,相比GET请求,POST请求相对更安全。


开启了CSRF防护之后,那么问题来了:


  1. 我们后端的POST请求都被拦截了,前端难道就没办法发起POST请求了吗?


  1. 我们何时需要CSRF防护,何时开启?


这些问题,后续将一一解答。


目录
打赏
0
0
0
0
8
分享
相关文章
什么是 CSRF 攻击?如何启用 CSRF 保护来抵御该攻击?
什么是 CSRF 攻击?如何启用 CSRF 保护来抵御该攻击?
295 5
如何防范 CSRF 攻击
CSRF(跨站请求伪造)攻击是一种常见的安全威胁。防范措施包括:使用Anti-CSRF Token、检查HTTP Referer、限制Cookie作用域、采用双重提交Cookie机制等,确保请求的合法性与安全性。
什么是 CSRF 攻击
CSRF(跨站请求伪造)攻击是指攻击者诱导用户点击恶意链接或提交表单,利用用户已登录的身份在目标网站上执行非授权操作,如转账、修改密码等。这种攻击通常通过嵌入恶意代码或链接实现。
Web安全进阶:XSS与CSRF攻击防御策略深度解析
【10月更文挑战第26天】Web安全是现代软件开发的重要领域,本文深入探讨了XSS和CSRF两种常见攻击的原理及防御策略。针对XSS,介绍了输入验证与转义、使用CSP、WAF、HTTP-only Cookie和代码审查等方法。对于CSRF,提出了启用CSRF保护、设置CSRF Token、使用HTTPS、二次验证和用户教育等措施。通过这些策略,开发者可以构建更安全的Web应用。
139 4
|
3月前
|
Web安全进阶:XSS与CSRF攻击防御策略深度解析
【10月更文挑战第27天】本文深入解析了Web安全中的XSS和CSRF攻击防御策略。针对XSS,介绍了输入验证与净化、内容安全策略(CSP)和HTTP头部安全配置;针对CSRF,提出了使用CSRF令牌、验证HTTP请求头、限制同源策略和双重提交Cookie等方法,帮助开发者有效保护网站和用户数据安全。
116 2
Web安全基础:防范XSS与CSRF攻击的方法
【10月更文挑战第25天】Web安全是互联网应用开发中的重要环节。本文通过具体案例分析了跨站脚本攻击(XSS)和跨站请求伪造(CSRF)的原理及防范方法,包括服务器端数据过滤、使用Content Security Policy (CSP)、添加CSRF令牌等措施,帮助开发者构建更安全的Web应用。
157 3
|
3月前
|
什么是XSS攻击?什么是SQL注入攻击?什么是CSRF攻击?
理解并防范XSS、SQL注入和CSRF攻击是Web应用安全的基础。通过采用严格的输入验证、使用安全编码实践以及实现适当的身份验证和授权机制,可以有效防止这些常见的Web攻击,保障应用程序和用户的数据安全。
67 0
Python Web开发者必学:SQL注入、XSS、CSRF攻击与防御实战演练!
【7月更文挑战第26天】在 Python Web 开发中, 安全性至关重要。本文聚焦 SQL 注入、XSS 和 CSRF 这三大安全威胁,提供实战防御策略。SQL 注入可通过参数化查询和 ORM 框架来防范;XSS 则需 HTML 转义用户输入与实施 CSP;CSRF 防御依赖 CSRF 令牌和双重提交 Cookie。掌握这些技巧,能有效加固 Web 应用的安全防线。安全是持续的过程,需贯穿开发始终。
118 1
Python Web开发者必学:SQL注入、XSS、CSRF攻击与防御实战演练!
就一次!带你彻底搞懂CSRF攻击与防御
与XSS攻击相比,利用CSRF漏洞发动攻击会比较困难,这也是在网络上看起来CSRF的人气小于XSS的原因之一。下面我们来利用CSRF漏洞发起攻击,并针对攻击进行防御,彻底弄懂CSRF,话不多说,我们直接开冲。
什么是 CSRF?如何防止 CSRF 攻击?
CSRF 攻击是一种常见且危险的 Web 安全漏洞,攻击者可以通过伪造用户请求,执行恶意操作,作为程序员,为了防御 CSRF 攻击,常见的策略包括使用 CSRF Token、检查 Referer 或 Origin 头、设置 SameSite Cookie 属性以及双重提交 Cookie。 因为程序员对于 CSRF 攻击可以做的事情还是很有限,所以,承担主要责任的是安全部门或者运维部门,但是作为程序员,我们需要具备这些安全意识,在安全等级比较高的需求中也需要把这些安全因素考虑在内。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等