1. <ul id="0c1fb"></ul>

      <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
      <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区

      RELATEED CONSULTING
      相關(guān)咨詢
      選擇下列產(chǎn)品馬上在線溝通
      服務(wù)時間:8:30-17:00
      你可能遇到了下面的問題
      關(guān)閉右側(cè)工具欄

      新聞中心

      這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
      SpringSecurity的防Csrf攻擊實現(xiàn)代碼解析

      CSRF(Cross-site request forgery)跨站請求偽造,也被稱為One Click Attack或者Session Riding,通常縮寫為CSRF或XSRF,是一種對網(wǎng)站的惡意利用。盡管聽起來像跨站腳本(XSS),但它與XSS非常不同,XSS利用站點內(nèi)的信任用戶,而CSRF則通過偽裝成受信任用戶的請求來利用受信任的網(wǎng)站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進(jìn)行防范的資源也相當(dāng)稀少)和難以防范,所以被認(rèn)為比XSS更具危險性。

      成都創(chuàng)新互聯(lián)公司專注于大豐網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供大豐營銷型網(wǎng)站建設(shè),大豐網(wǎng)站制作、大豐網(wǎng)頁設(shè)計、大豐網(wǎng)站官網(wǎng)定制、微信小程序服務(wù),打造大豐網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供大豐網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。

      CSRF是一種依賴web瀏覽器的、被混淆過的代理人攻擊(deputy attack)。

      如何防御

      使用POST請求時,確實避免了如img、script、iframe等標(biāo)簽自動發(fā)起GET請求的問題,但這并不能杜絕CSRF攻擊的發(fā)生。一些惡意網(wǎng)站會通過表單的形式構(gòu)造攻擊請求

      public final class CsrfFilter extends OncePerRequestFilter {
       public static final RequestMatcher DEFAULT_CSRF_MATCHER = new
         CsrfFilter.DefaultRequiresCsrfMatcher();
       private final Log logger = LogFactory.getLog(this.getClass());
       private final CsrfTokenRepository tokenRepository;
       private RequestMatcher requireCsrfProtectionMatcher;
       private AccessDeniedHandler accessDeniedHandler;
       public CsrfFilter(CsrfTokenRepository csrfTokenRepository) {
        this.requireCsrfProtectionMatcher = DEFAULT_CSRF_MATCHER;
        this.accessDeniedHandler = new AccessDeniedHandlerImpl();
        Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
        this.tokenRepository = csrfTokenRepository;
       }
       //通過這里可以看出SpringSecurity的csrf機制把請求方式分成兩類來處理
       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) {
         csrfToken = this.tokenRepository.generateToken(request);
         this.tokenRepository.saveToken(csrfToken, request, response);
        }
        request.setAttribute(CsrfToken.class.getName(), csrfToken);
        request.setAttribute(csrfToken.getParameterName(), csrfToken);
      //第一類:"GET", "HEAD", "TRACE", "OPTIONS"四類請求可以直接通過
        if (!this.requireCsrfProtectionMatcher.matches(request)) {
         filterChain.doFilter(request, response);
        } else {
      //第二類:除去上面四類,包括POST都要被驗證攜帶token才能通過
         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);
         }
        }
       }
       public void setRequireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
        Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be
        null");
        this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
       }
       public void setAccessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
        Assert.notNull(accessDeniedHandler, "accessDeniedHandler cannot be null");
        this.accessDeniedHandler = accessDeniedHandler;
       }
       private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
        private final HashSet allowedMethods;
        private DefaultRequiresCsrfMatcher() {
         this.allowedMethods = new HashSet(Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
       }
        public boolean matches(HttpServletRequest request) {
         return !this.allowedMethods.contains(request.getMethod());
        }
       }
      }

      禁用Csrf

      @EnableWebSecurity
      public class WebSecurityConfig extends
      WebSecurityConfigurerAdapter {
      
      @Override
      protected void configure(HttpSecurity http) throws Exception {
       http
      //關(guān)閉打開的csrf保護
       .csrf().disable();
      }
      }

      用戶登錄時,系統(tǒng)發(fā)放一個CsrfToken值,用戶攜帶該CsrfToken值與用戶名、密碼等參數(shù)完成登錄。系統(tǒng)記錄該會話的 CsrfToken 值,之后在用戶的任何請求中,都必須帶上該CsrfToken值,并由系統(tǒng)進(jìn)行校驗。

      這種方法需要與前端配合,包括存儲CsrfToken值,以及在任何請求中(包括表單和Ajax)攜帶CsrfToken值。安全性相較于HTTP Referer提高很多,如果都是XMLHttpRequest,則可以統(tǒng)一添加CsrfToken值;但如果存在大量的表單和a標(biāo)簽,就會變得非常煩瑣。

      SpringSecurity中使用Csrf Token

      Spring Security通過注冊一個CsrfFilter來專門處理CSRF攻擊,在Spring Security中,CsrfToken是一個用于描述Token值,以及驗證時應(yīng)當(dāng)獲取哪個請求參數(shù)或請求頭字段的接口

      public interface CsrfToken extends Serializable {
       String getHeaderName();
       String getParameterName();
       String getToken();
      }
      //CsrfTokenRepository則定義了如何生成、保存以及加載CsrfToken。
      public interface CsrfTokenRepository {
       CsrfToken generateToken(HttpServletRequest request);
       void saveToken(CsrfToken token, HttpServletRequest request,
           HttpServletResponse response);
       CsrfToken loadToken(HttpServletRequest request);
      }

      HttpSessionCsrfTokenRepository

      在默認(rèn)情況下,Spring Security加載的是一個HttpSessionCsrfTokenRepository

      HttpSessionCsrfTokenRepository 將 CsrfToken 值存儲在 HttpSession 中,并指定前端把CsrfToken 值放在名為“_csrf”的請求參數(shù)或名為“X-CSRF-TOKEN”的請求頭字段里(可以調(diào)用相應(yīng)的設(shè)置方法來重新設(shè)定)。校驗時,通過對比HttpSession內(nèi)存儲的CsrfToken值與前端攜帶的CsrfToken值是否一致,便能斷定本次請求是否為CSRF攻擊。

      這種方式在某些單頁應(yīng)用中局限性比較大,靈活性不足。

      CookieCsrfTokenRepository

      Spring Security還提供了另一種方式,即CookieCsrfTokenRepository

      CookieCsrfTokenRepository 是一種更加靈活可行的方案,它將 CsrfToken 值存儲在用戶的cookie內(nèi)。減少了服務(wù)器HttpSession存儲的內(nèi)存消耗,并且當(dāng)用cookie存儲CsrfToken值時,前端可以用JavaScript讀取(需要設(shè)置該cookie的httpOnly屬性為false),而不需要服務(wù)器注入?yún)?shù),在使用方式上更加靈活。

      存儲在cookie中是不可以被CSRF利用的,cookie 只有在同域的情況下才能被讀取,所以杜絕了第三方站點跨域獲取 CsrfToken 值的可能。CSRF攻擊本身是不知道cookie內(nèi)容的,只是利用了當(dāng)請求自動攜帶cookie時可以通過身份驗證的漏洞。但服務(wù)器對 CsrfToken 值的校驗并非取自 cookie,而是需要前端手動將CsrfToken值作為參數(shù)攜帶在請求里

      下面是csrfFilter的過濾過程

      @Override
       protected void doFilterInternal(HttpServletRequest request,
         HttpServletResponse response, FilterChain filterChain)
           throws ServletException, IOException {
        request.setAttribute(HttpServletResponse.class.getName(), response);
          
          //獲取到cookie中的csrf Token(CookieTokenRepository)或者從session中獲取(HttpSessionCsrfTokenRepository)
        CsrfToken csrfToken = this.tokenRepository.loadToken(request);
        final boolean missingToken = csrfToken == null;
          //加載不到,則證明請求是首次發(fā)起的,應(yīng)該生成并保存一個新的 CsrfToken 值
        if (missingToken) {
         csrfToken = this.tokenRepository.generateToken(request);
         this.tokenRepository.saveToken(csrfToken, request, response);
        }
        request.setAttribute(CsrfToken.class.getName(), csrfToken);
        request.setAttribute(csrfToken.getParameterName(), csrfToken);
      
          //排除部分不需要驗證CSRF攻擊的請求方法(默認(rèn)忽略了GET、HEAD、TRACE和OPTIONS)
        if (!this.requireCsrfProtectionMatcher.matches(request)) {
         filterChain.doFilter(request, response);
         return;
        }
      
          //實際的token從header或者parameter中獲取
        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));
         }
         return;
        }
      
        filterChain.doFilter(request, response);
       }

      用戶想要堅持CSRF Token在cookie中。 默認(rèn)情況下CookieCsrfTokenRepository將編寫一個名為 XSRF-TOKEN的cookie和從頭部命名 X-XSRF-TOKEN中讀取或HTTP參數(shù) _csrf。

      //代碼如下:
      .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

      我們在日常使用中,可以采用header或者param的方式添加csrf_token,下面示范從cookie中獲取token

      Sign in to continue

      kaptcha

      注意事項

      springSecurity配置了默認(rèn)放行, 不需要通過csrfFilter過濾器檢測的http訪問方式

      private static final class DefaultRequiresCsrfMatcher implements RequestMatcher {
        private final HashSet allowedMethods = new HashSet<>(
          Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
        @Override
        public boolean matches(HttpServletRequest request) {
         return !this.allowedMethods.contains(request.getMethod());
        }
       }

      之所以會有上面默認(rèn)的GET,HEAD,TRACE,OPTIONS方式,是因為

      如果這個http請求是通過get方式發(fā)起的請求,意味著它只是訪問服務(wù)器 的資源,僅僅只是查詢,沒有更新服務(wù)器的資源,所以對于這類請求,spring security的防御策略是允許的;

      如果這個http請求是通過post請求發(fā)起的, 那么spring security是默認(rèn)攔截這類請求的

      因為這類請求是帶有更新服務(wù)器資源的危險操作,如果惡意第三方可以通過劫持session id來更新 服務(wù)器資源,那會造成服務(wù)器數(shù)據(jù)被非法的篡改,所以這類請求是會被Spring security攔截的,在默認(rèn)的情況下,spring security是啟用csrf 攔截功能的,這會造成,在跨域的情況下,post方式提交的請求都會被攔截?zé)o法被處理(包括合理的post請求),前端發(fā)起的post請求后端無法正常 處理,雖然保證了跨域的安全性,但影響了正常的使用,如果關(guān)閉csrf防護功能,雖然可以正常處理post請求,但是無法防范通過劫持session id的非法的post請求,所以spring security為了正確的區(qū)別合法的post請求,采用了token的機制 。

      以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。


      網(wǎng)站欄目:SpringSecurity的防Csrf攻擊實現(xiàn)代碼解析
      地址分享:http://www.ef60e0e.cn/article/picseg.html
      99热在线精品一区二区三区_国产伦精品一区二区三区女破破_亚洲一区二区三区无码_精品国产欧美日韩另类一区
      1. <ul id="0c1fb"></ul>

        <noscript id="0c1fb"><video id="0c1fb"></video></noscript>
        <noscript id="0c1fb"><listing id="0c1fb"><thead id="0c1fb"></thead></listing></noscript>

        宝清县| 仁布县| 深泽县| 甘德县| 阿图什市| 新昌县| 桐乡市| 酉阳| 祁阳县| 鸡西市| 天长市| 三穗县| 亳州市| 海丰县| 通渭县| 香港 | 松滋市| 尚志市| 黄平县| 永安市| 高邑县| 宁晋县| 河池市| 黑山县| 永清县| 安陆市| 武乡县| 墨竹工卡县| 随州市| 巴彦县| 土默特右旗| 甘德县| 肃北| 厦门市| 泸溪县| 东乌珠穆沁旗| 翁源县| 若羌县| 柳州市| 屏东县| 旺苍县|