`
kong0itey
  • 浏览: 306065 次
社区版块
存档分类
最新评论

《Spring Security3》第三章第三部分翻译下(Remember me安全吗?)(转载)

阅读更多

 

Remember me 是否安全?

对我们精心保护的站点来说,为了用户体验而添加的任何与安全相关的功能,都有增加安全风险的潜在可能。按照其默认方式, Remember me 功能存在用户的 cookie 被拦截并被恶意用户重用的风险。下图展现了这种情况是如何发生的:

 


 

使用 SSL (第四章进行讨论)以及其他的网络安全技术能缓解这种类型攻击的风险,但是要注意的是还有其他技术如跨站脚本攻击( XSS )能够窃取或损害一个 remembered user session 。为了照顾用户的易用性,我们不会愿意让用户的财产信息或个人信息因为 remembered session 的不合理使用而遭到篡改或窃取。

 

【尽管我们不会涉及恶意用户行为的细节,但是当你实现安全系统时,了解恶意用户所使用的攻击技术是很重要的。 XSS 是其中的一种技术,当然还有其他的很多种。强烈建议你了解 OWASP Top Ten http://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project )作为一个入门列表并参考一本 web 应用安全参考书,里面介绍了各种的技术使用。】

 

平衡用户易用性和应用安全性的一种通用方法是识别出站点中与个人或敏感信息相关的功能点。确保这些功能点在进行授权校验时不仅要判断用户的角色,还要保证用户进行了完整的用户名和密码认证。这可以通过使用 SpEL 表达式语言的 fullyAuthenticated 伪属性来实现,关于授权规则的 SpEL 表达式语言我们在第二章中已经有所介绍。

Remember me 认证与完整认证的在认证规则上的区别

我们将在随后的第五章:精确的访问控制 中介绍高级的认证技术,但是,了解能够辨别认证 session 是否为 remembered 并以此建立访问规则也是很重要的。

 

我们可以设想一个使用 remembered session 登录的用户要查看和修改他的“ wish list ”。这与其他的客户在线站点很类似,并不会出现与用户信息或财务信息相关的风险(要注意的是每个站点各不相同,不能盲目的将这些规则应用与你的站点)。相反的,我们将会重点保护用户的账号以及订单功能。我们要确保即使是 remembered 的用户,如果试图访问账号信息或定购产品,都需要对他们进行认证。以下为我们如何设置授权规则:

 

 <intercept-url pattern="/login.do" access="permitAll"/>

Xml代码  收藏代码
  1. < intercept-url   pattern = "/account/*.do"   
  2.    access = "hasRole('ROLE_USER') and fullyAuthenticated" />   
  3. < intercept-url   pattern = "/*"   access = "hasRole('ROLE_USER')" />   

 已经存在的登录页和 ROLE_USER 设置没有变化。但我们添加了一条规则,要求用户具有 GrantedAuthority ROLE_USER 角色同时还要求用户被完全的认证,即这个认证的 session 确实是通过提供用户名、密码或等同的凭证来进行认证的。注意这里的 SpEL 逻辑操作语法——在 SpEL 中,使用 and or 以及 not 作为逻辑操作符。这是 SpEL 的设计者充分考虑的结果,因为 && 操作符在 XML 中很难被使用。

 

如果你在应用中尝试运行,如果以 remember me 功能登录并试图访问“ My Account ”链接,你将会得到一个 403 访问拒绝的提示,这说明这个地址已经被适当地保护了。出现错误界面是因为我们应用的配置还是使用默认的 AccessDeniedHandler ,这个类负责捕获和响应 AccessDeniedException 的信息。我们将会在第六章学习 AccessDeniedException 怎样被处理时,自定义这个行为。

 

【不使用表达式来实现完全认证的检查。如果你的应用不使用 SpEL 表达式来进行访问控制声明,你可以通过使用 IS_AUTHENTICATED_FULLY 访问规则来检查用户是不是进行了完整的认证(如: access=" IS_AUTHENTICATED_FULLY" )。但要注意的是,这种标准的角色设置声明并没有 SpEL 那样强的表现力,所以如果要处理复杂的 boolean 表达式的时候,可能会比较困难。】

 

错误处理尚没有添加,但是你可以看到通过这种方式将 remember me 的易用性与更高层次的安全性结合了起来,用户访问敏感的信息时就会被要求提供完整的凭证信息。

构建一个关联 IP Remember me Service

有一种让 remember me 功能更安全的方式就是将用户的 IP 地址绑定到 cookie 的内容上。让我们通过一个例子来描述怎样构建 RememberMeServices 的实现类来完成这个功能。

 

基本的实现方式是扩展 o.s.s.web.authentication.rememberme.TokenBasedRememberMeServices 基类,以添加请求者的 IP 地址到 cookie 本身和其他的 MD5 哈希元素中。

 

扩展这个基类涉及到重写两个主要方法,并重写或实现几个小的帮助方法。还有一个要注意的是我们需要临时存储 HttpServletRequest (将使用它来得到用户的 IP 地址)到一个 ThreadLocal 中,因为基类中的一些方法并没有将 HttpServletRequest 作为一个参数。

扩展 TokenBasedRememberMeServices

首先,我们要扩展 TokenBasedRememberMeServices 类并重写父类的特定行为。尽管父类是非常易于重写,但是我们不想去重复一些重要的处理流程,所以能使这个类非常简明却有点不好理解。在 com.packtpub.springsecurity.security 包下创建这个类:

 

Java代码  收藏代码
  1. public   class  IPTokenBasedRememberMeServices  extends   
  2.     TokenBasedRememberMeServices {  

 

 还有一些简单的方法来设置和获取 ThreadLocal HttpServletRequest

 

Java代码  收藏代码
  1. private   static   final  ThreadLocal<HttpServletRequest> requestHolder =   
  2. new  ThreadLocal<HttpServletRequest>();  
  3. public  HttpServletRequest getContext() {  
  4.     return  requestHolder.get();  
  5. }  
  6. public   void  setContext(HttpServletRequest context) {  
  7.     requestHolder.set(context);  
  8. }  
 

我们还需要添加一个工具方法以从 HttpServletRequest 中获取 IP 地址:

 

Java代码  收藏代码
  1. protected  String getUserIPAddress(HttpServletRequest request) {  
  2.   return  request.getRemoteAddr();  
  3. }  

 我们要重写的第一个有趣的方法是 onLoginSuccess ,它用来为 remember me 处理设置 cookie 的值。在这个方法中,我们需要设置 ThreadLocal 并在完成处理后将其清除。需要记住的是父类方法的处理流程——收集用户的所有认证请求信息并将其合成到 cookie 中。

 

Java代码  收藏代码
  1. @Override   
  2. public   void  onLoginSuccess(HttpServletRequest request,  
  3.     HttpServletResponse response,  
  4.     Authentication successfulAuthentication) {  
  5.   try   
  6.   {  
  7.     setContext(request);  
  8.     super .onLoginSuccess(request, response, successfulAuthentication  
  9.   }  
  10.   finally   
  11.   {    setContext(null );  
  12.   }  
  13. }  

 父类的 onLoginSuccess 方法将会触发 makeTokenSignature 方法来创建认证凭证的 MD5 哈希值。我们将要重写此方法,以实现从 request 中获取 IP 地址并使用 Spring 框架的一个工具类编码要返回的 cookie 值。(这个方法在进行 remember me 校验时还会被调用到,以判断前台传递过来的 cookie 值与后台根据用户名、密码、 IP 地址等信息生成的 MD5 值是否一致。——译者注)

 

Java代码  收藏代码
  1. @Override   
  2. protected  String makeTokenSignature( long  tokenExpiryTime,   
  3.     String username, String password) {  
  4.     return  DigestUtils.md5DigestAsHex((username +  ":"  +   
  5. tokenExpiryTime + ":"  + password +  ":"  + getKey() +  ":"  + getUserIPAdd  
  6. ress(getContext())).getBytes());   
  7. }  

 与之类似的,我们还重写了 setCookie 方法以添加包含 IP 地址的附加编码信息:

 

Java代码  收藏代码
  1. @Override   
  2. protected   void  setCookie(String[] tokens,  int  maxAge,  
  3.   HttpServletRequest request, HttpServletResponse response) {  
  4.   // append the IP adddress to the cookie   
  5.   String[] tokensWithIPAddress =   
  6.       Arrays.copyOf(tokens, tokens.length+1 );  
  7.   tokensWithIPAddress[tokensWithIPAddress.length-1 ] =   
  8.       getUserIPAddress(request);  
  9.   super .setCookie(tokensWithIPAddress, maxAge,   
  10.       request, response);  
  11. }  

 这就得到了生成新 cookie 所有需要的信息。

 

最后,我们要重写 processAutoLoginCookie 方法,它用来校验用户端提供的 remember me cookie 的内容。父类已经为我们解决了大部分有意思的工作,但是,为了避免调用父类冗长的代码,我们在调用它之前先进行了一次 IP 地址的校验。

 

 

Java代码  收藏代码
  1. @Override   
  2. protected  UserDetails processAutoLoginCookie(  
  3.   String[] cookieTokens,  
  4.   HttpServletRequest request, HttpServletResponse response)   
  5. {  
  6.   try   
  7.   {  
  8.     setContext(request);  
  9.   // take off the last token   
  10.     String ipAddressToken = cookieTokens[cookieTokens.length-1 ];  
  11.     if (!getUserIPAddress(request).equals(ipAddressToken))  
  12.     {  
  13.           throw   new  InvalidCookieException("Cookie IP Address did not   
  14. contain a matching IP (contained '" + ipAddressToken + "' )");  
  15.     }  
  16.         
  17.     return   super .processAutoLoginCookie(Arrays.copyOf(cookieTokens,   
  18. cookieTokens.length-1 ), request, response);  
  19.   }  
  20.   finally   
  21.   {  
  22.     setContext(null );  
  23.   }  
  24. }  

 我们的自定义的 RememberMeServices 编码已经完成了。现在我们要进行一些微小的配置。这个类的完整源代码(包括附加的注释)都在本章的源码中能够找到。

 

配置自定义的 RememberMeServices

配置自定义的 RememberMeServices 实现需要两步来完成。第一步是修改 dogstore-base.xml Spring 配置文件,以添加我们刚刚完成类的 Spring Bean 声明:

 

 

Xml代码  收藏代码
  1. < bean   class = "com.packtpub.springsecurity.security.IPTokenBasedRememberMeServices"   id = "ipTokenBasedRememberMeServicesBean" >   
  2.   < property   name = "key" > < value > jbcpPetStore </ value > </ property >   
  3.   < property   name = "userDetailsService"   ref = "userService" />   
  4. </ bean >   

 第二个要进行的修改是 Spring Security XML 配置文件。修改 <remember-me> 元素来引用自定义的 Spring Bean ,如下所示:

 

Xml代码  收藏代码
  1. < remember-me   key = "jbcpPetStore"    
  2.    services-ref = "ipTokenBasedRememberMeServicesBean" />   

 最后为 <user-service> 声明添加一个 id 属性,如果它还没有添加的话:

 

Xml代码  收藏代码
  1. < user-service    id = "userService" >   

 重启 web 应用,你将能看到新的 IP 过滤功能已经生效了。

 

因为 remember me cookie Base64 编码的,我们能够使用一个 Base64 解码的工具得到 cookie 的值以证实我们的新增功能是否生效。如果我们这样做的话,我们能够看到一个名为 SPRING_SECURITY_REMEMBER_ME_COOKIE cookie 的内容大致如下所示:

guest:1251695034322:776f8ad44034f77d13218a5c431b7b34:127.0.0.1

 

正如我们所料,你能够看到 IP 地址确实存在于 cookie 的结尾处。在 IP 地址之前,你还能够分别看到用户名、时间戳以及 MD5 的哈希值。

 

【调试 remember me cookie 。在尝试调试 remember me 功能时,会有两个难点。第一个就是得到 cookie 的值本身! Spring Security 并没有提供记录我们设置的 cookie 值的日志级别。我们推荐使用基于浏览器的工具如 Mozilla Firefox 下的 Chris Pederick's Web Developer 插件( http://chrispederick.com/work/web-developer/ )。基于浏览器的开发工具一般允许查看(甚至编辑) cookie 的值。第二个困难(相对来说较小)就是解码 cookie 的值。你能使用在线或离线的 Base64 解码工具来对 cookie 的值进行解码(需要记住的是添加一个等号符( = )结尾,以使其成为一个合法的 Base64 编码值)。】

 

如果用户是在一个共享的或负载均衡的网络设施下,如 multi-WAN 公司环境,基于 IP remember me tokens 可能会出现问题。但是在大多数场景下,添加 IP 地址到 remember me 功能能够为用户提供功能更强、更好的安全层。

 

 

自定义 Remember me 的签名

好奇的读者可能会关心 remember me form checkbox 名( _spring_security_remember_me )以及 cookie 的名( SPRING_SECURITY_REMEMBER_ME_COOKIE ),是否能够修改。 <remember-me> 声明是不支持这种扩展性的,但是现在我们作为一个 Spring Bean 声明了自己的 RememberMeServices 实现,那我们能够定义更多的属性来改变 checkbox cookie 的名字:

 

 

Xml代码  收藏代码
  1. < bean   class ="com.packtpub.springsecurity.web.custom.  
  2. IPTokenBasedRememberMeServices" id = "ipTokenBasedRememberMeServicesBean" >   
  3. < property   name = "key" > < value > jbcpPetStore </ value > </ property >   
  4.   < property   name = "userDetailsService"   ref = "userService" />   
  5.   < property   name = "parameter"   value = "_remember_me" />   
  6.   < property   name = "cookieName"   value = "REMEMBER_ME" />   
  7. </ bean >   
 

 

不要忘记的是,还需要修改 login.jsp 页面中的 checkbox form 域以与我们声明的 parameter 值相匹配。我们建议你进行一下实验以确保理解这些设置之间的关联。

(如果想更好的理解本章节内容,建议阅读一下 Spring Security 的源码——译者注)

分享到:
评论

相关推荐

    《Spring Security3》第四章第四部分翻译(Remember me后台存储和SSL)附前四章doc文件

    《Spring Security3》第四章第四部分主要探讨了Remember me服务的后台存储机制以及如何结合SSL(Secure Sockets Layer)来增强应用的安全性。这一部分的知识点涵盖了Spring Security中Remember me的功能,用户身份...

    Spring Security3中文文档

    文档的翻译者lengyun3566在博客中提到,他翻译了Spring Security3的文档,并在每篇文章的开头强调了版权信息,要求转载时必须注明出处。这表明了作者对知识产权的尊重以及对读者的责任感。 ### 第一章:Spring ...

    spring security3 中文版本

    自此之后,Spring Security 成为了 Spring 生态系统中的一个重要组成部分,不断迭代更新,以适应不断变化的安全需求和技术发展。 ##### 1.3 发行版本号 Spring Security 3.0.1 是在 Spring Security 3.0 的基础上...

    Spring Security 资料合集

    - 默认情况下,Spring Security 开启了跨站请求伪造(CSRF)防护,通过生成并验证CSRF令牌,防止恶意第三方发起未经授权的操作。 6. **表达式式语言**: - Spring Security 使用一种强大的表达式语言(EL),如`...

    springSecurity3例子

    - Spring Security 3引入了CSRF(跨站请求伪造)防护,通过添加一个不可预测的令牌到表单提交中,防止恶意第三方发起未经授权的操作。 5. **国际化支持**: - 支持多语言界面,可以根据用户的首选语言显示错误...

    springsecurity学习笔记

    7. **OAuth2 and JWT支持**:Spring Security 提供了对OAuth2和JSON Web Tokens (JWT) 的支持,这在现代微服务架构中非常重要,因为它允许第三方应用安全地与你的服务进行交互。 8. **表达式语言(SpEL)**:Spring...

    springsecurity3x快速构建企业级安全

    - Spring Security 3.x也可以与OAuth2协议集成,支持第三方服务的授权,提供安全的API访问。 8. **自定义扩展** - Spring Security的灵活性允许开发者根据需求自定义认证和授权策略,可以通过实现接口或继承类来...

    Spring Security3

    #### 第三章:增强用户体验 **自定义登录页面** - 通过自定义登录页面提高用户体验,可以更好地融入网站的设计风格。 **实现Remember-Me功能** - **原理**:记住用户的登录状态,下次访问时自动登录。 - **实现**...

    Spring Security 教程(Spring Security Tutorial)1

    - OAuth 2.0 是一个开放标准,用于授权第三方应用访问用户资源。Spring Security 支持 OAuth 2.0,可以帮助开发者构建安全的授权服务器和资源服务器。 通过这个教程,你将了解 Spring Security 的核心概念,并能...

    SpringSecurity源码

    7. **OAuth2支持**:SpringSecurity还支持OAuth2协议,提供了一种安全的第三方应用访问资源的方式。 8. **Remember-Me服务**:允许用户在一段时间内无须再次输入登录凭据,提高用户体验。 9. **自定义扩展**:...

    spring security 3.x第五章例子

    Spring Security 是一个强大的和高度可定制的身份验证和...总的来说,Spring Security 3.x第五章的实例将帮助开发者深入理解这个框架的使用,通过具体的代码示例来实践安全性配置,从而更好地保护他们的Spring应用。

    Spring Security安全权限管理手册 html

    - Spring Security也支持OAuth2协议,允许第三方应用获取资源服务器上的数据,同时提供了客户端和资源服务器的实现。 8. **异常处理**: - 当认证或授权失败时,Spring Security会抛出相应的异常,如...

    Spring Security 安全权限管理手册 PDF

    《Spring Security 安全权限管理手册》是一本深入解析Spring Security框架的专业指南,对于正在学习或已经在使用Spring框架的开发者来说,它提供了丰富的知识和实践经验。Spring Security是Spring生态系统中的一个...

    spring security3中文文档

    #### 第三章:增强用户体验 - **自定义登录页**: - **实现自定义的登录页**:提供具体实现步骤。 - **理解退出功能**: - **在站点页头上添加“LogOut”链接**:说明如何在网站中添加退出链接。 - **退出是怎么...

    springsecurity3.1.pdf

    标题:springsecurity3.1.pdf 描述:springsecurity3.1.pdf 标签:spring security3.1 部分内容:SpringSecurity Reference Documentation by Ben Alex and Luke Taylor 3.1.4.RELEASE **一、Spring Security 3.1...

    Spring Security3 中文版 张卫滨 推荐

    根据给定的信息,我们可以从《Spring Security3 中文版》一书中提炼出多个重要的知识点,主要涉及Spring Security的基础概念、具体实现以及高级配置等方面。下面将详细解释每一部分的关键内容。 ### 第一章:一个不...

    Spring Security 源码

    Spring Security支持OAuth2协议,允许第三方应用通过授权获取用户资源。这对于构建API或微服务环境中的身份验证和授权非常有用。 9. **配置**: Spring Security的配置可以通过XML、Java配置或者使用`@...

    SpringSecurity素材.zip

    SpringSecurity是Java领域中一款强大的安全框架,专为Web应用程序设计,用于实现身份验证和授权。这个名为"SpringSecurity素材.zip"的压缩包文件很可能包含了关于如何使用SpringSecurity进行安全控制的各种资料。...

    spring参考文档及SpringSecurity参考文档

    3. **CSRF(跨站请求伪造)防护**:防止恶意第三方模拟用户发送请求。 4. **会话管理**:包括会话固定保护、会话超时检测等功能,增强了系统的安全性。 5. **Remember Me服务**:允许用户在一段时间内免登录访问系统...

Global site tag (gtag.js) - Google Analytics