2017-04-11 2 views
2

Hallo allerseits Ich habe Probleme beim Einrichten einer Sicherheitslösung für meine App! So habe ich ein REST-API-Backend, das bei http://localhost:51030 läuft und mit Spring Framework entwickelt, und für die Vorderseite habe ich eine Angular 2-Anwendung (die neueste Version A.K.A. Angular 4), die unter http://localhost:4200 läuft. Ich habe die CORS Konfiguration im Backend wie unten gesehen:Angular 2 Spring Sicherheit CSRF Token

public class CORSFilter implements Filter 
{ 
// The list of domains allowed to access the server 
private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200", "http://127.0.0.1:4200"); 

public void destroy() 
{ 

} 

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
{ 
    // Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects) 
    if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) 
    { 
     HttpServletRequest request = (HttpServletRequest) req; 
     HttpServletResponse response = (HttpServletResponse) res; 

     // Access-Control-Allow-Origin 
     String origin = request.getHeader("Origin"); 
     response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : ""); 
     response.setHeader("Vary", "Origin"); 

     // Access-Control-Max-Age 
     response.setHeader("Access-Control-Max-Age", "3600"); 

     // Access-Control-Allow-Credentials 
     response.setHeader("Access-Control-Allow-Credentials", "true"); 

     // Access-Control-Allow-Methods 
     response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT"); 

     // Access-Control-Allow-Headers 
     response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, " + CSRF.REQUEST_HEADER_NAME); // + CSRF.REQUEST_HEADER_NAME 
    } 
    chain.doFilter(req, res); 
} 


public void init(FilterConfig filterConfig) 
{ 

} 
} 

nur diese Konfiguration verwenden funktioniert gut, ich Anfragen von dem Winkel App auf die Feder zurück und Antwort und alles tun bekomme ausführen kann. Aber wenn ich versuche, CSRF Sicherheitslösung einzurichten, funktioniert nichts. Dies ist die CSRF und Security-Konfiguration im Backend setted:

public class CSRF 
{ 

    /** 
    * The name of the cookie with the CSRF token sent by the server as a response. 
    */ 
    public static final String RESPONSE_COOKIE_NAME = "XSRF-TOKEN"; //CSRF-TOKEN 

    /** 
     * The name of the header carrying the CSRF token, expected in CSRF-protected requests to the server. 
     */ 
    public static final String REQUEST_HEADER_NAME = "X-XSRF-TOKEN"; //X-CSRF-TOKEN 

    // In Angular the CookieXSRFStrategy looks for a cookie called XSRF-TOKEN 
    // and sets a header named X-XSRF-TOKEN with the value of that cookie. 

    // The server must do its part by setting the initial XSRF-TOKEN cookie 
    // and confirming that each subsequent state-modifying request includes 
    // a matching XSRF-TOKEN cookie and X-XSRF-TOKEN header. 

} 

public class CSRFTokenResponseCookieBindingFilter extends OncePerRequestFilter 
{ 

    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf"; 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 
    throws ServletException, IOException 
    { 
     CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME); 

     Cookie cookie = new Cookie(CSRF.RESPONSE_COOKIE_NAME, token.getToken()); 
     cookie.setPath("/"); 

     response.addCookie(cookie); 

     filterChain.doFilter(request, response); 
    } 
} 

@Configuration 
public class Conf extends WebMvcConfigurerAdapter 
{ 
    @Bean 
    public CORSFilter corsFilter() 
    { 
     return new CORSFilter(); 
    } 

    @Override 
    public void addViewControllers(ViewControllerRegistry registry) 
    { 
     registry.addViewController("/login"); 
     registry.addViewController("/logout"); 
    } 
} 

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(securedEnabled = true) 
public class SecurityConfiguration extends WebSecurityConfigurerAdapter 
{ 

    @Autowired 
    private RESTAuthenticationEntryPoint authenticationEntryPoint; 

    @Autowired 
    private RESTAuthenticationFailureHandler authenticationFailureHandler; 

    @Autowired 
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler; 

    @Autowired 
    private RESTLogoutSuccessHandler logoutSuccessHandler; 

    @Resource 
    private CORSFilter corsFilter; 

    @Autowired 
    private DataSource dataSource; 


    @Autowired 
    public void globalConfig(AuthenticationManagerBuilder auth) throws Exception 
    { 
     auth.jdbcAuthentication() 
      .dataSource(dataSource) 
      .usersByUsernameQuery("select login as principal, password as credentials, true from user where login = ?") 
      .authoritiesByUsernameQuery("select login as principal, profile as role from user where login = ?") 
      .rolePrefix("ROLE_"); 
    } 


    @Override 
    protected void configure(HttpSecurity http) throws Exception 
    { 
     //csrf is disabled for the moment 
     //http.csrf().disable(); 

     //authorized requests 
     http.authorizeRequests() 
      .antMatchers("/api/users/**").permitAll() 
      .antMatchers(HttpMethod.OPTIONS , "/*/**").permitAll() 
      .antMatchers("/login").permitAll() 
      .anyRequest().authenticated(); 

     //handling authentication exceptions 
     http.exceptionHandling() 
      .authenticationEntryPoint(authenticationEntryPoint); 

     //login configuration 
     http.formLogin() 
      .loginProcessingUrl("/login") 
      .successHandler(authenticationSuccessHandler); 
     http.formLogin() 
      .failureHandler(authenticationFailureHandler); 

     //logout configuration 
     http.logout() 
      .logoutUrl("/logout") 
      .logoutSuccessHandler(logoutSuccessHandler); 

     //CORS configuration 
     http.addFilterBefore(corsFilter, ChannelProcessingFilter.class); 


     //CSRF configuration 
     http.csrf().requireCsrfProtectionMatcher(
       new AndRequestMatcher(
       // Apply CSRF protection to all paths that do NOT match the ones below 

       // We disable CSRF at login/logout, but only for OPTIONS methods to enable the browser preflight 
       new NegatedRequestMatcher(new AntPathRequestMatcher("/login*/**", HttpMethod.OPTIONS.toString())), 
       new NegatedRequestMatcher(new AntPathRequestMatcher("/logout*/**", HttpMethod.OPTIONS.toString())), 

       new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.GET.toString())), 
       new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.HEAD.toString())), 
       new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.OPTIONS.toString())), 
       new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.TRACE.toString())) 
      ) 
     ); 

     // CSRF tokens handling 
     http.addFilterAfter(new CSRFTokenResponseCookieBindingFilter(), CsrfFilter.class); 

    } 
} 

Das Problem ist in der Vorderseite und die eckige 4-Konfiguration, die CSRF-Dokumentation ist so schlecht und es gibt kein vollständiges Beispiel einer CSRF-Implementierung im Internet. So unten ist der Anmeldungsservice:

@Injectable() 
export class LoginService { 

    private loginUrl = 'http://localhost:51030/login'; 

    constructor(private http: Http) {} 

    preFlight() { 
     return this.http.options(this.loginUrl); 
    } 

    login(username: string , password: string) { 

     let headers = new Headers(); 

     headers.append('Content-Type', 'application/x-www-form-urlencoded'); 

     let options = new RequestOptions({headers: headers}); 

     let body = "username="+username+"&password="+password; 

     return this.http.post(this.loginUrl , body , options); 

    } 
} 

Und in der Login-Komponente I die Option Anfrage im ngOnInit Lebenszyklus Haken ausführen:

@Component({ 
    templateUrl: './login-layout.component.html' 
}) 
export class LoginLayoutComponent implements OnInit { 

    credentials = {username: '' , password: ''}; 

    constructor(private loginService: LoginService){} 

    ngOnInit() { 
     this.loginService.preFlight() 
         .subscribe(); 
    } 

    login() { 
     this.loginService.login(this.credentials.username , this.credentials.password) 
         .subscribe(
          response=>{ 
           console.log(response) ; 
          },error=>{ 
           console.log(error); 
          } 
         ); 
    } 

} 

Die Preflight gut geht und Ich bekomme den 200 OK-Status auf der Option Anfrage plus eine temporäre JSEEIONID und das XSRF-TOKEN Cookie.

Also in meinem App Modul hinzugefügt ich dies wie gesagt in den Winkel docs:

{ 
    provide: XSRFStrategy, 
    useValue: new CookieXSRFStrategy('XSRF-TOKEN', 'X-XSRF-TOKEN') 
    }, 

ABER, wenn ich versuche, eine POST-Anforderung mit den Anmeldeinformationen oder jede Anforderung an das auszuführen, ich habe 403 Forbidden: "Das angegebene CSRF-Token konnte nicht überprüft werden, da Ihre Sitzung nicht gefunden wurde."

Also bitte wie kann ich das lösen, kann mir jemand auf die richtige Richtung zeigen, weil ich keine Ahnung habe, wie man diese Arbeit machen kann !! Und Danke !!!

Antwort

1

Ich bin überrascht, dass Sie so viel Arbeit für CSRF und CORS tun, wie Spring Security und Angular Unterstützung eingebaut haben. Spring Security hat CSRF standardmäßig aktiviert.

Das Federsicherheitshandbuch verfügt über eine gute Dokumentation über die Konfiguration csrf: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf

Und googeln für "Angular 2 Spring Security csrf" mehrere Beispiele gibt (und auch, wie ich Ihren Beitrag gefunden). Hier ist eine:

https://medium.com/spektrakel-blog/angular2-and-spring-a-friend-in-security-need-is-a-friend-against-csrf-indeed-9f83eaa9ca2e