2016-08-08 66 views
1

Ich verwende Spring Boot und Spring Security, um mein Webprojekt zu erstellen. Ich möchte den CSRF-Schutz für ein bestimmtes URL-Muster deaktivieren, um API für Android-Geräte bereitzustellen. CSRF-Schutz für bestimmtes URL-Muster im Spring Boot deaktivieren

Mit

schrieb ich die folgende Konfiguration:

package com.hnu.tutorial.configs; 

import org.springframework.boot.autoconfigure.security.SecurityProperties; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.core.annotation.Order; 
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 
import org.springframework.security.config.annotation.web.builders.HttpSecurity; 
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 
import org.springframework.security.web.util.matcher.RegexRequestMatcher; 
import org.springframework.security.web.util.matcher.RequestMatcher; 

import javax.servlet.http.HttpServletRequest; 
import java.util.regex.Pattern; 

@Configuration 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     CsrfSecurityRequestMatcher crm = new CsrfSecurityRequestMatcher(); 
     http.csrf().requireCsrfProtectionMatcher(crm).and() 
       .authorizeRequests().antMatchers("/**").permitAll().anyRequest().fullyAuthenticated(); 
//  http.csrf().disable(); 
    } 

    public class CsrfSecurityRequestMatcher implements RequestMatcher { 
     private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); 
     private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/api/**", null); 

     @Override 
     public boolean matches(HttpServletRequest request) { 
      if(allowedMethods.matcher(request.getMethod()).matches()){ 
       return false; 
      } 
      return !unprotectedMatcher.matches(request); 
     } 
    } 

} 

Als ich dieses Projekt ausführen, bekomme ich die folgende Fehler:

2016-08-08 09:29:27.172 ERROR 6715 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]  : Exception starting filter springSecurityFilterChain 

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 6 
/api/** 
    ^
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1060) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:326) ~[spring-web-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235) ~[spring-web-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199) ~[spring-web-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279) ~[tomcat-embed-core-8.0.33.jar:8.0.33] 
    at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:109) ~[tomcat-embed-core-8.0.33.jar:8.0.33] 
    at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4658) [tomcat-embed-core-8.0.33.jar:8.0.33] 
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5277) [tomcat-embed-core-8.0.33.jar:8.0.33] 
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147) [tomcat-embed-core-8.0.33.jar:8.0.33] 
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408) [tomcat-embed-core-8.0.33.jar:8.0.33] 
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398) [tomcat-embed-core-8.0.33.jar:8.0.33] 
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_73] 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_73] 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_73] 
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_73] 
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 6 
/api/** 
    ^
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    ... 23 common frames omitted 
Caused by: java.util.regex.PatternSyntaxException: Dangling meta character '*' near index 6 
/api/** 
    ^
    at java.util.regex.Pattern.error(Pattern.java:1955) ~[na:1.8.0_73] 
    at java.util.regex.Pattern.sequence(Pattern.java:2123) ~[na:1.8.0_73] 
    at java.util.regex.Pattern.expr(Pattern.java:1996) ~[na:1.8.0_73] 
    at java.util.regex.Pattern.compile(Pattern.java:1696) ~[na:1.8.0_73] 
    at java.util.regex.Pattern.<init>(Pattern.java:1351) ~[na:1.8.0_73] 
    at java.util.regex.Pattern.compile(Pattern.java:1028) ~[na:1.8.0_73] 
    at org.springframework.security.web.util.matcher.RegexRequestMatcher.<init>(RegexRequestMatcher.java:68) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.web.util.matcher.RegexRequestMatcher.<init>(RegexRequestMatcher.java:52) ~[spring-security-web-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at com.hnu.tutorial.configs.SecurityConfig$CsrfSecurityRequestMatcher.<init>(SecurityConfig.java:35) ~[classes/:na] 
    at com.hnu.tutorial.configs.SecurityConfig.configure(SecurityConfig.java:27) ~[classes/:na] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:199) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:290) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:67) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at com.hnu.tutorial.configs.SecurityConfig$$EnhancerBySpringCGLIB$$db9c0de0.init(<generated>) ~[classes/:na] 
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:370) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:324) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:41) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:105) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$5dd0484b.CGLIB$springSecurityFilterChain$4(<generated>) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$5dd0484b$$FastClassBySpringCGLIB$$a796ba38.invoke(<generated>) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356) ~[spring-context-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$5dd0484b.springSecurityFilterChain(<generated>) ~[spring-security-config-4.0.4.RELEASE.jar:4.0.4.RELEASE] 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_73] 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_73] 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_73] 
    at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_73] 
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162) ~[spring-beans-4.2.6.RELEASE.jar:4.2.6.RELEASE] 
    ... 24 common frames omitted 

Das Protokoll oben zeigt, dass reguläre Ausdrücke /api/** in

private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("/api/**", null); 

Dangling meta character '*' near index 6 /api/** hat. Aber ich weiß nicht, was dieser Fehler bedeutet.

+1

'/ api/**' ist ein Ant-Stil-Muster, und Sie sollten 'AntPathRequestMatcher' anstelle von' RegexRequestMatcher' verwenden. Oder ändern Sie Ihren Ausdruck in einen gültigen regulären Ausdruck. – tan9

+0

Ja, vielen Dank, ich habe diese Frage mit 'AntPathRequestMatcher' gelöst. Ich habe meinen Code in der folgenden Antwort gepostet. –

+0

Wenn Sie interessiert sind, was ein dangling Meta-Zeichen ist, finden Sie unter Was sind baumelnde Metazeichen in Regex? (Https://stackoverflow.com/q/20585639/2157640). Asterisk ist ein Meta-Zeichen, das bedeutet "das vorherige Zeichen darf 0 oder mehrmals wiederholt werden". Zwei von ihnen hintereinander zu schreiben ist ein Syntaxfehler, aber da Regexes nur zur Laufzeit geparst werden, wird sie als Ausnahme angezeigt. – Palec

Antwort

0

Versuchen Sie Folgendes, damit api-Aufrufe die CSRF-Prüfung umgehen können.

final String API_URL = "/api/*"; 
http.csrf() 
    .requireCsrfProtectionMatcher(new RequestMatcher() { 
     private RegexRequestMatcher requestMatcher = new RegexRequestMatcher(API_URL, null); 

     @Override 
     public boolean matches(HttpServletRequest request) { 
      return !requestMatcher.matches(request); 
     } 
    }) 
    .csrfTokenRepository(csrfTokenRepository()); 
+0

Ich habe diese Lösung getestet, '/ api/*' kann kein URL-Muster, so dass dies meine Frage nicht lösen kann –

0

Obwohl ich weiß nicht, wie RegexRequestMatcher ungeschützten URL-Muster Verwendungszweck anzupassen, finde ich eine andere Lösung. Die folgende funktioniert gut für mich:

@Override 
    protected void configure(HttpSecurity http) throws Exception { 

     RequestMatcher csrfRequestMatcher = new RequestMatcher() { 

      // Enabled CSFR protection on the following urls: 
      private AntPathRequestMatcher[] disableCsrfMatchers = { 
        new AntPathRequestMatcher("/api/**") 
      }; 

      @Override 
      public boolean matches(HttpServletRequest request) { 
       // If the request match one url the CSFR protection will not be enabled 
       for (AntPathRequestMatcher rm : disableCsrfMatchers) { 
        if (rm.matches(request)) { 
         return false; 
        } 
       } 
       return true; 
      } // method matches 

     }; 

     http.csrf().requireCsrfProtectionMatcher(csrfRequestMatcher).and() 
       .authorizeRequests().antMatchers("/**").permitAll().anyRequest().fullyAuthenticated(); 
    } 
1

Für diejenigen, die diese Frage haben, wie die CSRF Prüfung für bestimmte Pfade zu deaktivieren, finde ich, dass der einfachste Weg, um ein Array von String mit Mustern zu erstellen, wie folgt aus:

String [] publicUrls = new String [] { 
      "/public/**", 
      "/login", 
      "/logout" 
    }; 

Hier ist der Code, den ich in CSRF verwende. Und der Code für Urls ignorieren ist dies .ignoringAntMatchers(publicUrls):

.csrf() 
     .csrfTokenRepository(csrfTokenRepository()) 
     .ignoringAntMatchers(publicUrls) 

ich diesen here finden.