Spring-Security

使用 Spring Security 构建 OAuth 2.0 资源服务器

1、概览 本文将带你了解如何使用 Spring Security 构建 OAuth 2.0 资源服务器(使用 JWT 和 Opaque Token,这两种由 Spring Security 支持的 Bearer Token)。 2、背景介绍 2.1、JWT 和 Opaque Token 是什么? JWT 或 JSON Web Token 是一种以广泛接受的 JSON 格式安全传输敏感信息的方式。其中包含的信息可能是关于用户的,也可能是关于 Token 本身的,例如其 expiry(有效期)和 issuer(签发者)。 Opaque Token 顾名思义,它所携带的信息是不透明的。Token 只是一个标识符,指向存储在授权服务器上的信息;它通过服务器端的自省(Introspection)进行验证。 2.2、资源服务器是什么? 在 OAuth 2.0 中,资源服务器是通过 OAuth Token 保护资源的应用。这些 Token 由授权服务器(通常是客户端应用)签发。资源服务器的工作是在向客户端提供资源之前验证 Token。 令牌的有效性由几个因素决定: 该令牌是否来自配置的授权服务器? 是否未过期? 该资源是否为预期受众(audience)提供服务? Token 是否具有访问所请求资源的必要权限? 来看一下 授权码模式 的顺序图,并观察所有相关的参与者: 正如在步骤 8 中看到的,当客户端应用调用资源服务器的 API 访问受保护的资源时,它首先会转到授权服务器,以验证请求的 Authorization: Bearer Header 信息中包含的 Token,然后响应客户端。 本文的重点是第 9 步。

使用 Spring Security 防止 CSRF 攻击

1、概览 本文将带你了解什么是跨站请求伪造(CSRF)攻击?以及如何使用 Spring Security 来防范这些攻击。 2、两种简单的 CSRF 攻击行为 CSRF 攻击有多种形式。 2.1、GET 示例 假如下面这个 GET 请求,用于一个已登录的用户向指定的银行账户 1234 转账: GET http://bank.com/transfer?accountNo=1234&amount=100 如果攻击者想把钱从受害者的账户转到自己的账户(5678),他需要让受害者触发请求: GET http://bank.com/transfer?accountNo=5678&amount=1000 有多种方法可以实现这一点: 链接 - 攻击者可以说服/诱导受害者点击该链接,例如执行转账: <a href="http://bank.com/transfer?accountNo=5678&amount=1000"> 点击展示美女图片 </a> 图片 - 攻击者可能会使用 <img/> 标签,将目标 URL 作为图片来源。换句话说,甚至不需要点击。请求将在页面加载时自动执行: <img src="http://bank.com/transfer?accountNo=5678&amount=1000"/> 所以,涉及到敏感的业务,千万不能用 GET 请求。 2.2、POST 示例 假设转账 API 是一个 POST 请求。 POST http://bank.com/transfer accountNo=1234&amount=100 在这种情况下,<a> 和 <img/> 标签都不起作用。 攻击者需要使用 <form>: <form action="http://bank.com/transfer" method="POST"> <input type="hidden" name="accountNo" value="5678"/> <input type="hidden" name="amount" value="1000"/> <input type="submit" value="Show Kittens Pictures"/> </form> 然后,使用 JavaScript 自动提交表单:

Spring Security LDAP 简介

1、概览 本文将带你了解如何设置 Spring Security LDAP。 LDAP、即 Lightweight Directory Access Protocol(轻量级目录访问协议)的缩写,是一种开放的、厂商中立的协议,用于通过 Web 访问目录服务。 2、Maven 依赖 所需 Maven 依赖如下: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-ldap</artifactId> </dependency> <dependency> <groupId>org.apache.directory.server</groupId> <artifactId>apacheds-server-jndi</artifactId> <version>1.5.5</version> </dependency> 注:使用 ApacheDS 作为 LDAP 服务器,这是一个可扩展、可嵌入的目录服务器。 3、Java 配置 Spring Security Java 配置: public class SecurityConfig { @Bean ApacheDSContainer ldapContainer() throws Exception { return new ApacheDSContainer("dc=baeldung,dc=com", "classpath:users.ldif"); } @Bean LdapAuthoritiesPopulator authorities(BaseLdapPathContextSource contextSource) { String groupSearchBase = "ou=groups"; DefaultLdapAuthoritiesPopulator authorities = new DefaultLdapAuthoritiesPopulator (contextSource, groupSearchBase); authorities.setGroupSearchFilter("(member={0})"); return authorities; } @Bean AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource, LdapAuthoritiesPopulator authorities) { LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory (contextSource); factory.

在 Spring 应用中防止跨站脚本(XSS)攻击

1、概览 在构建 Spring Web 应用时,关注安全性非常重要。跨站脚本 (XSS) 是对 Web 安全威胁最大的攻击之一。 在 Spring 应用中,防止 XSS 攻击是一项挑战。Spring 提供了内置的帮助来实现全面的保护。 本文将带你了解如何通过 Spring Security 使用 X-XSS-Protection 和 Content-Security-Policy 机制来防止 XSS 攻击。 2、什么是跨站脚本(XSS)攻击? 2.1、问题的定义 XSS 是一种常见的注入式攻击。在 XSS 中,攻击者试图在 Web 应用程序中执行恶意代码。他们通过 Web 浏览器或 HTTP 客户端工具(如 Postman)与应用交互。 XSS 攻击有两种类型: 反射性或非持久性 XSS 存储型或持久型 XSS 在反射型或非持久型 XSS 中,不受信任的用户数据被提交到 Web 应用,并立即在响应中返回,从而在页面中添加了不可信的内容。Web 浏览器会认为代码来自 Web 服务器并执行它。这可能会让黑客向你发送一个链接,当你点击该链接时,浏览器会从你使用的网站上获取你的私人数据,然后让你的浏览器将这些数据转发到黑客的服务器上。 在存储型或持久型 XSS 中,Web 服务器会存储攻击者的输入。随后,任何后来的访问者都可能执行该恶意代码。 2.2、防御攻击 防止 XSS 攻击的主要策略是清理用户输入。 在 Spring Web 应用中,用户的输入是 HTTP 请求。为防止攻击,应检查 HTTP 请求的内容,并删除可能可在服务器或浏览器中执行的任何内容。 对于通过 Web 浏览器访问的普通 Web 应用,可以使用 Spring Security 的内置功能(反射性 XSS)。

Spring Security Oauth 授权服务器

1、简介 OAuth 是一种描述授权过程的开放标准。它可用于授权用户访问 API。例如,REST API 可以限制只有具有适当角色的注册用户才能访问。 OAuth 授权服务器负责认证用户身份,并签发包含用户数据和适当访问策略的访问令牌(Access Token)。 本将带你了解如何使用 Spring Security OAuth 授权服务器 实现一个简单的 OAuth 应用。 我们要创建一个 CS 应用,通过 REST API 获取资源服务器上的文章列表。客户端服务和服务器服务都需要 OAuth 身份认证。 2、授权服务器实现 先来看看 OAuth 授权服务器的配置。它作为文章资源和客户端服务器的身份认证源。 2.1、依赖 首先,在 pom.xml 中添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.5.4</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-authorization-server</artifactId> <version>0.2.0</version> </dependency> 2.2、配置 在 application.yml 文件中,设置 server.port 属性来配置认证服务器的运行端口: server: port: 9000 然后,就可以开始配置 Spring Bean 了。首先,需要一个 @Configuration 类,在该类中创建一些 OAuth 特有的 Bean。 第一个是客户端服务的 Repository。在本例中,使用 RegisteredClient Builder 类创建一个客户端:

在 Spring Security 6 中实现动态权限管理

在 Spring Boot 3 之后,Spring Security 现在也升级到 Spring Security 6 了。 Spring Security 6 的用法跟之前比起来还是有很大差异,例如:动态权限定义的方式。 1、权限开发思路 先来说权限开发的思路,当设计好 RBAC 权限之后,具体到代码层面,有两种实现思路: 直接在接口/Service 层方法上添加权限注解,这样做的好处是实现简单,但是有一个问题就是权限硬编码,每一个方法需要什么权限都是代码中配置好的,后期如果想通过管理页面修改是不可能的,要修改某一个方法所需要的权限只能改代码。 将请求和权限的关系通过数据库来描述,每一个请求需要什么权限都在数据库中配置好,当请求到达的时候,动态查询,然后判断权限是否满足,这样做的好处是比较灵活,将来需要修改接口和权限之间的关系时,可以通过管理页面点击几下,问题就解决了,不用修改代码。 有人觉得第二种方案无法做到按钮级别的权限控制,这其实是一个误解。想要做到按钮级别的权限控制,只需要数据库中细化配置即可。 2、具体实践 2.1、旧方案回顾 在 vhr 项目中,通过重写两个类来和实现动态权限的。 第一个类是收集权限元数据的类: @Component public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { //... } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> clazz) { return true; } } 在 getAttributes 方法中,根据当前请求的 URL 地址(从参数 Object 中可提取出来)和根据权限表中的配置,分析出来当前请求需要哪些权限并返回。

Spring Security 中的 @EnableWebSecurity 和 @EnableGlobalMethodSecurity

1、概览 有时我们需要在 Spring Boot 应用的不同路径上应用多个 Security Filter。 本文将带你了解在 Spring Scurity 中自定义 Security 的两种方法 - 通过使用 @EnableWebSecurity 和 @EnableGlobalMethodSecurity。 本文通过一个简单的应用示例来说明这两者的区别。该应用包含一些管理员(ADMIN)才能访问的资源和一些只有认证了的用户(USER)才能访问的资源以及一些任何人都可以访问、下载的公共资源。 2、Spring Boot 整合 Spring Security 2.1、Maven 依赖 无论采用哪种方法,都需要添加 Spring Boot Stater 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 2.2、Spring Boot 自动配置 当 classpath 上存在 Spring Security 时,Spring Boot Security Auto-Configuration 的 WebSecurityEnablerConfiguration 就会激活 @EnableWebSecurity。这会在应用中加载默认的安全配置。 默认的安全配置会激活 HTTP Security Filter 和 Security Filter Chain,并对端点应用 Basic Authentication 认证。 3、保护端点 第一种方式,创建一个 MySecurityConfigurer 类,使用 @EnableWebSecurity 对其进行注解。 @EnableWebSecurity public class MySecurityConfigurer { } 3.

Spring Security 中的 RequestRejectedException

1、简介 Spring 5.0 至 5.0.4、4.3 至 4.3.14 以及其他旧版本在 Windows 系统上存在目录或路径遍历安全漏洞。 静态资源配置错误会导致恶意用户访问服务器的文件系统。例如,在 Windows 上使用 file: 协议配置静态资源,可能导致用户非法访问文件系统。 Spring 承认存在该 漏洞,并在后续版本中对其进行了修复。 此修复可防止应用遭受路径遍历攻击。不过,在修复后,一些之前的 URL 现在会抛出 org.springframework.security.web.firewall.RequestRejectedException 异常。 本文先带你了解什么是 “路径遍历攻击”,在这个知识背景下再带你了解 org.springframework.security.web.firewall.RequestRejectedException 和 StrictHttpFirewall 的相关知识。 2、路径遍历漏洞 路径遍历或目录遍历漏洞可非法访问 Web 文档根目录以外的内容。例如,篡改 URL 可对文档根目录以外的文件进行未经授权的访问。 虽然大多数最新和流行的 Web 服务器都能抵消大部分攻击,但攻击者仍可使用特殊字符(如 ./、../)的 URL 编码来规避 Web 服务器的安全设置并获取非法访问权限。 OWASP 介绍了路径遍历漏洞和解决方法。 3、Spring 的漏洞 先尝试复现这个漏洞,然后再介绍如何进行修复。 首先,克隆 Spring Framework MVC 示例。然后,修改 pom.xml,用一个易受攻击的版本替换现有的 Spring Framework 版本。 克隆仓库: git clone git@github.com:spring-projects/spring-mvc-showcase.git 在克隆目录中,编辑 pom.xml,修改 Spring Framework 的版本为 5.0.0.RELEASE: <org.springframework-version>5.0.0.RELEASE</org.springframework-version> 接下来,编辑 Web 配置类 WebMvcConfig,修改 addResourceHandlers 方法,使用 file: 将资源映射到本地文件目录:

Spring Security 配置 Content Security Policy(CSP)

1、概览 跨站脚本攻击(Cross-Site Scripting,XSS)一直稳居最常见的 十大网络攻击 之列。XSS 攻击发生在 Web 服务器处理用户恶意输入时,未经验证或编码即在页面上渲染。与 XSS 攻击类似,代码注入和点击劫持通过窃取用户数据和冒充用户身份来对 Web 应用造成严重影响。 本文将会带你了解如何使用 Spring Security 通过内容安全策略(Content-Security-Policy)保护 Web 应用免受点击劫持、代码注入和 XSS 攻击。 2、Content Security Policy 内容安全策略(Content Security Policy,简称 CSP)是一种 HTTP 响应头,可大大减少 现代浏览器 中的代码注入攻击,如 XSS、点击劫持 等。 Web 服务器通过 Content-Security-Policy Header 部指定了浏览器可以渲染的资源的列表。这些资源可以是浏览器渲染的任何内容,例如 CSS、JavaScript、图像等。 该 Header 的语法如下: Content-Security-Policy: <directive>; <directive>; <directive> ; ... 此外,还可以将此策略设置为 HTML 页面中 <meta> 标签的一部分: <meta http-equiv="Content-Security-Policy" content="<directive>;<directive>;<directive>; ..."> 每个 指令 都包含一个具有多个值的 key。指令可以不止一个,每个指令之间用分号(;) 分隔: Content-Security-Policy: script-src 'self' https://baeldung.com; style-src 'self'; 如上例所示,有两个指令(script-src 和 style-src),而指令 script-src 有两个值(self 和 https://baeldung.

Spring Security 配置不同 URL 的认证和授权规则

1、概览 本文将带你了解如何在 Spring Security 中针对不同的 URL 进行不同的安全配置。 2、设置 创建应用,在 pom.xml 中添加 Web 和 Security 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 3、创建 API 创建一个包含两个 API 的 RESTful 服务:Product(产品) API 和 Customer(客户) API。 3.1、Product API 创建 ProductController。它包含一个 getProducts 方法,该方法返回产品列表: @RestController("/products") public class ProductController { @GetMapping public List<Product> getProducts() { return new ArrayList<>(Arrays.asList( new Product("Product 1", "Description 1", 1.0), new Product("Product 2", "Description 2", 2.0) )); } } 3.2、Customer API 同样,定义 CustomerController: