Spring Security4 之 csrf

CSRF(Cross-site request forgery跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。爲了防止跨站提交攻擊,一般會配置csrf。javascript

Spring Security 爲了防止跨站提交攻擊提供了CSRF保護功能,該功能在Spring Security 3時就已經存在,默認是不啓用,Spring Security 4默認啓用了,因此由Spring Security 3升級到Spring Security 4就會有全部POST方式請求的服務會調用失敗的問題,緣由在於:啓用csrf後,全部http請求都被會CsrfFilter攔截,而CsrfFilter中有一個私有類DefaultRequiresCsrfMatcher。html

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

從這段源碼能夠發現,POST方法被排除在外了,也就是說只有GET|HEAD|TRACE|OPTIONS這4類方法會被放行,其它Method的http請求,都要驗證_csrf的token是否正確,而一般post方式調用rest服務時,又沒有_csrf的token,因此校驗失敗。java

 

若是想禁用CSRF保護功能,可採起如下方式:jquery

Security XML配置文件中配置:web

<csrf disabled="true" />

若是你使用JAVA註解配置:ajax

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable();
  }
}

 

若是正常使用CSRF:spring

對於表單域,可增長一個標籤<security:csrfInput/>,這個標籤會生成一個隱藏域。ide

<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %> 

<form action="login" class="login-form" method="post" style="display: inline-table;">  
   //其餘表單域
   <security:csrfInput/>
   <button type="submit" class="btn btn-success btn-block">登 錄</button>  
</form>

//<security:csrfInput/>實際會生成<input type="hidden" name="_csrf" value="XXXXXXXXXXXXXXXXXXXX">

對於非表單域,增長<security:csrfMetaTags/>,該標籤可在報文頭增長crsf的token。post

<%@ taglib prefix='security' uri='http://www.springframework.org/security/tags' %>  

<!DOCTYPE html>  
<html lang="zh">  
  <head>  
    <meta charset="utf-8">  
    <title>首頁</title>  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <security:csrfMetaTags/> 


//這個標籤會生成如下內容
<meta name="_csrf_parameter" content="_csrf" />  
<meta name="_csrf_header" content="X-CSRF-TOKEN" />  
<meta name="_csrf" content="XXXXXXXXXXXXXXXXXX" />

最後寫一個jquery提交的處理網站

(function(){  
    $(document).ajaxSend(function(e,xhr,opt) {  
        if (opt.type == "POST"){  
            var header = $('meta[name=_csrf_header]').attr('content');  
            var token  = $('meta[name=_csrf]').attr('content');   
            if (header != '' && token != ''){             
                xhr.setRequestHeader(header, token);  
            }  
        }  
    });  
})();
相關文章
相關標籤/搜索