【问题标题】:Spring Security - Url with request parameters rules ignoredSpring Security - 忽略请求参数规则的 URL
【发布时间】:2012-02-13 01:11:13
【问题描述】:

我有一个使用 Spring Security 的 Web 应用程序。它使用<intercept-url ../> 元素来描述不同url 的访问过滤器。默认情况下,这不考虑 url 的请求参数。我需要根据请求参数设置 url 的自定义安全规则。所以我做了以下事情:

1) 我创建了一个 bean 后处理器类,它将为 spring 安全机制启用请求参数选项:

<beans:beans>
    . . .
    <beans:bean class="MySecurityBeanPostProcessor">
        <beans:property name="stripQueryStringFromUrls" value="false" />
    </beans:bean>
    . . .
</beans:beans>

还有代码:

public class MySecurityBeanPostProcessor implements BeanPostProcessor {

    private Boolean stripQueryStringFromUrls = null;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DefaultFilterInvocationSecurityMetadataSource && stripQueryStringFromUrls != null) {
            ((DefaultFilterInvocationSecurityMetadataSource) bean)
                .setStripQueryStringFromUrls(stripQueryStringFromUrls.booleanValue());
        }
        return bean;
    }

    // code stripped for clarity
}

这应该设置 spring 安全元数据源以考虑请求参数。我已经调试了上面的代码,并且正在设置stripQueryStringFromUrls 属性。

2) 在我的安全上下文 xml 中,我有以下定义:

<intercept-url pattern="/myUrl?param=value" access="!isAuthenticated() or hasRole('ROLE_GUEST')" />
<intercept-url pattern="/myUrl" filters="none" />
...
<intercept-url pattern="/**" access="isAuthenticated()" />

如您所见,仅当用户未通过身份验证或使用访客帐户时,我才需要使用指定的参数访问 url。另外,我为相同的 url 添加了一条规则,但没有任何参数,没有过滤器。

据我所知,spring security 应该配置提供更具体的 url BEFORE 不太具体的,否则链将首先检测到更一般的规则并且不会继续越具体。这就是为什么我希望带有参数的 url 更具体,因此被拒绝访问经过身份验证的非来宾用户。相反,下面定义的更一般的规则适用。 这是输出:

INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] 调试 org.springframework.security.web.FilterChainProxy - 候选人是:'/myUrl';模式是 /myUrl;匹配=真

INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] 调试 org.springframework.security.web.FilterChainProxy - /myUrl?param=value 有一个空的过滤器列表

我还尝试删除没有参数的 url 规则。然后,过滤器选择/** 模式并要求用户登录,而不是让我的带有参数的url 规则起作用。 输出是:

INFO [STDOUT] 73066 [http-0.0.0.0-8080-1] 调试 org.springframework.security.web.FilterChainProxy - 候选人是:'/myUrl';模式是 /**;匹配=真

INFO [STDOUT] 73068 [http-0.0.0.0-8080-1] 调试 org.springframework.security.web.FilterChainProxy - /myUrl?param=value 位于附加过滤器链中第 8 位的第 1 位;触发过滤器:'SecurityContextPersistenceFilter'

该应用程序是用 Java 1.6 编写的,使用 Spring v3.0 并部署在 Linux 机器上的 JBoss v5.1.0-GA 上。我不知道为什么过滤器会按照我描述的方式运行。非常感谢您的帮助和建议。


编辑:

作为结论,我观察到 /myUrl?param=value 过滤器从未应用 - 好像 security-context.xml 中的条目被忽略了。这符合我到目前为止观察到的行为。我还尝试用access="permitAll" 替换filters="none",切换到正则表达式(并相应地更改模式 - 例如/myUrl?param=value 变为\A/myUrl\?param=value\Z)并且在所有变体中我得到的行为都是相同的。


编辑 2:

这里描述的问题实际上是无效的。造成这种情况的原因如下:由于内部库冲突和不兼容,存在问题的项目排除了一些 spring 包,而整个设置以某种方式工作。我从来没有意识到这一点,实际上这种不纯的配置使整个问题过时了。具体原因是 isAuthenticated() 和 isAnonymous() 方法的实现没有按预期工作,因此这里提供的任何建议都不起作用。

【问题讨论】:

    标签: java spring spring-security


    【解决方案1】:

    在 Spring Security 3.0 中,这是(可以理解的)一个常见的混淆源,因为使用 filters="none" 将带有空过滤器列表的模式添加到 FilterChainProxy,而使用 access 属性会添加对FilterSecurityInterceptor 的安全访问规则,用于保护 URL。

    匹配过程为:

    1. FilterChainProxy 将请求匹配到过滤器链
    2. 如果过滤器链非空,请求将由FilterSecurityInterceptor检查

    两个类都维护一个单独的匹配器有序列表,它们会按照您定义它们的顺序应用,但您需要了解,在下面实际上配置了两个不直接连接的独立 bean。

    在一个简单的命名空间应用程序中,&lt;http&gt; 块将单个过滤器链添加到 FilterChainProxy,模式为 /**。您添加的任何filters="none" 模式都会在实际链之前放置空过滤器链。

    这种情况在 Spring Security 3.1 中得到了很大改善,您可以通过使用单独的 &lt;http&gt; 块来配置单独的过滤器链,该块更直观地映射到 bean 级别的实际情况。 request-matching process 也得到了很大改进,现在对所有内容都使用RequestMatcher 接口。您也可以在配置 &lt;http&gt; 块时使用它来代替模式。

    因此,您最好的选择可能是升级。然后你可以实现一个RequestMatcher,它检查你正在寻找的参数是否存在,比如MyParamRequestMatcher,然后使用:

    <http request-matcher-ref="myParamMatcher" security="none" />
    
    <bean:bean id="myParamMatcher" class="MyParamRequestMatcher" />
    
    <http>
        <!-- Define the default filter chain configuration here -->
    </http>
    

    请注意,使用 URL 模式匹配参数通常不是很安全,因为通过重新排序 URL、添加虚假模式等很容易绕过。您的情况可能没问题,因为带有参数的版本允许不安全的访问,并且您的模式需要对其他情况进行身份验证。

    如果您想继续使用 3.0,最好的选择是避免使用 filters="none"(改用 isAnonymous())并且可能使用正则表达式匹配而不是 ant 路径,以便您可以更轻松地匹配查询字符串. 再次重申,以这种方式定义的规则几乎肯定可以被绕过,所以不要依赖它们来获得更高的安全性,并确保您在默认情况下是安全的。


    更新:

    作为对我使用正则表达式匹配和permitAll 的建议的测试,如果我像这样修改 Spring Security 的 3.0.x 分支中的“教程”示例应用程序:

    <http use-expressions="true" path-type="regex">
        <intercept-url pattern="\A/secure/extreme/.*\Z" access="hasRole('ROLE_SUPERVISOR')"/>
        <intercept-url pattern="\A/secure/index.jsp\?param=value\Z" access="permitAll" />
        <intercept-url pattern="\A/secure/.*\Z" access="isAuthenticated()" />
        <intercept-url pattern="/.*" access="permitAll" />
        ...
    </http>
    

    然后我确实得到了预期的行为:

    [DEBUG,FilterChainProxy] Candidate is: '/secure/index.jsp?param=value'; pattern is /.*; matched=true
    [DEBUG,FilterChainProxy] /secure/index.jsp?param=value at position 1 of 12 in additional filter chain; firing Filter: 'ConcurrentSessionFilter'
    ...
    [DEBUG,FilterChainProxy] /secure/index.jsp?param=value at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    [DEBUG,FilterChainProxy] /secure/index.jsp?param=value at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    [DEBUG,ExpressionBasedFilterInvocationSecurityMetadataSource] Candidate is: '/secure/index.jsp?param=value'; pattern is \A/secure/extreme/.*\Z; matched=false
    [DEBUG,ExpressionBasedFilterInvocationSecurityMetadataSource] Candidate is: '/secure/index.jsp?param=value'; pattern is \A/secure/index.jsp\?param=value\Z; matched=true
    [DEBUG,FilterSecurityInterceptor] Secure object: FilterInvocation: URL: /secure/index.jsp?param=value; Attributes: [permitAll]
    

    它显示.* 下的FilterChainProxy 匹配,然后是FilterSecurityInterceptor 与参数的确切URL 匹配。

    【讨论】:

      猜你喜欢
      • 2012-06-15
      • 1970-01-01
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      • 2017-11-24
      • 2020-01-17
      • 2012-08-14
      相关资源
      最近更新 更多