国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開發(fā) > Java > 正文

詳解利用spring-security解決CSRF問(wèn)題

2024-07-14 08:40:23
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

CSRF介紹

CSRF(Cross-site request forgery),中文名稱:跨站請(qǐng)求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。

具體SCRF的介紹和攻擊方式請(qǐng)參看百度百科的介紹和一位大牛的分析:
CSRF百度百科
淺談CSRF攻擊方式

配置步驟

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的實(shí)現(xiàn)類CsrfSecurityRequestMatcher

這個(gè)類被用來(lái)自定義哪些請(qǐng)求是不需要進(jìn)行攔截過(guò)濾的。如果配置csrf,所有http請(qǐng)求都被會(huì)CsrfFilter攔截,而CsrfFilter中有一個(gè)私有類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方法被排除在外了,也就是說(shuō)只有GET|HEAD|TRACE|OPTIONS這4類方法會(huì)被放行,其它Method的http請(qǐng)求,都要驗(yàn)證_csrf的token是否正確,而通常post方式調(diào)用rest接口服務(wù)時(shí),又沒(méi)有_csrf的token,所以會(huì)導(dǎo)致我們的rest接口調(diào)用失敗,我們需要自定義一個(gè)類對(duì)該類型接口進(jìn)行放行。來(lái)看下我們自定義的過(guò)濾器:

源碼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);   } } 

說(shuō)明:一般我們定義的rest接口服務(wù),都帶上 /rest/ ,所以如果你的項(xiàng)目中不是使用的這種,或者項(xiàng)目中沒(méi)有rest服務(wù),這個(gè)類完全可以省略的。

5.post請(qǐng)求配置

一般我們的項(xiàng)目中都有一個(gè)通用的jsp文件,就是每個(gè)頁(yè)面都會(huì)引用的,所以我們可以在通用文件中做如下配置:

<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的意思就是給我們所有的請(qǐng)求都加上這個(gè)header和token,或者放到form表單中。注意,_csrf這個(gè)要與spring security的配置文件中的配置相匹配,默認(rèn)為_csrf。

源碼解析

我們知道,既然配置了csrf,所有的http請(qǐng)求都會(huì)被CsrfFilter攔截到,所以看下CsrfFilter的源碼就對(duì)原理一目了然了。這里我們只看具體過(guò)濾的方法即可:

源碼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為空,說(shuō)明第一次訪問(wèn),生成一個(gè)token對(duì)象       csrfToken = this.tokenRepository.generateToken(request);       this.tokenRepository.saveToken(csrfToken, request, response);     }      request.setAttribute(CsrfToken.class.getName(), csrfToken);     //把token對(duì)象放到request中,注意這里key是csrfToken.getParameterName()= _csrf,所以我們頁(yè)面上才那么寫死。     request.setAttribute(csrfToken.getParameterName(), csrfToken);          //這個(gè)macher就是我們?cè)赟pring配置文件中自定義的過(guò)濾器,也就是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);       }     }   } 

從源碼中可以看到,通過(guò)我們自定義的過(guò)濾器以外的post請(qǐng)求都需要進(jìn)行token驗(yàn)證。

本來(lái)呢,是想截圖弄個(gè)案例上去的,然后通過(guò)斷點(diǎn)看看頁(yè)面和后臺(tái)的傳值情況....不過(guò),我這里沒(méi)法上傳圖片抓狂。好吧,就總結(jié)這么多吧!如果有寫的不對(duì)的或者有其他問(wèn)題可以留言交流。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)


注:相關(guān)教程知識(shí)閱讀請(qǐng)移步到JAVA教程頻道。
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 小金县| 沙湾县| 邯郸市| 永德县| 平阴县| 河南省| 武汉市| 凉城县| 永胜县| 北川| 万山特区| 盐山县| 五河县| 平江县| 克拉玛依市| 元阳县| 石阡县| 沁水县| 垦利县| 屯门区| 孙吴县| 行唐县| 胶州市| 新河县| 湘潭县| 牡丹江市| 长兴县| 青龙| 隆回县| 青海省| 神农架林区| 锡林郭勒盟| 珲春市| 杭锦旗| 锡林浩特市| 福泉市| 呼和浩特市| 上栗县| 新巴尔虎右旗| 象州县| 双鸭山市|