重学SpringBoot3-集成Spring Security(三)

重学SpringBoot3-集成Spring Security(三)

CoderJia 67 2024-10-17

在现代应用开发中,安全性是不可忽视的核心问题。无论是小型应用,还是大型分布式系统,应用都需要防范来自网络的潜在攻击。Spring Boot 3Spring Security 提供了一系列功能来帮助开发者构建安全、健壮的应用,尤其是在防范常见漏洞攻击方面。本文将讨论如何在 Spring Boot 3 中利用 Spring Security 来防范几类常见的漏洞攻击。


1. 防范CSRF(跨站请求伪造)

CSRF(跨站请求伪造)攻击的原理是利用用户已登录的身份,在不知情的情况下,执行恶意的操作。攻击者通常会诱导用户点击恶意链接或访问恶意网站,该请求会在用户已登录的应用中以用户的身份执行。例如,用户登录了银行账户,攻击者发送一个请求,执行转账操作,而用户并未察觉。

攻击的关键是:用户的身份验证凭据(如Cookie、Session等)会自动随请求发送,从而使恶意请求在服务器端被认为是合法的。

在默认情况下,Spring Security 会启用 CSRF 保护,特别是对于会话管理的应用。

默认开启CSRF保护

1.1 演示效果

如果提交表单时未传 _csrf ,则会提示 403 禁止访问。

post请求未携带_csrf时

当前表单里携带了 _csrf token 时,则请求通过。

自动为表单提交添加 CSRF 保护

使用 thymeleaf 模板时,会自动携带上 _csrf token。

post请求携带_csrf

1.2 关闭 CSRF 防护

有些请求不涉及到状态形式运行时,如REST API,则需要关闭 CSRF 防护配置。

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.context.annotation.Bean;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(csrf -> csrf.disable())  // 若某些请求无需 CSRF 保护可以禁用
        .authorizeRequests(auth -> auth
            .requestMatchers("/").permitAll()
            .anyRequest().authenticated())
        .formLogin();
    return http.build();
}
  • 启用或禁用 CSRF:当应用以无状态(stateless)形式运行时,如 REST API,CSRF 保护可以适当禁用。
  • 默认防护:对于常见的 Web 应用,Spring Security 默认会自动为表单提交添加 CSRF 保护。

2. 防范XSS(跨站脚本攻击)

在 Spring Security 中,防范 XSS(跨站脚本攻击) 是非常重要的。XSS 攻击允许攻击者通过注入恶意的客户端脚本(如JavaScript)来操纵用户浏览器,从而窃取用户信息或执行其他恶意行为。Spring Security 默认提供了一些 XSS 防护机制,但我们仍需确保在前端输入和后端输出时严格过滤和转义数据。

下面是一个简单的 Spring Boot 3 和 Spring Security 演示,展示如何在应用中防范 XSS 攻击。

2.1 配置 Spring Security

配置一个简单的 Security 配置类,允许所有用户访问我们的演示页面。

package com.coderjia.boot313security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

/**
 * @author CoderJia
 * @create 2024/10/13 下午 01:57
 * @Description
 **/
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http
                .authorizeHttpRequests((authz) -> authz
                        .anyRequest().permitAll()  // 允许所有请求
                )
                .csrf(csrf->csrf.disable());  // 这里禁用 CSRF 仅用于演示,实际开发中请根据需要启用 CSRF 防护
        return http.build();
    }
}

2.2 定义控制器

package com.coderjia.boot313security.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author CoderJia
 * @create 2024/10/13 下午 02:10
 * @Description
 **/
@Slf4j
@Controller
public class LoginController {

    @GetMapping("/home")
    public String home() {
        return "xss_demo";
    }

    @PostMapping("/submit")
    public String submit(@RequestParam String input, Model model) {
        model.addAttribute("input", input);
        return "xss_result";
    }
}

2.3 创建 Thymeleaf 模板

xss_demo.html (用户输入页面)

我们使用 Thymeleaf 模板展示用户输入的内容,这也是 XSS 攻击常发生的地方。如果没有适当的转义,恶意代码将被执行。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>XSS Demo</title>
</head>
<body>
    <h1>输入内容</h1>
    <form action="/submit" method="post">
        <input type="text" name="input" />
        <button type="submit">提交</button>
    </form>
</body>
</html>

xss_result.html (展示用户输入结果)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>结果</title>
</head>
<body>
    <h1>结果</h1>
    <p>您输入的内容:</p>
    <!-- 使用 Thymeleaf 来自动转义用户输入的内容,防止 XSS 攻击,所有使用th:utext -->
    <p th:utext="${input}"></p>
</body>
</html>

2.4 XSS 攻击演示

在没有安全防护的情况下,如果用户输入了类似以下内容:

<script>alert('XSS 攻击!')</script>

输入框输入脚本:

输入脚本

显示攻击:

显示攻击

如果我们没有使用 th:text 来转义输出,恶意脚本将被执行并弹出警告框。然而,使用 th:text 后,Thymeleaf 会自动转义 <script> 标签,防止它被执行。

2.5 启用内容安全策略(CSP)

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authz) -> authz
                        .anyRequest().permitAll()  // 允许所有请求
                )
                .headers(headers -> headers.contentSecurityPolicy(contentSecurityPolicyConfig -> contentSecurityPolicyConfig.policyDirectives("script-src 'self'")))
                .csrf(csrf->csrf.disable());  // 这里禁用 CSRF 仅用于演示,实际开发中请根据需要启用 CSRF 防护
        return http.build();
    }

这种配置通过**内容安全策略(CSP)**来防止外部来源的脚本加载,从而有效减少 XSS 攻击的风险。

  • 输出编码:在服务端,应确保在返回 HTML 内容时,对用户输入的数据进行适当的转义处理,以防止恶意脚本注入。

未显示脚本


3. 防范SQL注入

SQL 注入是最常见的攻击之一,通过在输入字段中插入恶意的 SQL 语句来篡改数据库。Spring Security 通过数据访问层的安全来防止 SQL 注入。

使用参数化查询:

@Query("SELECT u FROM User u WHERE u.username = :username")
User findByUsername(@Param("username") String username);

Spring Data JPA 提供了安全的参数化查询方式,避免了 SQL 注入的风险。

此外,Hibernate 作为 Spring Boot 默认的 ORM 框架,天生对 SQL 注入有很强的防护能力,确保开发者不会在使用 JPQL(Java Persistence Query Language)时受到攻击。


4. 防范暴力破解

暴力破解 是攻击者不断尝试不同的用户名和密码组合,直到找到正确的凭据。为防范暴力破解攻击,可以使用账户锁定策略限制登录次数

配置登录失败次数限制:

        http
                .formLogin(form->form.failureHandler((request, response, exception) -> {
                    // 如果登录失败次数过多,则锁定账户
                    String username = request.getParameter("username");
                    // 调用业务逻辑锁定账户
                }));

通过设置登录失败后的延时账户锁定策略,可以显著减少暴力破解的威胁。


5. 安全头部配置

HTTP 头部是重要的安全防护部分。Spring Security 提供了很多内建的 HTTP 头部配置来增强安全性:

        http
                .headers(headers -> headers
                        .xssProtection(Customizer.withDefaults())   // 防范XSS
                        .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin) // 防范点击劫持
                        .contentTypeOptions(Customizer.withDefaults())  // 禁止内容嗅探
                        .httpStrictTransportSecurity(Customizer.withDefaults()));  // 强制 HTTPS 连接
        return http.build();

这些安全头部能够有效地防范一系列的攻击,包括Clickjacking内容嗅探、以及通过不安全的 HTTP 协议传输敏感数据。


6. 防范Clickjacking攻击

Clickjacking 是通过将网页嵌入到恶意页面的 iframe 中,使得用户误点击,执行意图不明的操作。可以通过设置 X-Frame-Options 来防范这类攻击。

        http
                .headers(headers -> headers
                        .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin));  // 防范点击劫持 

这种配置将只允许页面嵌入自身的 iframe,而拒绝外部页面嵌入。


7. 总结

Spring Security 在 Spring Boot 3 中提供了丰富的防护机制,帮助开发者应对多种常见的网络攻击。从 CSRF 到 SQL 注入,XSS 攻击再到 Clickjacking,每个环节都能通过适当的配置和策略,保障应用的安全性。通过正确的防护措施,开发者不仅能避免潜在的安全漏洞,还能提高用户对应用的信任和满意度。