這篇文章主要介紹了怎么利用spring-security解決CSRF問題,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
目前創(chuàng)新互聯(lián)已為成百上千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬主機、網(wǎng)站改版維護、企業(yè)網(wǎng)站設(shè)計、金塔網(wǎng)站維護等服務(wù),公司將堅持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。CSRF介紹
CSRF(Cross-site request forgery),中文名稱:跨站請求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。
配置步驟
1.依賴jar包
<properties> <spring.security.version>4.2.2.RELEASE</spring.security.version> </properties> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring.security.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.security.version}</version> </dependency>
2.web.xml配置
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
3.Spring配置文件配置
<bean id="csrfSecurityRequestMatcher" class="com.xxx.CsrfSecurityRequestMatcher"></bean> <security:http auto-config="true" use-expressions="true"> <security:headers> <security:frame-options disabled="true"/> </security:headers> <security:csrf request-matcher-ref="csrfSecurityRequestMatcher" /> </security:http>
4.自定義RequestMatcher的實現(xiàn)類CsrfSecurityRequestMatcher
這個類被用來自定義哪些請求是不需要進行攔截過濾的。如果配置csrf,所有http請求都被會CsrfFilter攔截,而CsrfFilter中有一個私有類DefaultRequiresCsrfMatcher。
源碼1:DefaultRequiresCsrfMatcher類
private static final class DefaultRequiresCsrfMatcher implements RequestMatcher { private final HashSet<String> allowedMethods; private DefaultRequiresCsrfMatcher() { this.allowedMethods = new HashSet(Arrays.asList(new String[]{"GET", "HEAD", "TRACE", "OPTIONS"})); } public boolean matches(HttpServletRequest request) { return !this.allowedMethods.contains(request.getMethod()); } }
從這段源碼可以發(fā)現(xiàn),POST方法被排除在外了,也就是說只有GET|HEAD|TRACE|OPTIONS這4類方法會被放行,其它Method的http請求,都要驗證_csrf的token是否正確,而通常post方式調(diào)用rest接口服務(wù)時,又沒有_csrf的token,所以會導(dǎo)致我們的rest接口調(diào)用失敗,我們需要自定義一個類對該類型接口進行放行。來看下我們自定義的過濾器:
源碼2:csrfSecurityRequestMatcher類
public class CsrfSecurityRequestMatcher implements RequestMatcher { private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$"); private RegexRequestMatcher unprotectedMatcher = new RegexRequestMatcher("^/rest/.*", null); @Override public boolean matches(HttpServletRequest request) { if(allowedMethods.matcher(request.getMethod()).matches()){ return false; } return !unprotectedMatcher.matches(request); } }
說明:一般我們定義的rest接口服務(wù),都帶上 /rest/ ,所以如果你的項目中不是使用的這種,或者項目中沒有rest服務(wù),這個類完全可以省略的。
5.post請求配置
一般我們的項目中都有一個通用的jsp文件,就是每個頁面都會引用的,所以我們可以在通用文件中做如下配置:
<meta name="_csrf" content="${_csrf.token}"/> <meta name="_csrf_header" content="${_csrf.headerName}"/> <script> var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content"); $.ajaxSetup({ beforeSend: function (xhr) { if(header && token ){ xhr.setRequestHeader(header, token); } }} ); </script>
$.ajaxSetup的意思就是給我們所有的請求都加上這個header和token,或者放到form表單中。注意,_csrf這個要與spring security的配置文件中的配置相匹配,默認為_csrf。
源碼解析
我們知道,既然配置了csrf,所有的http請求都會被CsrfFilter攔截到,所以看下CsrfFilter的源碼就對原理一目了然了。這里我們只看具體過濾的方法即可:
源碼3:CsrfFilter的doFilterInternal方法
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { request.setAttribute(HttpServletResponse.class.getName(), response); CsrfToken csrfToken = this.tokenRepository.loadToken(request); boolean missingToken = csrfToken == null; if(missingToken) {//如果token為空,說明第一次訪問,生成一個token對象 csrfToken = this.tokenRepository.generateToken(request); this.tokenRepository.saveToken(csrfToken, request, response); } request.setAttribute(CsrfToken.class.getName(), csrfToken); //把token對象放到request中,注意這里key是csrfToken.getParameterName()= _csrf,所以我們頁面上才那么寫死。 request.setAttribute(csrfToken.getParameterName(), csrfToken); //這個macher就是我們在Spring配置文件中自定義的過濾器,也就是GET,HEAD, TRACE, OPTIONS和我們的rest都不處理 if(!this.requireCsrfProtectionMatcher.matches(request)) { filterChain.doFilter(request, response); } else { String actualToken = request.getHeader(csrfToken.getHeaderName()); if(actualToken == null) { actualToken = request.getParameter(csrfToken.getParameterName()); } if(!csrfToken.getToken().equals(actualToken)) { if(this.logger.isDebugEnabled()) { this.logger.debug("Invalid CSRF token found for " + UrlUtils.buildFullRequestUrl(request)); } if(missingToken) { this.accessDeniedHandler.handle(request, response, new MissingCsrfTokenException(actualToken)); } else { this.accessDeniedHandler.handle(request, response, new InvalidCsrfTokenException(csrfToken, actualToken)); } } else { filterChain.doFilter(request, response); } } }
從源碼中可以看到,通過我們自定義的過濾器以外的post請求都需要進行token驗證。
本來呢,是想截圖弄個案例上去的,然后通過斷點看看頁面和后臺的傳值情況....不過,我這里沒法上傳圖片抓狂。好吧,就總結(jié)這么多吧!如果有寫的不對的或者有其他問題可以留言交流。
感謝你能夠認真閱讀完這篇文章,希望小編分享的“怎么利用spring-security解決CSRF問題”這篇文章對大家有幫助,同時也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!
分享名稱:怎么利用spring-security解決CSRF問題-創(chuàng)新互聯(lián)
本文網(wǎng)址:http://jinyejixie.com/article18/csojgp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設(shè)計、網(wǎng)站排名、靜態(tài)網(wǎng)站、App開發(fā)、商城網(wǎng)站、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)