2017-04-11 20 views
2

こんにちは皆私のアプリのセキュリティソリューションをセットアップする際に問題があります! 私はhttp://localhost:51030で実行され、Spring Frameworkで開発されたREST APIバックエンドを持っています。フロント側には、http://localhost:4200で動作するAngular 2アプリケーション(最新バージョンA.K.A. Angular 4)があります。下図のように 私はバックエンドでCORS構成を設定している:角2春のセキュリティCSRFトークン

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) 
{ 

} 
} 

を、この設定を使用するだけで正常に動作し、私は戻って春に角度アプリからの要求を実行し、応答を取得し、何を行うことができます。 しかし、私はCSRFセキュリティソリューションを設定しようとすると何も動作しません。

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); 

    } 
} 

問題が前面にある: これは、バックエンドでアップsetted CSRFとセキュリティの設定ですAngle 4の設定では、CSRFのドキュメントは非常に貧しく、CSRF実装の完全な例はインターネットにはありません。そこで、以下の は私のログインサービスである:

@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); 

    } 
} 

そして、私はngOnInitライフサイクルフックにオプション要求を実行し、ログインコンポーネントで:

@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); 
          } 
         ); 
    } 

} 

プリフライトはうまくいくと私は、オプション要求と一時的なJSEEIONIDとXSRF-TOKEN Cookieに200 OKステータスを取得します。

角度ドキュメントに言って私のアプリモジュールで、私はこれを追加しました:

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

しかし、私は資格情報または私は403を禁じてしまったバックへの要求とPOSTリクエストを実行してみてください: "あなたのセッションが見つからないため、提供されたCSRFトークンを検証できませんでした。"

私はこれをどのように解決することができますか、私はこの仕事をする方法の手がかりを持っていない原因を右の方向に私をポイントすることができます! ありがとうございます!

答えて

1

Spring SecurityとAngularのサポートが組み込まれているので、CSRFとCORSの作業が盛んであることに驚いています.Spring SecurityではデフォルトでCSRFが有効になっています。 「角度2春のセキュリティCSRF」の https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf

そして、グーグルでは、いくつかの例を示します(また、どのように私はあなたのポストを見つけました):

春のセキュリティマニュアルには良い設定CSRFに関するドキュメントを持っています。ここに1つあります:

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

関連する問題