第九期读书会深入浅出Spring Security读书笔记整理
一、Spring Security简介
缘起:
在 Web 应用开发中,安全一直是非常重要的一个方面。安全虽然属于应用的非功能性需求,但是应该在应用开发的初期就考虑进来。如果在应用开发的后期才考虑安全的问题,就可能陷入一个两难的境地:一方面,应用存在严重的安全漏洞,无法满足用户的要求,并可能造成用户的隐私数据被攻击者窃取;另一方面,应用的基本架构已经确定,要修复安全漏洞,可能需要对系统的架构做出比较重大的调整,因而需要更多的开发时间,影响应用的发布进程。因此,从应用开发的第一天就应该把安全相关的因素考虑进来,并在整个应用的开发过程中。
Spring Security 简介:
为什么选择 Spring Security?
Shiro本身是一个老牌的安全管理框架(一个强大且易用的Java安全框架),能够非常清晰的处理身份验证、授权、管理会话以及密码加密。有着众多的优点,例如轻量、简单、易于集成、可以在JavaSE环境中使用等。不过在微服务面前,它无法充分展示自己的优势。
Spring Security作为Spring家族的一员,在和Spring家族的其他成员进行整合时,具有其他框架无可比拟的优势,同时对OAuth2有着良好的支持,再加上Spring Cloud对Spring Security的不断加持,让Spring Security成为微服务项目的首选安全管理方案。除了不能脱离Spring,shiro的功能它都有。
所以推荐选择Spring Security。
Spring Security 核心功能:
认证 (你是谁)(Authentication):
Authentication 是一个接口,用来表示用户认证信息的,在用户登录认证之前相关信息会封装为一个 Authentication 具体实现类的对象,在登录认证成功之后又会生成一个信息更全面,包含用户权限等信息的 Authentication 对象,然后把它保存在 SecurityContextHolder 所持有的 SecurityContext 中,供后续的程序进行调用,如访问权限的鉴定等。
授权 (你能干什么)(Authorization):
也叫访问控制,即在应用中控制谁访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
Spring Security 整体架构:
认证和授权:在Spring Security的授权体系中,有两个关键接口:AccessDecisionManager和AccessDecisionVoter
Web 安全:在Spring Security中,认证、授权等功能都是基于过滤器来完成的。开发者所见到的Spring Security提供的功能,都是通过这些过滤器来实现的,这些过滤器按照既定的优先级排列,最终形成一个过滤器链。开发者也可以自定义过滤器,并通过@Order注解去调整自定义过滤器在过滤器链中的位置。需要注意的是,默认过滤器并不是直接放在Web项目的原生过滤器链中,而是通过一个FilterChainProxy来统一管理。
总结:
Spring 是一个非常流行和成功的java应用开发框架。
Spring Security 基于Spring 框架,提供了一套web应用安全性的完整解决方案。
Spring Security 核心功能是:认证和授权。
Spring安全的所有内部过滤器对于容器来说都是透明的。
二、Spring Security 认证流程分析
Spring Security是一款强大的安全认证服务框架,它的原理就是在访问我们的系统前加了一系列的过滤器,可以称为过滤器链。它的两大核心就是认证和授权
1.Spring Security 基本认证
在 Spring Boot项目中使用 SpringSecurity非方便,创建一个新的 Spring Boot项目,我们只需要引入Web和 Spring Security依赖即可。
新建一个springboot工程,pom里添加springsecurity的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
引入 Spring Security依赖后,项目中的所有接口就都被保护起来了,此时访问接口就可以看到登录页面了。
在不进行配置的情况下,默认拦截所有的请求
2.Spring Security 认证流程分析
AuthenticationManager
AuthenticationManager是一个认证管理器,它定义了 Spring Security过滤器要如何执行认证操作。 AuthenticationManager是一个接口,它有着诸多的实现类,开发者也可以自定义 Authentication Manager的实现类,不过在实际应用中,我们使用最多的是 ProviderManager.在 Spring Security框架中,默认也是使用 ProviderManager.
添加用户自己的处理逻辑,需要实现UserDetailsService接口
ProviderManager
常见的 DaoAuthenticationProvider用来支持用户名/密码
登录认证, RememberMeAuthenticationProvider用来支持记住我"的认证。
3.配置多数据源
同时支持多张用户表
多个数据源是指在同一个系统中,用户数据来自不同的表,在认证时,如果第一张表没有查找到用户,那就去第二张表中查询,依次类推。
要实现这个需求就很容易,认证要经过 Authenticatic,每一个 AuthenticationProvid中都配置了一个 UserDetailsService,而不同的 UserDetailsService则可以代表不同的数据源。所以我们只需要手动配置多个 AuthenticationProvider,并为不同的 Authenticatio Provider提供不同的userDetailsService即可。
4.添加登录验证码
登录验证码也是项目中一个常见的需求,但是 Spring Security对此并未提供自动化配置方案,需要开发者自行定义。一般来说,有两种实现登录验证码的思路:
(1)自定义过滤器。
(2)自定义认证逻辑。
总结:
三、Spring Security 密码加密
1.为什么需要密码加密
由于很多用户是多个网站共用一个密码,因此一个网站密码泄漏就会造成很大的安全隐患。由于有了这么多前车之鉴,我们现在做系统时,密码都要加密处理。
2.加密方案进化史
Hash算法
-
原始密码经哈希函数计算后得到一个哈希值
-
改变原始密码,哈希函数计算出的哈希值也会相应改变
-
同样的密码,哈希值也是相同的
-
哈希函数是单向、不可逆的。也就是说从哈希值,你无法推算出原始的密码是多少
密码加盐
为了防止黑客通过彩虹表根据哈希值反推原始口令,在计算哈希的时候,不能仅针对原始输入计算,需要增加一个salt来使得相同的输入也能得到不同的哈希,这样,大大增加了黑客破解的难度。
自适应单向函数
现在鼓励开发人员利用自适应单向函数来存储密码。开发人员来设定不同的worker factor满足不同的安全需要,在安全和效率之间做出权衡。例如: bcrypt , PBKDF2 , scrypt , and Argon2 .
3.PasswordEncoder
常见实现类
-
BCryptPasswordEncoder
-
Argon2PasswordEncoder
-
Pbkdf2PasswordEncoder
-
SCryptPasswordEncoder
为什么采用 Delegatin“g-P-a-s-s”wordEncoder而不是某一个具体加密方式作为默认的密码加密方案呢?主要考虑了如下三方面的因素:
-
兼容性
-
便捷性
-
稳定性
4.加密方案自动升级
如果开发者使用了 Delegatin“g-P-a-s-s”wordEncoder,只要数据库中存储的密码加密方案不是 Delegatin“g-P-a-s-s”wordEncoder中默认的BCryptPassword Encoder,在登录成功之后,都会自动升级为 BCryptPassword Encoder加密。在同一种密码加密方案中,也有可能存在升级的情况。
总结:
Delegatin“g-P-a-s-s”wordEncoder(spring5.0后的新特性)
-
确保使用当前密码存储建议对密码进行编码
-
允许验证现代和传统格式的密码
-
允许将来升级编码
-
将编码方式存入密码文本
四、Spring Security 会话管理
由于HTTP协议是无状态协议,对于服务器而言每个请求都一样,缺少一个状态去区分请求是否来自于不同的用户,以便服务器提供不同的服务。所以我们需要利用某种机制来记录不同用户的标识信息。这个机制就是Session,这个时候cookie就体现了它的重要作用。当客户端首次请求服务端时,服务端为该用户生成一个sessionId,并保存在cookie中,带回客户端,客户端保存这个cookie。之后客户端每次请求都带上这个cookie,服务端可以很容易区分是来自哪个用户的请求。但出于安全考虑,有时用户在浏览器中禁用cookie,这个时候可以利用URL重写,将sessionId拼接在重写的URL后面返回给已经授权的用户。
1.会话简介
当浏览器调用登录接口成功后,服务端会和浏览器直接建立一个会话(session),浏览器每次发送请求都会携带sessionId,服务端会根据这个id判断身份,浏览器关闭后服务器的session不会自动销毁,需要手动在服务端调用销毁方法,或者等待过期时间自动销毁。
2.会话并发管理
会话并发管理就是当前系统中同一个用户可以创建多个会话,一台设备对应一个会话,一个用户可以在多台设备上登录,这个并没有限制,但在spring security中可以配置。
当会话并发数达到限制时,新的会话将之前旧的会话 挤下线 ,旧的登录会话失效。
当会话并发数达到限制时,新的会话将被限制创建,除非旧的会话主动退出登录。
3.会话固定攻击与防御
会话固定攻击是一种潜在的风险,恶意攻击者有可能通过访问当前应用程序来创建会话,然后诱导用户以相同的会话ID登录(通常是将会话 作为参数放在请求链接中,然后诱导用户去单击),进而获取用户的登录身份。
攻击者自己正常访问系统,系统给攻击者分配了一个sessionId,攻击者拿着自己手上的sessionId伪造一个系统登录链接,受害者利用链接登陆了,那么sessionId绑定了用户的信息,攻击者可以利用手里的sessionId冒充受害者,这就是会话固定攻击
当我们登录成功之后重新生成新的session,即可避免。
Spring Security自带该功能,并且自带的HTTP防火墙会帮我们拦截掉哪些拼接的不合法的URL
sessionManagement是一个会话管理的配置器,其中,防御会话固定攻击的策略有四种:
-
none:不做任何变动,登录之后沿用旧的session。
-
newSession:登录之后创建一个新的session。
-
migrateSession:登录之后创建一个新的session,并将旧的session中的数据复制过来。
-
changeSessionId:不创建新的会话,而是使用由Servlet容器提供的会话固定保护。
默认已经启用migrateSession策略,如有必要,可以做出修改。
Spring Security从三方面防范会话固定攻击:
(1)默认自带Http防火墙
(2)在Http响应的Set-Cookie字段中有httpOnly属性,这样避免了通过xss攻击来获取Cookie中的会话信息,
进而达成会话固定攻击。
(3)登录成功后改变sessionId, Spring Security中默认实现了该种方案。
总结:
在 Spring Security 中,即便没有配置,也大可不必担心会话固定攻击。这是因为Spring Security的HTTP防火墙会帮助我们拦截不合法的URL,当我们试图访问带session的URL时,实际上会被重定向到一个错误页。
五、Spring Security 防火墙
各种各样的web攻击每天都在发生,什么xss攻击、sql注入等等,如果不了解这些攻击,那么做出来的系统肯定也不能防御这些攻击。使用 Spring Security 的好处就是,即使不了解这些攻击,也不用担心这些攻击,因为 Spring Security 已经帮你做好防御工作了。
1.HttpFirewall 简介
HttpFirewall 是Spring Security提供的Http防火墙,它可以用于拒绝潜在的危险请求或者包装这些请求进而控制其行为。通过HttpFirewall 可以对各种非法请求提前进行拦截并处理,降低损失。
在 servlet容器规范中,为Httpervletrequest定义了一些属性,如contextPath、servletath、pathinfo、 queryString等,这些属性都可以通过get方法获取。
HttpFirewall 目前一共有两个实现类:一个是严格模式的防火墙设置,还有一个默认防火墙设置。
-
DefaultHttpFirewall:虽然名字中包含Default,但这并不是框架默认使用的Http防火墙,它只是一个检查相对宽松的防火墙。
-
StrictHttpFirewall:这是一个检查严格的Http防火墙,也是框架默认使用的Http防火墙。
DefaultHttpFirewall 的限制相对于 StrictHttpFirewall 要宽松一些,当然也意味着安全性不如 StrictHttpFirewall。Spring Security 中默认使用的是 StrictHttpFirewall。
2.HttpFirewall 严格模式
StrictHttpFirewall是Spring Security Web提供的一个HTTP防火墙(对应概念模型接口HttpFirewall)实现,该实现采用了严格模式,遇到任何可疑的请求,会通过抛出异常RequestRejectedException拒绝该请求。StrictHttpFirewall也是Spring Security Web在安全过滤器代理FilterChainProxy内置缺省使用的HTTP防火墙机制。
-
rejectForbiddenHttpMethod:校验请求方法是否合法。
-
rejectedBlacklistedUrls:校验请求中的非法字符。
-
rejectedUntrustedHosts:检验主机信息。
-
isNormalized:判断参数格式是否合法。
-
containsOnlyPrintableAsciiCharacters:判断请求字符是否合法。
3.HttpFirewall 普通模式
HttpFirewall普通模式就是使用DefaultHttpFirewall,该类的校验规则就要简单很多。
一般来说,并不建议开发者在项目中使用DefaultHttpFirewall,因为相比于StrictHttpFirewall,DefaultHttpFirewall的安全性要差很多。
总结:
不在HTTP method许可清单的请求会被拒绝。
标准化的URL必须符合以下条件 :在其requestURI/contextPath/servletPath/pathInfo中,必须不能包含以下字符串序列之一 :["//","./","/…/","/."]
每一条限制都有它的原由,每放开一个限制,就会带来未知的安全风险。尤其是如果请求URL 中包含不可打印ASCII字符则该请求会被拒绝。该规则不可关闭,因为对应风极高。
江南一点雨老师博客1:江南一点雨-分享 Java 点滴
江南一点雨老师博客2:江南一点雨
开源社区:江南一点雨 (lenve) - Gitee.com
学习任重而道远,加油!感谢老师!
- 点赞
- 收藏
- 关注作者
评论(0)