Spring Security, trailing slashes, and dots in URLs
Asked Answered
C

3

21

I use Spring Security 3.1.4 to secure a Spring MVC 3.2.4 application deployed to Tomcat. I have the following Spring Security configuration:

<http auto-config="true" use-expressions="true">
   <http-basic />
   <logout ... />
   <form-login ... />

   <intercept-url pattern="/" access="isAnonymous() or hasRole('ROLE_USER')" />
   <intercept-url pattern="/about" access="isAnonymous() or hasRole('ROLE_USER')" />
   <intercept-url pattern="/login" access="isAnonymous() or hasRole('ROLE_USER')" />
   <intercept-url pattern="/under-construction" access="isAnonymous() or hasRole('ROLE_USER')" />
   <intercept-url pattern="/admin-task*" access="hasRole('ROLE_USER') and hasRole('ROLE_ADMINISTRATOR')" />
   <intercept-url pattern="/resources/**" access="isAnonymous() or hasRole('ROLE_USER')" />
   <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
</http>

I noticed that URL patterns without a trailing slash (e.g., /about) do not match URLs with a trailing slash (e.g., /about/) and vice-versa. In other words, a URL with a slash and an identical URL without a slash are treated as two different URLs by Spring Security. The problem could be fixed by using two security rules:

<intercept-url pattern="/about" access="isAnonymous() or hasRole('ROLE_USER')" />
<intercept-url pattern="/about/" access="isAnonymous() or hasRole('ROLE_USER')" />

Is there a better solution?

I know that path-type="regex" allows to define URL patterns with regular expressions, but I would like to avoid any unnecessary complexity if it's possible.

Update

As Adam Gent noted, there is an additional problem that involves URLs with a dot: /about.foo and /about are treated as the same URL by Spring MVC. However, Spring Security treats them as two different URLs. So, one more security rule may be necessary:

<intercept-url pattern="/about.*" .../>
Canady answered 15/12, 2013 at 3:10 Comment(0)
R
19

Spring Security 4.1+

Spring Security has now added a new matcher which is aware of your Spring MVC URL matching configuration. This tells Spring Security to match paths based on the same rules that Spring MVC uses, eliminating the possibility of a URL being valid, but unsecured.

First you need to replace any old matchers with the new MVC matcher. Spring Security is now in sync with however you have configured Spring MVC so you are free to add or remove any path matching configuration. I recommend sticking with the defaults where possible.

Java Config

If you were using antMatchers, you now should use mvcMatchers:

protected configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
        .mvcMatchers("/about").hasRole("USER");
}

XML Config

You need to add the attribute request-matcher to your http tag:

<http request-matcher="mvc">
  <intercept-url pattern="/about" access="hasRole('USER')"/>
</http>

Full Reference

Please note that you also should no longer be prefixing your roles with "ROLE_" as Spring Security does this for you automatically.


Spring Security Before 4.1

I've not been able to find a way to handle both trailing slash and path suffixes in Spring Security. Obviously it is possible to write a regexp to handle these cases but this seems to make the security rules overly complex and prone to error. I want to be as confident as possible that I'm not exposing resources accidentally.

Therefore, my approach is to disable this behaviour in Spring by configuring the path matcher to be strict about both trailing slashes and suffixes.

Java Config

@Configuration
public class ServletConfig extends WebMvcConfigurerAdapter {
  @Override
  public void configurePathMatch(final PathMatchConfigurer configurer) {
    configurer.setUseSuffixPatternMatch(false);
    configurer.setUseTrailingSlashMatch(false);
  }
}

XML Config

<mvc:annotation-driven>
  <mvc:path-matching suffix-pattern="false" trailing-slash="false" />
</mvc:annotation-driven>
Richart answered 1/7, 2015 at 9:54 Comment(0)
C
3
<intercept-url pattern="/about/**"...

also works for me in Spring Security 3.1.4. This secures /about, /about/, and /about/anything_else

Carrico answered 15/12, 2013 at 19:14 Comment(6)
You need to also add <intercept-url pattern="/about.*" .... The reason is your Spring MVC request mappings will map /about.stuff -> /about but your security filter will not intercept it. I found this out during a lovely security audit.Saskatchewan
Hmm... Spring Security is full of surprises. Though Evgeny's solution works for me, I still need two security rules for most URLs because of Adam's remark: <intercept-url pattern="/about/**" ... and <intercept-url pattern="/about.*" ... I will wait a bit longer and than will accept this response because it answers the original question.Canady
Adam is right. @Canady to make yor life with Spring security easyer I suggest to turn the logging on. It will show you a lot of what happens.Carrico
Did you try <intercept-url pattern="/about**" .../>?Humblebee
@Smoky that would match too much like "/aboutus"Saskatchewan
Adam is right, for example, it could give an anonymous access to pages like /about-our-top-secrets. It also does not match URLs with a trailing slash like /about/ (I have just tried it).Canady
B
0

I have used separate patterns for the same url. It is working for Spring security 3.1.7.RELEASE

<security:intercept-url pattern="/mypage./**" access="hasAnyRole('admin','reportviewer')"/>
<security:intercept-url pattern="/mypage" access="hasAnyRole('admin','reportviewer')"/>
<security:intercept-url pattern="/mypage/**" access="hasAnyRole('admin','reportviewer')"/>
Berkowitz answered 29/12, 2021 at 8:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.