免费发布信息
当前位置:APP交易 > 热点资讯 > 资产交易 >  JavaWeb中的权限控制——Spr

JavaWeb中的权限控制——Spr

发表时间:2021-07-09 16:53:50  来源:红帽社区  浏览:次   【】【】【
红帽社区是一个垂直网络安全社区,融合“红帽先锋”正能量精神,每日分享最新安全资讯,提供安全问答、靶场、众测、漏洞库等功能,是网络安全爱好者学习、交流的优质社区。

SpringSecurity概述

   Spring Security是一个灵活、强大和可定制的身份验证和访问控制框架,以确保基于Spring的Java Web应用程序的安全。

  Spring Security是基于Spring AOP和Servlet过滤器的安全框架。通过若干个过滤器,它们能够拦截Servlet请求,并将这些请求转给认证和访问决策管理器处理,增强应用的安全性。

  相关特点:

  • 对身份验证和授权提供全面可拓展的支持
  • 可防御会话固定、点击劫持、csrf跨站请求伪造等攻击
  • Servlet API集成
  • 方便集成,Spring Boot 对于 Spring Security 提供了自动化配置方案,可以零配置使用Spring Security

工作方式

  spring security内部其实是通过一个过滤器链来实现认证流程的:
permission_Audit14.png
  常见的例如AuthenticationProcessingFilter处理用户登陆相关的操作,ExceptionTranslationFilter用于处理异常并返回对应的页面或者状态码,SessionFixationProtectionFilter用于防止csrf攻击,还有主要用户权限控制的FilterSecurityInterceptor等。
  简单的过滤器链如下:
  以认证授权流程为例,UsernamePasswordAuthenticationFilter用于拦截我们通过表单提交接口提交的用户名和密码,然后在AuthenticationProcessingFilter处理用户登陆认证相关的操作,最后的FilterSecurityInterceptor是首先判断我们当前请求的url是否需要认证,如果需要认证,那么就看当前请求是否已经认证,是的话就放行到我们要访问的接口,否则重定向到认证页面。
permission_Audit15.png

相关依赖

  要使用Spring Security需要引入spring-security-web和spring-security-config:
图片.png
  在Spring Boot中使用Spring Security非常容易,引入spring-boot-starter-security依赖即可。

用户认证与授权

  Spring Security中进行身份验证的是AuthenticationManager接口,ProviderManager是它的一个默认实现,但它并不用来处理身份认证,而是委托给配置好的AuthenticationProvider,每个AuthenticationProvider会轮流检查身份认证。检查后或者返回Authentication对象或者抛出异常。
  Spring Security其支持在内存中设置身份验证,可以直接在配置文件中配置:
图片.png
  注解形式:

@Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter{ @Autowired public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception{ auth.inMemoryAuthentication().withUser("test").password("123456").roles("USER"); } }

  实际开发中用于验证的用户一般都存储在数据库中,上述方式明显不太合适,那么就需要在AuthenticationProvider中创建基于数据库自定义UserDetailsService进行相关的认证操作。下面是相应实现的流程:
  验证身份就是加载响应的UserDetails,看看是否和用户输入的账号、密码、权限等信息匹配。此步骤由实现AuthenticationProvider的DaoAuthenticationProvider(它利用UserDetailsService验证用户名、密码和授权)处理。包含 GrantedAuthority 的 UserDetails对象在构建 Authentication对象时填入数据。
图片.png
  举例如下,因为Spring Security是通过委托AuthenticationProvider进行认证的,那么首先需要在其配置中注入userDetailsService():
图片.png
  若使用注解方式的话通过auth.userDetailsService()方法即可。
  根据上述配置,可以直接定位到userDetailsService的具体实现在com.work.security.UserDetailsServiceImpl。
  在loadUserByUsername()方法,根据username查询用户实体,可以实现该接口覆盖该方法,实现自定义获取用户过程。

public class UserDetailService implements UserDetailsService{ @Autowired private IUserService userService; @Overrid public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{ UserDetails userDetails=null; try{ com.security.entity.user user = this.userService.Login(username); Collection<GrantedAuthority> authList = getAuthorities(user.getRole()); userDetails = new User(username,user.getPassword,true,true,true,true,authList); }catch(Exception e){ //TODO:handle exception throw new UsernameNotFoundException(username); } return userDetails; } //获取当前登陆用户的角色权限 private Collection<GrantedAuthority> getAuthorities(String role){ List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(); if(role.equals("ROLE_ADMIN")){ authList.add(new SimpleGrantedAuthority("ROLE_ADMIN")); }else{ authList.add(new SimpleGrantedAuthority("ROLE_STATIC)); } return authList; } }

其他配置

  除了认证授权以外,还有很多强大的过滤器可以进行相关的安全防护,例如csrf防护、单点登录限制等,均可以通过相关的标签或者方法进行实现:
permission_Audit17.png

权限控制方式

  通过UserDetailsService完成用户认证以及权限角色赋予后,可以结合以下方式完成相关的权限控制:

通过HttpSecurity对象

  Spring Security的配置文件命名空间配置中的<http>元素。它允许对特定的http请求基于安全考虑进行配置。
  例如如下配置,pattern代表匹配的路径,security="none"表示放行,不进行拦截及权限检查:

<http pattern="/static/**" security="none"></http>

  通过其子元素<intercept-url>可以对相关接口进行权限控制。例如/system下的所有接口仅仅只有ROLE_ADMIN,ROLE_USER权限的用户才可以访问,login接口支持匿名访问:

<intercept-url pattern="/system/**" access="ROLE_ADMIN,ROLE_USER" /> <intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>

  此外,还可以通过SpEL表达式进行配置,可以通过<http>元素的use-s来设置(默认为true,开启),例如下面的例子,用户匹配ROLE_ADMIN,ROLE_USER其中的任何一个均可放行:

<http auto-config="true" use-s="true"> <intercept-url pattern="/system/**" access="hasRole('ROLE_USER','ROLE_ADMIN')"/> </http>

  常用的有:

表达式 功能
hasRole([role]) 用户拥有指定的角色role时候返回true
hasAnyRole([role1,role2]) 用户拥有role1,role2任意一个指定的角色时返回true
permitAll 任何用户均可访问
hasIpAddress (ipAddress) 匹配一个请求的IP地址
denyAll 任何用户都不可以访问
authenticated 检查用户是否认证通过
anonymous 匿名用户即可访问

  除此之外,也可以使用@EnableWebSecurity注解,然后继承适配器WebSecurityConfigurerAdapter,通过HttpSecurity对象的相关配置进行权限控制。主要是通过http.authorizeRequests()方法,通过每个子匹配器进行相关的权限声明。例如下面的例子:

protected void configure(HttpSecurity http ) throws Exception { http.authorizeRequests() .antMatchers( "/resources/**", "/signup" , "/about").permitAll()//permitAll代表这类资源任何用户均可访问 .antMatchers( "/admin/**").hasRole("ADMIN" )//只有具有ROLE_ADMIN角色的用户才能访问/admin开头的接口 .antMatchers( "/db/**").access("hasRole('ADMIN') and hasRole('DBA')") //同时拥有ROLE_ADMIN和ROLE_DBA角色的用户才能访问/db开头的接口 .anyRequest().authenticated()//没有匹配的请求只需要用户认证成功即可访问 // ... .formLogin(); }

  通过antMatchers方法即可定义什么样的请求可以放过,什么样的请求需要验证。也可以通过regexMatchers()方法通过正则表达式来定义请求路径。

通过相关标签

  在实际业务场景中,对于已登陆的用户角色,需要根据不同的权限对view层进行保护,显示/隐藏Web应用程序的JSP/View。例如查看所有用户信息的页面仅仅只有管理员角色才可以查看。对于普通用户来说需要隐藏。

  在jsp页面中我们可以使用spring security提供的权限标签来进行权限控制,需要引入spring security-taglibs标记库的依赖库:

<dependency> <groupId>org.springwork.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>5.0.1.RELEASE</version> </dependency>

  然后通过在jsp页面中引入标签库,通过对应的标签来实现:

<%@taglib uri="http://www.springwork.org/security/tags" prefix="security"%>

  常见的标签如下:

标签 功能
<security:authenticatio> 获取当前认证对象信息,例如用户名
<security:authorize> 若当前用户满足特定权限,则显示标签范围的内容
<security:accesscontrollist> 若认证用户具有权限列表中的某一个权限,那这个标签范围的内容将显示(一般用于鉴定ACL权限)

  例如下面的例子:

  只有拥有ADMIN角色的用户才能查看相关的页面:

<%@ taglib prefix="sec" uri="http://www.springwork.org/security/tags"%> <div> <sec:authorize access="hasRole("ADMIN)"> ...... <form name="contact-form" class="contact-form" method="post" action="./deleteUser/ByUserId"> ...... </sec:authorize> </div>

通过权限注解

  Spring Security默认是禁用注解的,要想开启注解,有以下方式:

  • 继承WebSecurityConfigurerAdapter并且加上@EnableGlobalMethodSecurity注解,并在该类中将AuthenticationManager定义为Bean:

  例如下面是开启了secured的注解支持:

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(securedEnabled=true) public class CasSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired AuthenticationManager authenticationManager; }

  • 在配置文件中开启注解支持:

<security:global-method-security pre-post-annotations="enabled"> <security:global-method-security jsr250-annotations="enabled"> <security:global-method-security secured-annotations="enabled">

  常见的注解:

  • securedEnabled

  开启@Secured 注解过滤权限,可以在需要安全[角色/权限等]的方法上指定 @Secured,并且只有那些角色/权限的用户才可以调用该方法。如果有人不具备要求的角色/权限但试图调用此方法,将会抛出AccessDenied异常。但是有一个缺点是,无法满足&&的关系(例如角色同时为admin和system时才能调用该接口)。

  例如下面的例子:

import org.springwork.security.access.annotation.Secured; public interface UserService{ @Secured("ROLE_ADMIN")//具备ROLE_ADMIN角色的用户才可以访问 List<User> findAllUsers(); @Secured({"ROLE_ADMIN","ROLE_USER"})//具备ROLE_ADMIN或者ROLE_USER角色的用户均可以访问。 User getUserByName(String name); ...... }

  • jsr250Enabled

  主要用于提供角色的权限约束,常用注解有:

注解 功能
@DenyAll 拒绝所有访问
@PermitAll 允许所有访问
@RolesAllowed({“USER”, “ADMIN”}) 具有"USER", "ADMIN"任意一种权限就可以访问。
  • prePostEnabled

  基于表达式的注解,可以自定义扩展。主要包括以下注解:

注解 功能
@PreAuthorize 在方法调用之前,基于表达式的结果来限制对方法的访问
@PostAuthorize 在方法执行后再给予表达式的结果进行权限验证,适合验证带有返回值的权限
@PostFilter 在方法执行之后执行,这里可以调用方法的返回值,然后对返回值进行过滤或处理或修改并返回。
@PreFilter 在方法执行之前执行,而且这里可以调用方法的参数,然后对参数值进行过滤或处理或修改。

  比较常用的是@PreAuthorize和@PostAuthorize。

  例如下面的例子:

  通过@PostAuthorize注解确保登录用户只能获取他自己的用户对象防止平行越权,还有在调用删除用户的方法前先检查是否具有ADMIN角色权限:

import org.springwork.security.access.prepost.PostAuthorize; import org.springwork.security.access.prepost.PreAuthorize; ...... public interface UserService{ @PostAuthorize("returnObject.type == authentication.name ") User findById(int id); @PreAuthorize("hasRole('ADMIN')") boolean deleteUser(int id) ...... }

审计要点

  权限控制相关的审计要点有:

平行越权

  SpringSecurity可以通过如下方法获取当前用户:

SecurityContextHolder.getContext().getAuthentication()

  一般来说,使用类似@PostAuthorize注解可以比较好的解决平行越权的问题,但是在多表关联的场景下很难进行覆盖。所以针对类似的业务接口还是需要进行相关的检查。

垂直越权

  一般使用标签库对普通用户与管理员用户的在view层页面上进行了区分,但是没有细粒度覆盖接口,认为只要在界面上没法操作就可以防止垂直越权了。
  例如下面的例子,通过<sec:authorize>标签,在view层进行了限制,仅仅拥有ADMIN角色的用户才能查看到删除用户对应的功能模块:

<div> <sec:authorize access="hasRole('ADMIN')"> <form action="${pageContext.request.contextPath}/system/delete" method="POST"> ......... </form> </sec:authorize> </div>

  可以直接定位/system/delete接口,结合配置文件查看对应的权限细粒度覆盖.
  在安全配置时仅仅考虑到了未授权访问的问题:

<http use-="false"> <intercept-url pattern="login" access="IS_AUTHENTICATED_ANONYMOUSLY"/> <intercept-url pattern="/system/**" access="ROLE_USER"/> ......

  再查看实际的接口鉴权,可以看到接口处也没有任何的权限注解,也就是说只要通过登陆认证,以普通用户的角色也可以访问管理员删除用户的接口:

@RequestMapping("/delete") public Boolean deleteUser(String userId){ Boolean result = userservice.deleteById(userId); return result; }

Tips:在进行审计时,可以先在view层搜索对应的SpringSecurity标签关键字(例如<sec:authorize>),然后查看对应隐藏/显示的接口,通过检查相关的权限配置以及接口具体实现,快速寻找垂直越权缺陷

静态资源

  一般静态资源和登陆接口可以非登陆状态下匿名使用,一般在对应的权限配置中会做如下配置:

<http pattern="/common/**" security="none"/> <http pattern="/*.pdf" security="none"/>

  或者是如下方式:

antMatchers("/","/login**", "/webjars*", "/static*").permitAll()

  但是部分静态文件可能存在未授权访问,例如网站部分业务的模版文件、内部资料,或者是通过相关接口道出的统计Excel表、PDF单据等,都可能存在匿名下载的风险。

  所以可以定位相关的目录,审计目录下的内容以及可能关联的接口。

权限绕过

  同时还需要进行版本检查,避免相关的权限绕过:

  • CVE-2010-3700: Spring Security bypass of security constraints
    • 影响范围:(需部署在IBM WebSphere Application Server (WAS) 6.1 and 7.0容器中)
      • Spring Security
        • 3.0.0 to 3.0.3
        • 2.0.0 to 2.0.5
  • CVE-2016-5007 Spring Security / MVC Path Matching Inconsistency
    • 影响范围
      • Spring Security
        • 3.2.x,4.0.x,4.1.0
      • 具体分袖参考CVE-2016-5007,跟之前的shiro绕过权限控制原理类似。
  • CVE-2016-9879 Encoded “/” in path variables
    • 影响范围(需部署在IBMWebSphereApplication Server 8.5.x 的容器中)
      • SpringSecurity
        • 3.2.0 - 3.2.9
        • 4.0.x - 4.1.3
        • 4.2.0
        • 旧的不维护的版本也会受到影响
  • CVE-2018-1199: Security bypass with static resources
    • 影响范围
      • Spring Security
        • 4.1.0 - 4.1.4
        • 4.2.0 - 4.2.3
        • 5.0.0

参考资料

https://docs.spring.io/spring-security/site/docs/current/reference/html5/

责任编辑:
声明:本平台发布的内容(图片、视频和文字)以原创、转载和分享网络内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。

德品

1377 678 6470