问题描述
我有一个使用 spring 安全性的 Web 应用程序.它使用 元素来描述不同 url 的访问过滤器.默认情况下,这不考虑 url 的请求参数.我需要根据请求参数设置 url 的自定义安全规则.所以我做了以下事情:
I have a web application that uses spring security. It uses <intercept-url ../>
elements to describe the access filters for different urls. By default, this does not take request parameters of urls into account. I needed to set custom security rules of an url based on the request parameters. So I've done the following:
1) 我创建了一个 bean 后处理器类,它将为 spring 安全机制启用请求参数选项:
1) I created a bean post-processor class that will enable request parameters option for the spring security mechanisms:
<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
属性.
This should set the spring security metadata source to take into account the request parameters. I have debugged the above code and the stripQueryStringFromUrls
property is being set.
2) 在我的安全上下文 xml 中,我有以下定义:
2) In my security context xml I have the following definitions:
<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 添加了一条规则,但没有任何参数,也没有过滤器.
As you can see, I need to access the url with the params specified only if the user is not authenticated, or uses a guest account. Also, I have added a rule for the same url, but without any params, which has no filters.
据我所知,spring security 应该被配置为提供更具体的 url BEFORE 不太具体的,否则链将首先检测到更通用的规则并且不会继续越具体.这就是为什么我希望带有 params 的 url 更加具体,因此拒绝经过身份验证的非访客用户的访问.相反,下面定义的更一般规则适用.这是输出:
As far as I know, spring security should be configured providing the more-specific url BEFORE the less-specific, because otherwise the chain will detect the more-general rule first and will not continue to the more-specific. That is why I expect the url with params to be more-specific, therefore to be denied access of authenticated non-guest users. Instead, the defined below more general rule applies.Here is the output:
INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - 候选人是:'/myUrl';模式是/myUrl;匹配=真
INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy -/myUrl?param=value has a empty filter list
INFO [STDOUT] 186879 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - /myUrl?param=value has an empty filter list
我还尝试删除没有参数的 url 规则.然后,过滤器选择 /**
模式并要求用户登录,而不是让我的带有参数的 url 规则起作用.输出为:
I also tried to remove the rule for the url wit no params. Then, instead of getting my rule for the url with params to work, the filter chooses the /**
pattern and requires the users to log-in.The output for that is:
INFO [STDOUT] 73066 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - 候选人是:'/myUrl';模式是/**;匹配=真
INFO [STDOUT] 73068 [http-0.0.0.0-8080-1] 调试 org.springframework.security.web.FilterChainProxy -/myUrl?param=value 在附加过滤器链中的第 1 个位置;触发过滤器:'SecurityContextPersistenceFilter'
INFO [STDOUT] 73068 [http-0.0.0.0-8080-1] DEBUG org.springframework.security.web.FilterChainProxy - /myUrl?param=value at position 1 of 8 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
该应用程序是用 Java 1.6 编写的,使用 Spring v3.0 并部署在 JBoss v5.1.0-GA 上,在 Linux 机器上.我不知道为什么过滤器会按照我描述的方式运行.您的帮助和建议将不胜感激.
The application is written in Java 1.6, uses Spring v3.0 and is deployed on JBoss v5.1.0-GA, on a linux machine. I have no clues why the filters behave in the way I described. Your help and advices will be greatly appreciated.
作为结论,我观察到的是 /myUrl?param=value
过滤器从未被应用 - 就像 security-context.xml 中的条目被忽略一样.这符合我迄今为止观察到的行为.我还尝试将 filters="none"
替换为 access="permitAll"
,切换到正则表达式(并相应地更改模式 - 例如 /myUrl?param=value
变为 A/myUrl?param=value
) 并且在所有变体中,我得到的行为都是相同的.
As a conclusion, what I observed is that the /myUrl?param=value
filter is never applied - as if the entry in the security-context.xml was ignored. This fits the behavior I have observed up to now. I have also tried replacing filters="none"
with access="permitAll"
, switched to regex (and changes patterns accordingly - for example /myUrl?param=value
becomes A/myUrl?param=value
) and in all variations the behavior I get is the same.
编辑 2:
这里描述的问题实际上是无效的.造成这种情况的原因如下:由于内部库冲突和不兼容,存在问题的项目排除了一些spring包,而整个设置以某种方式起作用.我从来没有意识到这一点,实际上这种不纯的配置使整个问题变得过时.具体原因是 isAuthenticated() 和 isAnonymous() 方法的实现没有按预期工作,因此这里提供的任何建议都不起作用.
The issue described here is actually invalid. The reasons for this is the following matter: the project where the problem is present has excluded some spring packages due to internal library clashes and incompatibility, while the whole setup somehow worked. I was never made aware of that and actually this unpure configuration renders the whole question obsolete. The concrete reason is that the implementations of isAuthenticated() and isAnonymous() methods were not working as expected, therefore any advice provided here was not working.
推荐答案
在 Spring Security 3.0 中,这是(可以理解的)一个常见的混淆源,因为使用 filters="none"
FilterChainProxy
的过滤器列表为空的模式,而使用 access
属性将安全访问规则添加到使用的 FilterSecurityInterceptor
保护网址.
In Spring Security 3.0, this is (understandably) a common source of confusion in that the use of filters="none"
adds a pattern with an empty list of filters to the FilterChainProxy
whereas the use of an access
attribute adds a security access rule to the FilterSecurityInterceptor
which is used to protect URLs.
匹配过程为:
FilterChainProxy
将请求匹配到过滤器链- 如果过滤器链不为空,请求将被
FilterSecurityInterceptor
检查
FilterChainProxy
matches the request to a filter chain- If the filter chain is non-empty, the request will be checked by the
FilterSecurityInterceptor
这两个类都维护一个单独的匹配器排序列表,它们按照您定义的顺序应用它们,但您需要了解在下面实际上配置了两个不直接连接的单独 bean.
Both classes maintain a separate ordered list of matchers which they do apply in the order you have defined them, but you need to understand that underneath there are actually two separate beans being configured which are not directly connected.
在一个简单的命名空间应用程序中, 块使用模式
/**
将单个过滤器链添加到 FilterChainProxy
.您添加的任何 filters="none"
模式都会在实际链之前放置空过滤器链.
In a simple namespace application, the <http>
block is adding a single filter chain to the FilterChainProxy
with pattern /**
. Any filters="none"
patterns you add will place empty filter chains before the actual chain.
这种情况在 Spring Security 3.1 中得到了很大改善,因为您可以使用单独的 <http>
块配置单独的过滤器链,该块更直观地映射到 bean 中实际发生的情况等级.请求匹配过程 也得到了很大的改进,现在一切都使用 RequestMatcher
接口.在配置 块时,您也可以使用它来代替模式.
The situation has improved a lot in Spring Security 3.1, in that you configure separate filter chains by using a separate <http>
block, which maps more intuitively to what is actually happening at the bean level. The request-matching process has also been improved a lot and now uses a RequestMatcher
interface for everything. You can also use this instead of a pattern when configuring the <http>
block.
因此,您最好的选择可能是升级.然后你可以实现一个 RequestMatcher
来检查你正在寻找的参数是否存在,比如 MyParamRequestMatcher
,然后使用:
So, your best option is probably to upgrade. You could then implement a RequestMatcher
which checks for the presence of the the parameter you are looking for, say MyParamRequestMatcher
, and then use:
<http request-matcher-ref="myParamMatcher" security="none" />
<bean:bean id="myParamMatcher" class="MyParamRequestMatcher" />
<http>
<!-- Define the default filter chain configuration here -->
</http>
请注意,使用 URL 模式匹配参数通常不是很安全,因为通过重新排序 URL、添加虚假模式等很容易绕过.您的情况可能没问题,因为带有参数的版本允许不安全的访问,并且您的模式需要对其他情况进行身份验证.
Note that matching on parameters using a URL pattern is not very secure in general as it is easy to bypass by reordering the URL, adding bogus patterns and so on. Your case is probably OK, since the version with the parameter is allowing unsecured access and you have patterns which require authentication for other cases.
如果您想继续使用 3.0,最好的选择是避免使用 filters="none
"(使用 isAnonymous()
代替)并可能使用正则表达式匹配而不是蚂蚁路径,以便您可以更轻松地匹配查询字符串.我再次重申,以这种方式定义的规则几乎肯定可以被绕过,所以不要依赖它们来提高安全性,并确保默认情况下是安全的.
If you want to stay with 3.0, your best option is to avoid using filters="none
" (use isAnonymous()
instead) and probably use regular-expression matching rather than ant paths so that you can match the query string more easily. Again I should repeat that rules defined this way can almost certainly be bypassed, so don't rely on them for more security and make sure you are secure by default.
作为对我使用正则表达式匹配和 permitAll
的建议的测试,如果我像这样修改 Spring Security 3.0.x 分支中的教程"示例应用程序:
As a test for my suggestion of using regex matching and permitAll
, if I modify the "tutorial" sample application in the 3.0.x branch of Spring Security like so:
<http use-expressions="true" path-type="regex">
<intercept-url pattern="A/secure/extreme/.*" access="hasRole('ROLE_SUPERVISOR')"/>
<intercept-url pattern="A/secure/index.jsp?param=value" access="permitAll" />
<intercept-url pattern="A/secure/.*" access="isAuthenticated()" />
<intercept-url pattern="/.*" access="permitAll" />
...
</http>
然后我确实得到了预期的行为:
Then I do get the expected behaviour:
[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/.*; matched=false
[DEBUG,ExpressionBasedFilterInvocationSecurityMetadataSource] Candidate is: '/secure/index.jsp?param=value'; pattern is A/secure/index.jsp?param=value; matched=true
[DEBUG,FilterSecurityInterceptor] Secure object: FilterInvocation: URL: /secure/index.jsp?param=value; Attributes: [permitAll]
它显示了 .*
下的 FilterChainProxy
匹配,然后是 FilterSecurityInterceptor
与参数的确切 URL 匹配.
which shows the FilterChainProxy
matching under .*
followed by the FilterSecurityInterceptor
matching the exact URL with the parameter.
这篇关于Spring Security - 忽略请求参数规则的 URL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!