Spring Security:如何开始

发布日期:2024-02-09 08:00:00   来源 : 杭州电子商务研究院    作者 :Josh Cummings    浏览量 :1
Josh Cummings 杭州电子商务研究院 发布日期:2024-02-09 08:00:00  
1

在本文中,您将了解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
    
<div class="rich-text-editor-component
以上内容来自杭州电子商务研究院推送
订阅
关于我们
热门推荐
合作伙伴
免责声明:本站部分资讯来源于网络,如有侵权请及时联系客服,我们将尽快处理
Copyright © 2025-2027 ToB产业网址导航 公安备案 浙公网安备33010602013138号 浙ICP备16025413号-9
支持 反馈 订阅 数据