2015-09-06 56 views
0

我有一個angularjs應用程序。這一步是註冊一個用戶,所以它是一個POST方法。提交報名表的angularjs服務如下:angularjs和spring security給405錯誤時啓用csrf

homeApp.factory('mainService', ['$http', function($http) { 

     var mainService = {}; 

     mainService.signupArtist = function(data){ 
      var promise = $http.post('../user/register/artist', data) .then(function(response) { 
       return response.data; 
      }); 
      return promise; 
     } 

     return mainService; 

    }]); 

我有我的春季安全設置爲這樣:

<beans:beans xmlns="http://www.springframework.org/schema/security" 
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security-3.2.xsd 
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util-3.2.xsd"> 

    <http auto-config="false" use-expressions="true" entry-point-ref="customAuthenticationEntryPoint"> 

     <intercept-url pattern="/artist/**" access="hasRole('ROLE_ARTIST')" /> 
     <intercept-url pattern="customer/**" access="hasRole('ROLE_CUSTOMER')" /> 

     <!-- access denied page --> 
     <access-denied-handler error-page="/user/403" /> 

     <logout invalidate-session="true" logout-success-url="/user/login" /> 
     <custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" /> 
     <!-- enable csrf protection --> 
     <csrf/> 
     <custom-filter after="CSRF_FILTER" ref="csrfHeaderFilter" /> 
     <csrf token-repository-ref="csrfTokenRepository" /> 
    </http> 

    <!-- Select users and user_roles from database --> 
    <authentication-manager alias="authenticationManager"> 
     <authentication-provider ref="authenticationProvider" > 
     </authentication-provider> 
    </authentication-manager> 

    <beans:bean id="encoder" 
     class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> 


    <beans:bean id="customAuthenticationEntryPoint" 
     class="com.tong.learn.service.security.CustomAuthenticationEntryPoint"> 
     <beans:property name="loginPageUrl" value="/user/login" /> 
     <beans:property name="returnParameterEnabled" value="true" /> 
     <beans:property name="returnParameterName" value="r" /> 
    </beans:bean> 

    <beans:bean id="authenticationFilter" 
     class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
     <beans:property name="authenticationManager" ref="authenticationManager" /> 
     <beans:property name="filterProcessesUrl" value="/j_spring_security_check" /> 

      <!-- change here if customize form action 
     handler are for login with ajax POST --> 
     <beans:property name="authenticationFailureHandler" 
      ref="securityLoginFailureHandler" /> 
     <beans:property name="authenticationSuccessHandler" 
      ref="securityLoginSuccessHandler" /> 
     <beans:property name="passwordParameter" value="password" /> 
     <beans:property name="usernameParameter" value="username" /> 
    </beans:bean> 

    <beans:bean id="securityLoginSuccessHandler" 
     class="com.tong.learn.service.security.SecurityLoginSuccessHandler"> 
    </beans:bean> 

    <beans:bean id="securityLoginFailureHandler" 
     class="com.tong.learn.service.security.SecurityLoginFailureHandler"> 
     <beans:property name="defaultFailureUrl" value="/user/login" /> 
    </beans:bean> 

    <beans:bean id="csrfHeaderFilter" 
     class="com.tong.learn.service.security.CsrfHeaderFilter" > 
    </beans:bean> 

    <beans:bean id="csrfTokenRepository" class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository"> 
     <beans:property name="headerName" value="X-XSRF-TOKEN" /> 
    </beans:bean> 


</beans:beans> 

這些都是從Spring website的鏈接。

當我提交表單時,服務器給我一個405錯誤,這是意外的,因爲我一直在本地主機上,而不是請求來自不同域的東西。該cookie應該是正確的。

請求和響應如下:

General 
Remote Address:[::1]:8080 
Request URL:http://localhost:8080/learn/user/register/artist 
Request Method:POST 
Status Code:405 Method Not Allowed 
Response Headers 
view source 
Allow:GET 
Content-Language:en 
Content-Length:1090 
Content-Type:text/html;charset=ISO-8859-1 
Date:Sun, 06 Sep 2015 03:48:16 GMT 
Server:Apache-Coyote/1.1 
Request Headers 
view source 
Accept:application/json, text/plain, */* 
Accept-Encoding:gzip, deflate 
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4 
Connection:keep-alive 
Content-Length:2 
Content-Type:application/json;charset=UTF-8 
Cookie:JSESSIONID=2E77A6690C8F56BFA8F51AF37974BA1B; XSRF-TOKEN=2dfa09e4-9201-4b14-b2d3-fea8a9117be3 
Host:localhost:8080 
Origin:http://localhost:8080 
Referer:http://localhost:8080/learn/home/ 
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36 
X-Requested-With:XMLHttpRequest 
X-XSRF-TOKEN:2dfa09e4-9201-4b14-b2d3-fea8a9117be3 

我不知道什麼是錯的。你可以幫我嗎?謝謝。

+0

域不是問題,405意味着您的服務器不允許您執行「POST」請求。您正在關注的教程在groovy文件中設置了一些標題。 – Jorg

+0

但是當我在spring-security xml中刪除行「」時,它可以工作!到底是怎麼回事? – Tong

+0

對不起,我不知道春天。我所能做的就是指出錯誤的含義。 – Jorg

回答

1

UPDATE:

選中此類似SO問題其中有例如angularjs HTTP攔截越來越直接CSRF PARAMS,並在所有的請求頭添加。

默認angularJS

原因不中link

上班提到默認情況下AngularJS提供了一種機制來實現跨站請求僞造,但是這個機制的工作,只有餅乾。由於Spring Security通過將令牌設置爲HTTP參數來工作,所以AngularJS提供的開箱即用解決方案將無法工作。

作爲spring-security-csrf-token-interceptor項目的文件中提到的 - 「一個AngularJS攔截器,設置春季安全CSRF令牌信息在所有HTTP請求」 - 它的工作原理是使頭調用接收X-CSRF-TOKEN,它然後存儲該令牌並將其與每個http請求一起發送出去。

摘要:在上述項目中添加角度攔截器以解決您的問題。檢查該github項目中提到的示例。

+0

謝謝!我遵循了您提供的鏈接並找出了實現這一目標的方式。 – Tong

0

更新:

一些調查後,我發現我誤會了CSRF與CORS(https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)。防止CSRF攻擊非常重要。我認爲只有當CSRF可以通過其他方式防止時,你可以繞過CsrfFilter。

============================================== =======

我遇到過類似的問題。根據this post,一旦SCRF被啓用,所有http請求將被CsrfFilter攔截,其中包含私人類DefaultRequiresCsrfMatcher

private static final class DefaultRequiresCsrfMatcher implements RequestMatcher { 
    private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); 

    /* (non-Javadoc) 
    * @see org.springframework.security.web.util.matcher.RequestMatcher#matches(javax.servlet.http.HttpServletRequest) 
    */ 
    public boolean matches(HttpServletRequest request) { 
     return !allowedMethods.matcher(request.getMethod()).matches(); 
    } 
} 

對於GET|HEAD|TRACE|OPTIONS方法它只會通過,而POST方法將針對其CSRF令牌進行檢查。

因此,如果您不打算通過使用CSRF向其他域公開您的POST URL,只需實現另一個用於CSRFFilter的匹配器即可繞過POST方法或某些URL模式。

+0

是的,我不打算讓其他域名使用我的帖子網址。你的意思是我甚至不需要爲這些網址添加csrf過濾器?其實我沒有其他域的任何職位,所以我可以取消csrf保護? – Tong

+0

沒有csrf與域無關,它與打擊攻擊者的請求作鬥爭。在你的問題中發佈你的類在做什麼com.tong.learn.service.security.CsrfHeaderFilter –

+0

經過一些調查後,我發現我誤解了CORS的CSRF(https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)。防止CSRF攻擊非常重要。 –