热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

springsecurity源码分析之二web包分析

Spring是一个非常流行和成功的Java应用开发框架。SpringSecurity基于Spring框架,提供了一套Web应用安全性的完整解决方案。一般来说,Web应用的安全性包括

Spring 是一个非常流行和成功的 Java 应用开发框架。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

对于上面提到的两种应用情景,Spring Security 框架都有很好的支持。在用户认证方面,Spring Security 框架支持主流的认证方式,包括 HTTP 基本认证、HTTP 表单验证、HTTP 摘要认证、OpenID 和 LDAP 等。在用户授权方面,Spring Security 提供了基于角色的访问控制和访问控制列表(Access Control List,ACL),可以对应用中的领域对象进行细粒度的控制。

本文先从web包来分析spring-security提供的安全保护。

1. access模块:

技术分享

其中,ExceptionTranslationFilter:处理过滤器链抛出的所有AccessDeniedException和AuthenticationException异常.

WebInvocationPrivilegeEvaluator:允许用户来决定他们是否有访问特定web url的权限。

   1.1 channel包:确保从指定传输通道接收web请求。

技术分享

其中,

ChannelProcessingFilter: 确保一个web请求通过要求的channel。在内部使用FilterInvocation来表示request请求,允许使用FilterInvoctionSecurityMetaDataSource来查询应用之上的属性。
代理ChannelDecisionManager来处理真实的通道安全Decision和必须的action。若响应由ChannelDecisionManager来提交,ChannelProcessingFilter将不会处理。

下面的示例强制将登陆表单和对/secure路径下的访问都通过https来访问。

<bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter">
  <property name="channelDecisionManager" ref="channelDecisionManager"/>
  <property name="securityMetadataSource">
    <security:filter-security-metadata-source path-type="regex">
      <security:intercept-url pattern="\A/secure/.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
      <security:intercept-url pattern="\A/login.jsp.*\Z" access="REQUIRES_SECURE_CHANNEL"/>
      <security:intercept-url pattern="\A/.*\Z" access="ANY_CHANNEL"/>
    security:filter-security-metadata-source>
  property>
bean>

<bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl">
  <property name="channelProcessors">
    <list>
    <ref bean="secureChannelProcessor"/>
    <ref bean="insecureChannelProcessor"/>
    list>
  property>
bean>

<bean id="secureChannelProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor"/>
<bean id="insecureChannelProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor"/>
channelDecisionManager:确定一个web channel是否提供了足够的安全性。
ChannelProcessor:确定一个web channel是否满足特定安全条件。
ChannelEntryPoint:由ChannelProcessor使用来启动一个web channel。

 1.2 expression包:

   技术分享

SecurityExpressionHandler 是一个门面,它将内在的表达式对象实现和spring security对安全表达式的需求分离开来。

DefaultWebSecurityExpressionHandler是SecurityExpressionHandler的默认实现。

    protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
        WebSecurityExpressionRoot root = new WebSecurityExpressionRoot(authentication, fi);
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(trustResolver);
        root.setRoleHierarchy(getRoleHierarchy());
        return root;
    }

 1.3 intercept包:增强http请求的安全性,特别是url请求。

   技术分享

其中,FilterSecurityInterceptor 通过实现了filter来增加http资源的安全性。这个安全拦截器需要FilterInvocationSecurityMedataSource。

2. authentication模块

认证处理机制,支持多种协议如BASIC,CAS,form login等提交认证信息。

    2.1 logout和rememberme 包

技术分享

 其中

  LogoutFilter记录用户的退出,它包含了一组Logouthandler。这些hangler应用按照顺序排序,顺序是你想调用TockenBasedRememberMeServices和securityContxtLogoutHander的顺序。退出后,将由LogoutSucessHandler或者LogoutSuccesUrl来决定跳转到哪里。到底由谁确定依赖于创建LogoutFilter使用的构造方法。

  RememberMeAuthenticationFilter检查SecurityContext中是否有Authentication对象,并且当有RememberMeServices实现了该请求时将一个remember-me authentication token设置到SecurityContext中。这个过滤器会调用RememberMeServices实现的autoLogin方法,如果上述方法返回一个非空的Authentication对象,会被传递到AuthenticationManager,这样任何特定authentication将可以完成。若Authentication结果返回成功,它将会被设置到SecurityContext中。

  如果认证成功,一个InteractiveAuthenticationSuccessEvent时间将会发布到application context中,若认证不成功,则不会有事件发布,因为不成功的话会记录成特定AuthenticationManager的应用事件。 正常情况下,不管Authentication是成功还是失败,都会允许处理请求request。如果需要控制特定认证用户的访问目的,可以将AuthenticationSuccessHandler注入其中。

  2.2 peauth包

  支持已认证的场景--spring 假定请求request已经被外部配置系统认证通过的场景。

技术分享

AuthenticationDetailsSource:给特定的web请求request提供一个Authentication接口提供一个getDetails()方法

J2eePreAuthenticatedProcessingFilter:基于j2ee容器认证机制的过滤器,它将使用j2ee 用户principal名称作为预先完成认证的principal。

WebSpherePreAuthenticatedProcessingFilter:基于Websphere认证的过滤器,它将使用Websphere RunAs 用户principal名称作为先完成认证的principal。

X509AuthenticationFilter:负责处理要求未认证用户提供客户端证书的请求。如果这个请求包含了合法的证书,它将会使SubjectDnX509PrincipalExtractor抽取出安全实体.

RequestHeaderAuthenticationFilter:一个简单的预先认证完成过滤器,它从用户的请求头获取用户名,使用在诸如CA siteminder系统等。

  2.3 session和switchuser

  session包:提供一个新认证用户处理session相关行为的策略接口和实现类

  switchuser包:提供一个基于http的具有切换用户能力的包。类似于linux中的su命令。

技术分享

 SessionAuthenticationStrategy:在一次认证过程中对httpSession相关的行为允许可插拔支持。典型应用场景是确认session是否存在或者改变session id来保证基于session攻击的安全。

SwitchUserFilter:高权限用户向低权限用户切换 。

  2. 4 ui包

DefaultLoginPageGeneratingFilter:当一个用户没有配置login页面时使用。仅当跳转到login页面时用到。

  2.5 www包

  BasicAuthenticationFilter:处理一个http请求的basic认证头,将结果放入SecurityContextHolder。

总之,该过滤器负责处理具有basic认证scheme和base64编码的username:password token的http请求头消息.例如,认证一个名为"Aladdin"的用户,其密码为“open sesame” ,其头部如下:

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

该过滤器不但可以用来为远程协议客户端(如hessian和soap)提供basic认证服务,还可以为标准的用户代理(如ie和netscape)提供basic认证服务。如果认证成功,认证结果Authentication对象将会放入SecurityContextHolder之中。如果认证失败并且设置为false(默认),将会调用AuthenticationEntryPoint实现类(除非属性被设置为true)。通常情况下是BasicAuthenticationEntryPoint,它提醒用户通过Basic认证方式重新认证。因basic认证协议的简单和广泛部署,它是一个非常有吸引力的协议。然而,由于该协议通过明确的text传递密码,因此它不适用于很多应用场景。spring security提供的Digest认证可以在这些场景中替换Basic认证。

注意:若设置了RememberMeService,该filter将自动给用户返回remember-me细节。

  DigestAuthenticationFilter:参照BasicAuthenticationFilter,注意:digest认证的缺点,尽管digest认证方式比basic认证方式更全面、更安全,但Rfc2617第四部分详细讨论了digest认证方式比basic认证方式的好处,也论述了digest的缺陷。

3.bind模块

  AuthenticationPrincipal注解:绑定一个方法的参数或者方法到Authentication的getPrincipal()方法。必须指明,参数应该解析到当前用户而不是可以在表单编辑的用户。示例如下:

 @Controller
public class MyController {
    @RequestMapping("/user/current/show")
     public String show(@AuthenticationPrincipal CustomUser customUser) {
         // do something with CustomUser
         return "view";
     }

AuthenticationPrincipalArgumentResolver:解析AuthenticationPrincipal注解。上述例子也可以这样做:

@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@AuthenticationPrincipal
public @interface CurrentUser {
  }

  @Controller
  public class MyController {
      @RequestMapping("/user/current/show")
      public String show(@CurrentUser CustomUser customUser) {
          // do something with CustomUser
          return "view";
      }

4.上下文context模块

技术分享

同步SecurityContextPersistenceFilter:从配置的SecurityContextRepository而不是request中获取信息存到SecurityContextHolder,并且当请求结束清理contextHolder时将值存回repository中(默认使用HttpSessionSecurityContextRepository).在该过滤器中每一个请求仅执行一次,该filter需在任何认证处理机制其作用之前执行。认证处理机制如basic,cas等期望在执行时从SecurityContextHolder中获取SecurityContext。

异步WebAsyncManagerIntegrationFilter:提供了对securityContext和WebAsyncManager的集成。方式是通过SecurityContextCallableProcessingInterceptor的beforeConcurrentHandling(NativeWebRequest, Callable)方法来讲SecurityContext设置到Callable上。

SecurityContextCallableProcessingInterceptor:支持spring mvc Callable集成。当SecurityContextCallableProcessingInterceptor执行preProcess(NativeWebRequest, Callable)方法时将注入的SecurityContext传递给SecurityContextHolder。

    @Override
    public  void preProcess(NativeWebRequest request, Callable task) throws Exception {
        SecurityContextHolder.setContext(securityContext);
    }

同样清楚的是,SecurityContextCallableProcessingInterceptor在执行postProcess(NativeWebRequest, Callable, Object)方法时调用SecurityContextHolder的clearContext()。

    @Override
    public  void postProcess(NativeWebRequest request, Callable task, Object concurrentResult) throws Exception {
        SecurityContextHolder.clearContext();
    }

5 csrf模块

Cross-site request forgery跨站请求伪造,也被称为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

CsrfException:当一个HttpServletRequest没有有效的CsrfToken或者没有CsrfToken时抛出的异常,有两个子类:InvalidCsrfTokenException和MissingCsrfTokenException。

CsrfToken提供了一个期望的csrf token信息。默认实现为DefaultCsrfToken,还有一个内部实现类SaveOnAccessCsrfToken。

CsrfTokenRepository:将crsfToken与HttpServletRequest关联起来,使之能关联CsrfToken的api。例如,可以存储到HttpSesssion中。默认实现为HttpSessionCsrfTokenRepository。

 CsrfFilter:通过使用同步token模式来进行csrf防护。

CsrfLogoutHandler 负责在退出时移除csrfToken。调用时在LogoutFilter中的logout方法中:

            for (LogoutHandler handler : handlers) {
                handler.logout(request, response, auth);
            }

6. Debug模块

  DebugFilter:spring security的调试过滤器。为帮助用户理解请求request是如何被spring security处理的,使用日志记录诸如session创建等消息。同时也会记录一些别的相关消息。

  Logger封装了apache commons-logging。

7.firewall模块

  HttpFirewall接口时为了阻止潜在威胁的请求而将请求进行封装来控制这些请求的行为的接口。

 DefaultHttpFirewall是默认实现。主要是检查一个路径是否合法:

 /**
     * Checks whether a path is normalized (doesn‘t contain path traversal sequences like "./", "/../" or "/.")
     *
     * @param path the path to test
     * @return true if the path doesn‘t contain any path-traversal character sequences.
     */
    private boolean isNormalized(String path) {
        if (path == null) {
            return true;
        }

        for (int j = path.length(); j > 0;) {
            int i = path.lastIndexOf(‘/‘, j - 1);
            int gap = j - i;

            if (gap == 2 && path.charAt(i+1) == ‘.‘) {
                // ".", "/./" or "/."
                return false;
            } else if (gap == 3 && path.charAt(i+1) == ‘.‘&& path.charAt(i+2) == ‘.‘) {
                return false;
            }

            j = i;
        }

        return true;
    }

FirewalledRequest是个抽象类,是请求request的封装,返回一个HttpFirewall接口。不同之处在于reset方法,该方法允许当请求离开security filter chain时重置部分或者全部状态。默认实现为RequestWrapper。

8. header模块

技术分享

HeaderWriter是一个向HttpServletResponse写入http请求头的约定。

HeaderWriterFilter向当前请求中增加http请求头的过滤器,为浏览器保护增加特定的http请求头。如X-FRAME-options(X-Frame-Options response header 可用于指示是否应该允许浏览器呈现在一个页面 或 中. 以确保网站内容是不是嵌入到其它网站. )、x-xss-protection(在正常情况下,通过下面的HTTP header,就可以完美的关闭发送这个header的页面XSS保护特性了。X-XSS-Protection: 0)和x-content-type-options(这个header主要用来防止在IE9、chrome和safari中的MIME类型混淆攻击。firefox目前对此还存在争议。通常浏览器可以通过嗅探内容本身的方法来决定它是什么类型,而不是看响应中的content-type值。通过设置 X-Content-Type-Options:如果content-type和期望的类型匹配,则不需要嗅探,只能从外部加载确定类型的资源。)。

9.session模块

ConcurrentSessionFilter:这个filter有两个功能。第一:它调用SessionRegistry的refreshLastRequest(String)方法来保证注册的session通常拥有正确的最后一次更新时间。

第二:它从每个请求的SessionRegistry中检索SessionInformation,并检查session是否已经标示为过期。若标示为过期,则调用配置的所有logout handler(在LogoutFilter中调用),通常的场景是使session过期。此时会跳转到指定的expiredURL,session过期会通过注册在的HttpSessionEventPublisher产生一个HttpSessionDestroyedEvent事件。

10 小结

   Spring Security对Web安全性的支持大量地依赖于Servlet过滤器。这些过滤器拦截进入请求,并且在应用程序处理该请求之前进行某些安全处理。 Spring Security提供有若干个过滤器,它们能够拦截Servlet请求,并将这些请求转给认证和访问决策管理器处理,从而增强安全性。

参考文献:

1. http://www.ibm.com/developerworks/cn/java/j-lo-springsecurity/

2. http://baike.baidu.com/link?url=mk6ZedYayBqvXehW094XdImcU9g2SGLgt-gmdKYAF17db97_mEloPPm3K-1eqqEymefNNO30b2CTGw2Ryf6amq

spring security源码分析之二---web包分析


推荐阅读
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
author-avatar
爱碩爱你_静莫失心
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有