日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

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

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
SpringBoot 如何防御 CSRF 攻擊?

CSRF 就是跨域請(qǐng)求偽造,英文全稱(chēng)是 Cross Site Request Forgery。

創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),興縣企業(yè)網(wǎng)站建設(shè),興縣品牌網(wǎng)站建設(shè),網(wǎng)站定制,興縣網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷(xiāo),網(wǎng)絡(luò)優(yōu)化,興縣網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M(mǎn)足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專(zhuān)業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶(hù)成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。

這是一種非常常見(jiàn)的 Web 攻擊方式,其實(shí)是很好防御的,但是由于經(jīng)常被很多開(kāi)發(fā)者忽略,進(jìn)而導(dǎo)致很多網(wǎng)站實(shí)際上都存在 CSRF 攻擊的安全隱患。

今天松哥就來(lái)和大家聊一聊什么是 CSRF 攻擊以及 CSRF 攻擊該如何防御。

1.CSRF原理

想要防御 CSRF 攻擊,那我們得先搞清楚什么是 CSRF 攻擊,松哥通過(guò)下面一張圖,來(lái)和大家梳理 CSRF 攻擊流程:

其實(shí)這個(gè)流程很簡(jiǎn)單:

  • 假設(shè)用戶(hù)打開(kāi)了招商銀行網(wǎng)上銀行網(wǎng)站,并且登錄。
  • 登錄成功后,網(wǎng)上銀行會(huì)返回 Cookie 給前端,瀏覽器將 Cookie 保存下來(lái)。
  • 用戶(hù)在沒(méi)有登出網(wǎng)上銀行的情況下,在瀏覽器里邊打開(kāi)了一個(gè)新的選項(xiàng)卡,然后又去訪(fǎng)問(wèn)了一個(gè)危險(xiǎn)網(wǎng)站。
  • 這個(gè)危險(xiǎn)網(wǎng)站上有一個(gè)超鏈接,超鏈接的地址指向了招商銀行網(wǎng)上銀行。
  • 用戶(hù)點(diǎn)擊了這個(gè)超鏈接,由于這個(gè)超鏈接會(huì)自動(dòng)攜帶上瀏覽器中保存的 Cookie,所以用戶(hù)不知不覺(jué)中就訪(fǎng)問(wèn)了網(wǎng)上銀行,進(jìn)而可能給自己造成了損失。

CSRF 的流程大致就是這樣,接下來(lái)松哥用一個(gè)簡(jiǎn)單的例子和小伙伴們展示一下 CSRF 到底是怎么回事。

2.CSRF實(shí)踐

接下來(lái),我創(chuàng)建一個(gè)名為 csrf-1 的 Spring Boot 項(xiàng)目,這個(gè)項(xiàng)目相當(dāng)于我們上面所說(shuō)的網(wǎng)上銀行網(wǎng)站,創(chuàng)建項(xiàng)目時(shí)引入 Web 和 Spring Security 依賴(lài),如下:

創(chuàng)建成功后,方便起見(jiàn),我們直接將 Spring Security 用戶(hù)名/密碼 配置在 application.properties 文件中:

 
 
 
  1. spring.security.user.name=javaboy 
  2. spring.security.user.password=123 

然后我們提供兩個(gè)測(cè)試接口:

 
 
 
  1. @RestController 
  2. public class HelloController { 
  3.     @PostMapping("/transfer") 
  4.     public void transferMoney(String name, Integer money) { 
  5.         System.out.println("name = " + name); 
  6.         System.out.println("money = " + money); 
  7.     } 
  8.     @GetMapping("/hello") 
  9.     public String hello() { 
  10.         return "hello"; 
  11.     } 

假設(shè) /transfer 是一個(gè)轉(zhuǎn)賬接口(這里是假設(shè),主要是給大家演示 CSRF 攻擊,真實(shí)的轉(zhuǎn)賬接口比這復(fù)雜)。

最后我們還需要配置一下 Spring Security,因?yàn)?Spring Security 中默認(rèn)是可以自動(dòng)防御 CSRF 攻擊的,所以我們要把這個(gè)關(guān)閉掉:

 
 
 
  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.     @Override 
  4.     protected void configure(HttpSecurity http) throws Exception { 
  5.         http.authorizeRequests().anyRequest().authenticated() 
  6.                 .and() 
  7.                 .formLogin() 
  8.                 .and() 
  9.                 .csrf() 
  10.                 .disable(); 
  11.     } 

配置完成后,我們啟動(dòng) csrf-1 項(xiàng)目。

接下來(lái),我們?cè)賱?chuàng)建一個(gè) csrf-2 項(xiàng)目,這個(gè)項(xiàng)目相當(dāng)于是一個(gè)危險(xiǎn)網(wǎng)站,為了方便,這里創(chuàng)建時(shí)我們只需要引入 web 依賴(lài)即可。

項(xiàng)目創(chuàng)建成功后,首先修改項(xiàng)目端口:

 
 
 
  1. server.port=8081 

然后我們?cè)?resources/static 目錄下創(chuàng)建一個(gè) hello.html ,內(nèi)容如下:

 
 
 
  1.  
  2.  
  3.      
  4.      
  5.      
  6.  
  7.  

這里有一個(gè)超鏈接,超鏈接的文本是點(diǎn)擊查看美女圖片,當(dāng)你點(diǎn)擊了超鏈接之后,會(huì)自動(dòng)請(qǐng)求 http://localhost:8080/transfer 接口,同時(shí)隱藏域還攜帶了兩個(gè)參數(shù)。

配置完成后,就可以啟動(dòng) csrf-2 項(xiàng)目了。

接下來(lái),用戶(hù)首先訪(fǎng)問(wèn) csrf-1 項(xiàng)目中的接口,在訪(fǎng)問(wèn)的時(shí)候需要登錄,用戶(hù)就執(zhí)行了登錄操作,訪(fǎng)問(wèn)完整后,用戶(hù)并沒(méi)有執(zhí)行登出操作,然后用戶(hù)訪(fǎng)問(wèn) csrf-2 中的頁(yè)面,看到了超鏈接,好奇這美女到底長(zhǎng)啥樣,一點(diǎn)擊,結(jié)果錢(qián)就被人轉(zhuǎn)走了。

3.CSRF防御

先來(lái)說(shuō)說(shuō)防御思路。

CSRF 防御,一個(gè)核心思路就是在前端請(qǐng)求中,添加一個(gè)隨機(jī)數(shù)。

因?yàn)樵?CSRF 攻擊中,黑客網(wǎng)站其實(shí)是不知道用戶(hù)的 Cookie 具體是什么的,他是讓用戶(hù)自己發(fā)送請(qǐng)求到網(wǎng)上銀行這個(gè)網(wǎng)站的,因?yàn)檫@個(gè)過(guò)程會(huì)自動(dòng)攜帶上 Cookie 中的信息。

所以我們的防御思路是這樣:用戶(hù)在訪(fǎng)問(wèn)網(wǎng)上銀行時(shí),除了攜帶 Cookie 中的信息之外,還需要攜帶一個(gè)隨機(jī)數(shù),如果用戶(hù)沒(méi)有攜帶這個(gè)隨機(jī)數(shù),則網(wǎng)上銀行網(wǎng)站會(huì)拒絕該請(qǐng)求。黑客網(wǎng)站誘導(dǎo)用戶(hù)點(diǎn)擊超鏈接時(shí),會(huì)自動(dòng)攜帶上 Cookie 中的信息,但是卻不會(huì)自動(dòng)攜帶隨機(jī)數(shù),這樣就成功的避免掉 CSRF 攻擊了。

Spring Security 中對(duì)此提供了很好的支持,我們一起來(lái)看下。

3.1 默認(rèn)方案

Spring Security 中默認(rèn)實(shí)際上就提供了 csrf 防御,但是需要開(kāi)發(fā)者做的事情比較多。

首先我們來(lái)創(chuàng)建一個(gè)新的 Spring Boot 工程,創(chuàng)建時(shí)引入 Spring Security、Thymeleaf 和 web 依賴(lài)。

項(xiàng)目創(chuàng)建成功后,我們還是在 application.properties 中配置用戶(hù)名/密碼:

 
 
 
  1. spring.security.user.name=javaboy 
  2. spring.security.user.password=123 

接下來(lái),我們提供一個(gè)測(cè)試接口:

 
 
 
  1. @Controller 
  2. public class HelloController { 
  3.     @PostMapping("/hello") 
  4.     @ResponseBody 
  5.     public String hello() { 
  6.         return "hello"; 
  7.     } 

注意,這個(gè)測(cè)試接口是一個(gè) POST 請(qǐng)求,因?yàn)槟J(rèn)情況下,GET、HEAD、TRACE 以及 OPTIONS 是不需要驗(yàn)證 CSRF 攻擊的。

然后,我們?cè)?resources/templates 目錄下,新建一個(gè) thymeleaf 模版,如下:

 
 
 
  1.  
  2.  
  3.      
  4.      
  5.  
  6.  

注意,在發(fā)送 POST 請(qǐng)求的時(shí)候,還額外攜帶了一個(gè)隱藏域,隱藏域的 key 是 ${_csrf.parameterName},value 則是 ${_csrf.token}。

這兩個(gè)值服務(wù)端會(huì)自動(dòng)帶過(guò)來(lái),我們只需要在前端渲染出來(lái)即可。

接下來(lái)給前端 hello.html 頁(yè)面添加一個(gè)控制器,如下:

 
 
 
  1. @GetMapping("/hello") 
  2. public String hello2() { 
  3.     return "hello"; 

添加完成后,啟動(dòng)項(xiàng)目,我們?cè)L問(wèn) hello 頁(yè)面,在訪(fǎng)問(wèn)時(shí)候,需要先登錄,登錄成功之后,我們可以看到登錄請(qǐng)求中也多了一個(gè)參數(shù),如下:

可以看到,這里也多了 _csrf 參數(shù)。

這里我們用了 Spring Security 的默認(rèn)登錄頁(yè)面,如果大家使用自定義登錄頁(yè)面,可以參考上面 hello.html 的寫(xiě)法,通過(guò)一個(gè)隱藏域傳遞 _csrf 參數(shù)。

訪(fǎng)問(wèn)到 hello 頁(yè)面之后,再去點(diǎn)擊按鈕,就可以訪(fǎng)問(wèn)到 hello 接口了。

小伙伴們可以自行嘗試在 hello.html 頁(yè)面中,去掉 _csrf 參數(shù),看看訪(fǎng)問(wèn) hello 接口的效果。

這是 Spring Security 中默認(rèn)的方案,通過(guò) Model 將相關(guān)的數(shù)據(jù)帶到前端來(lái)。

如果你的項(xiàng)目是前后端不分項(xiàng)目,這種方案就可以了,如果你的項(xiàng)目是前后端分離項(xiàng)目,這種方案很明顯不夠用。

3.2 前后端分離方案

如果是前后端分離項(xiàng)目,Spring Security 也提供了解決方案。

這次不是將 _csrf 放在 Model 中返回前端了,而是放在 Cookie 中返回前端,配置方式如下:

 
 
 
  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.     @Override 
  4.     protected void configure(HttpSecurity http) throws Exception { 
  5.         http.authorizeRequests().anyRequest().authenticated() 
  6.                 .and() 
  7.                 .formLogin() 
  8.                 .and() 
  9.                 .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); 
  10.     } 

有小伙伴可能會(huì)說(shuō)放在 Cookie 中不是又被黑客網(wǎng)站盜用了嗎?其實(shí)不會(huì)的,大家注意如下兩個(gè)問(wèn)題:

  1. 黑客網(wǎng)站根本不知道你的 Cookie 里邊存的啥,他也不需要知道,因?yàn)?CSRF 攻擊是瀏覽器自動(dòng)攜帶上 Cookie 中的數(shù)據(jù)的。
  2. 我們將服務(wù)端生成的隨機(jī)數(shù)放在 Cookie 中,前端需要從 Cookie 中自己提取出來(lái) _csrf 參數(shù),然后拼接成參數(shù)傳遞給后端,單純的將 Cookie 中的數(shù)據(jù)傳到服務(wù)端是沒(méi)用的。

理解透了上面兩點(diǎn),你就會(huì)發(fā)現(xiàn) _csrf 放在 Cookie 中是沒(méi)有問(wèn)題的,但是大家注意,配置的時(shí)候我們通過(guò) withHttpOnlyFalse 方法獲取了 CookieCsrfTokenRepository 的實(shí)例,該方法會(huì)設(shè)置 Cookie 中的 HttpOnly 屬性為 false,也就是允許前端通過(guò) js 操作 Cookie(否則你就沒(méi)有辦法獲取到 _csrf)。

配置完成后,重啟項(xiàng)目,此時(shí)我們就發(fā)現(xiàn)返回的 Cookie 中多了一項(xiàng):

接下來(lái),我們通過(guò)自定義登錄頁(yè)面,來(lái)看看前端要如何操作。

首先我們?cè)?resources/static 目錄下新建一個(gè) html 頁(yè)面叫做 login.html:

 
 
 
  1.  
  2.  
  3.  
  4.      
  5.     Title 
  6.      
  7.      
  8.  
  9.  
  10.  
  11.      
  12.      
  13.      
 
  •  
  •  
  •  
  • 這段 html 我給大家解釋下:

    1. 首先引入 jquery 和 jquery.cookie ,方便我們一會(huì)操作 Cookie。
    2. 定義三個(gè) input,前兩個(gè)是用戶(hù)名和密碼,第三個(gè)是登錄按鈕。
    3. 點(diǎn)擊登錄按鈕之后,我們先從 Cookie 中提取出 XSRF-TOKEN,這也就是我們要上傳的 csrf 參數(shù)。
    4. 通過(guò)一個(gè) POST 請(qǐng)求執(zhí)行登錄操作,注意攜帶上 _csrf 參數(shù)。

    服務(wù)端我們也稍作修改,如下:

     
     
     
    1. @Configuration 
    2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    3.     @Override 
    4.     public void configure(WebSecurity web) throws Exception { 
    5.         web.ignoring().antMatchers("/js/**"); 
    6.     } 
    7.  
    8.     @Override 
    9.     protected void configure(HttpSecurity http) throws Exception { 
    10.         http.authorizeRequests().anyRequest().authenticated() 
    11.                 .and() 
    12.                 .formLogin() 
    13.                 .loginPage("/login.html") 
    14.                 .successHandler((req,resp,authentication)->{ 
    15.                     resp.getWriter().write("success"); 
    16.                 }) 
    17.                 .permitAll() 
    18.                 .and() 
    19.                 .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); 
    20.     } 

    一方面這里給 js 文件放行。

    另一方面配置一下登錄頁(yè)面,以及登錄成功的回調(diào),這里簡(jiǎn)單期間,登錄成功的回調(diào)我就給一個(gè)字符串就可以了。大家感興趣的話(huà),可以查看本系列前面文章,有登錄成功后回調(diào)的詳細(xì)解釋。

    OK,所有事情做完之后,我們?cè)L問(wèn) login.html 頁(yè)面,輸入用戶(hù)名密碼進(jìn)行登錄,結(jié)果如下:

    可以看到,我們的 _csrf 配置已經(jīng)生效了。

    小伙伴們可以自行嘗試從登錄參數(shù)中去掉 _csrf,然后再看看效果。

    4.小結(jié)

    好了,今天主要和小伙伴們介紹了 csrf 攻擊以及如何防御的問(wèn)題。大家看到,csrf 攻擊主要是借助了瀏覽器默認(rèn)發(fā)送 Cookie 的這一機(jī)制,所以如果你的前端是 App、小程序之類(lèi)的應(yīng)用,不涉及瀏覽器應(yīng)用的話(huà),其實(shí)可以忽略這個(gè)問(wèn)題,如果你的前端包含瀏覽器應(yīng)用的話(huà),這個(gè)問(wèn)題就要認(rèn)真考慮了。

    好了 ,本文就說(shuō)到這里,本文相關(guān)案例我已經(jīng)上傳到 GitHub ,大家可以自行下載:https://github.com/lenve/spring-security-samples

    本文轉(zhuǎn)載自微信公眾號(hào)「江南一點(diǎn)雨」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系江南一點(diǎn)雨公眾號(hào)。


    網(wǎng)頁(yè)題目:SpringBoot 如何防御 CSRF 攻擊?
    文章位置:http://m.5511xx.com/article/coddeci.html