Spring Security:如何开始
在本文中,您将了解Spring Security,这是一个用于身份验证、授权和 Web 应用程序防御的 Java 安全框架。我们将从基本的Spring Boot 应用程序开始,逐步构建安全功能。在此过程中,您将了解这为您解决了哪些复杂性,这样您就可以继续前进,因为 Spring Security 会为您提供支持。
目录
设置 Spring Security:第一步
要开始使用任何 Spring 模块,我建议使用start.spring.io 上的Spring Initializr。在那里,您可以添加开始所需的模块。首先,我将只添加 Spring Web,这样我就可以先向您展示一下没有 Spring Security 的生活是什么样的。
以下是我为制作应用程序选择的设置:
然后,我添加了以下@RestController:
@SpringBootApplication
public class SpringSecurityStartApplication {
@RestController
public static class OkController {
@GetMapping
public String ok() {
return "ok";
}
}
public static void main(String[] args) {
SpringApplication.run(SpringSecurityStartApplication.class, args);
}
}
就这样!我可以像这样启动应用程序:
./gradlew bootRun
....然后开始探索。
Spring Security 如何保护你的默认设置
Spring Security 为您提供的主要重要功能之一是安全默认值。也就是说,Spring Security 会根据您的用例默认选择它所知道的最安全的东西。我今天要使用的用例是 REST API,正如您在上文中从 Spring Web 中使用@RestController注释所看到的。
如果我尝试像这样请求应用程序的根目录:
http :8080
然后,我会收到类似如下的回复:
HTTP/1.1 200
Connection: keep-alive
Content-Length: 2
Content-Type: text/plain;charset=UTF-8
Date: Mon, 27 Nov 2023 21:22:51 GMT
Keep-Alive: timeout=60
ok
冒着显而易见的风险,请注意,端点不需要任何身份证明(身份验证)或权限证明(授权)。正因为如此,此端点无法轻松调整其行为以适应不同类型的用户或保护其信息。
不太明显的是,从浏览器或其他 REST API 调用此方法充其量是可疑的。如果没有进一步的防御,此应用程序的端点可能容易受到跨站点请求伪造 (CSRF)、跨站点脚本 (XSS)、中间人攻击 (MITM)、敏感数据泄露等攻击。
将 Spring Security 添加到您的应用程序
所以现在我将通过更改依赖文件将 Spring Security 模块添加到应用程序中,如下所示:
implementation ‘org.springframework.boot:spring-boot-starter-security’ // alphabetical order
implementation ‘org.springframework.boot:spring-boot-starter-web’
如果我重新启动应用程序,这将添加 Spring Security 模块及其所有安全默认值。
现在,如果我提出同样的请求:
http :8080
我得到了不同的答复:
HTTP/1.1 401
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: keep-alive
Content-Length: 0
Date: Mon, 27 Nov 2023 23:04:05 GMT
Expires: 0
Keep-Alive: timeout=60
Pragma: no-cache
Set-Cookie: JSESSIONID=4E5A935F1B30EBD82AE96FADD26AD23E; Path=/; HttpOnly
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
WWW-Authenticate: Basic realm="Realm"
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 0
这可真是太难理解了!我希望您能从中认识到,安全性不仅仅是一种让用户登录的方法。它还关乎确保您的应用程序不会被滥用。
更具体地说,主要有以下三个区别:
首先,同一个端点现在拒绝请求并返回 401。
第二,提供了更多标头,每个标头都根据安全最佳实践进行了微调。
第三个是,一个特定的标头WWW-Authenticate告诉我们,应用程序现在已配置为使用 HTTP 基本身份验证方案对用户进行身份验证。
请注意,即使我请求一个不存在的端点,如下所示:
http :8080/made-up-endpoint
...那么 Spring Security 也将使用 401 和同一组标头保护该端点。
我请您花一点时间来了解 Spring Security 为我们的应用程序提供的巨大优势。
只需添加 Spring Security 模块,它就可以接受基于标准的身份验证方案,授权每个请求(甚至是您没有考虑到的请求),并防御最常见的 Web 应用程序漏洞。
从响应中看不到幕后发生的事情。Spring Security 部署了 Web 应用程序防火墙,在身份验证过程中防止定时攻击,安全地编码密码和其他机密信息,并与 Spring 生态系统的其余部分兼容。
架构如何运作
了解架构的最佳方法之一是在应用程序中打开 TRACE 日志记录。我可以通过编辑application.properties 文件来实现这一点,如下所示:
logging.level.org.springframework.security=TRACE
然后,如果我提出与之前相同的请求:
http :8080
我将在日志中看到更多信息:
2023-11-27T17:34:33.169-07:00 DEBUG 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Securing GET /
2023-11-27T17:34:33.170-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking DisableEncodeUrlFilter (1/16)
2023-11-27T17:34:33.171-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking WebAsyncManagerIntegrationFilter (2/16)
2023-11-27T17:34:33.173-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderFilter (3/16)
2023-11-27T17:34:33.175-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking HeaderWriterFilter (4/16)
2023-11-27T17:34:33.177-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking CorsFilter (5/16)
2023-11-27T17:34:33.194-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking CsrfFilter (6/16)
2023-11-27T17:34:33.196-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.csrf.CsrfFilter : Did not protect against CSRF since request did not match CsrfNotRequired [TRACE, HEAD, GET, OPTIONS]
2023-11-27T17:34:33.196-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking LogoutFilter (7/16)
2023-11-27T17:34:33.196-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.s.w.a.logout.LogoutFilter : Did not match request to Ant [pattern='/logout', POST]
2023-11-27T17:34:33.197-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking UsernamePasswordAuthenticationFilter (8/16)
2023-11-27T17:34:33.197-07:00 TRACE 293546 --- [nio-8080-exec-1] w.a.UsernamePasswordAuthenticationFilter : Did not match request to Ant [pattern='/login', POST]
2023-11-27T17:34:33.197-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking DefaultLoginPageGeneratingFilter (9/16)
2023-11-27T17:34:33.197-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking DefaultLogoutPageGeneratingFilter (10/16)
2023-11-27T17:34:33.197-07:00 TRACE 293546 --- [nio-8080-exec-1] .w.a.u.DefaultLogoutPageGeneratingFilter : Did not render default logout page since request did not match [Ant [pattern='/logout', GET]]
2023-11-27T17:34:33.198-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking BasicAuthenticationFilter (11/16)
2023-11-27T17:34:33.198-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter : Did not process authentication request since failed to find username and password in Basic Authorization header
2023-11-27T17:34:33.198-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking RequestCacheAwareFilter (12/16)
2023-11-27T17:34:33.198-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.s.w.s.HttpSessionRequestCache : matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
2023-11-27T17:34:33.199-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking SecurityContextHolderAwareRequestFilter (13/16)
2023-11-27T17:34:33.200-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking AnonymousAuthenticationFilter (14/16)
2023-11-27T17:34:33.201-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking ExceptionTranslationFilter (15/16)
2023-11-27T17:34:33.201-07:00 TRACE 293546 --- [nio-8080-exec-1] o.s.security.web.FilterChainProxy : Invoking AuthorizationFilter (16/16)
从日志中可以看出,Spring Security 本质上是一组拦截每个请求的过滤器。每个过滤器要么执行身份验证、授权或防御,要么执行一些基础架构角色。
例如,您可以在过滤器列表中看到每种类型的示例:
BasicAuthenticationFilter用于验证 HTTP Basic 方案,
AuthorizationFilter授权请求,
HeaderWriterFilter会写入安全标头,就像您之前看到的缓存控制标头一样,并且
ExceptionTranslationFilter捕获 Spring Security 异常并将其转换为适当的 HTTP 响应
Spring Security 有一组默认拦截每个 HTTP 请求的 Web 过滤器。它还有其他过滤器,例如用于拦截方法调用、Websocket 消息和需要您配置的 RSocket 请求。
Spring Security 执行任何操作时,其最初都来自这些 Spring Security 过滤器之一。成功执行身份验证过滤器的结果是Authentication的一个实例,该实例通常具有用户的识别特征以及 Spring Security 授予该用户的权限。
如何为你的应用配置身份验证
尽管有这些有用的安全默认值,但大多数使用 Spring Security 的应用程序的主要目标还是让用户登录。
正如我已经提到的,Spring Security 默认启用 HTTP Basic 身份验证。默认用户是user ,没有默认密码。没错,密码是在启动时生成的,以确保应用程序不会意外地使用默认密码部署;另一个 Spring Security 安全默认值。
您可以通过在application.properties文件中设置来更改密码,如下所示:
spring.security.user.password=password
然后你就可以到达终点了:
http -a user:password :8080
并得到之前的 200 响应:
HTTP/1.1 200
Connection: keep-alive
Content-Length: 2
Content-Type: text/plain;charset=UTF-8
Date: Mon, 27 Nov 2023 21:51:51 GMT
Keep-Alive: timeout=60
ok
免责声明:本内容来源于第三方作者授权、网友推荐或互联网整理,旨在为广大用户提供学习与参考之用。所有文本和图片版权归原创网站或作者本人所有,其观点并不代表本站立场。如有任何版权侵犯或转载不当之情况,请与我们取得联系,我们将尽快进行相关处理与修改。感谢您的理解与支持!
请先 登录后发表评论 ~