成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot 如何防御 CSRF 攻擊?

安全 應用安全
CSRF 就是跨域請求偽造,英文全稱是 Cross Site Request Forgery。這是一種非常常見的 Web 攻擊方式,其實是很好防御的,但是由于經常被很多開發者忽略,進而導致很多網站實際上都存在 CSRF 攻擊的安全隱患。

[[403473]]

CSRF 就是跨域請求偽造,英文全稱是 Cross Site Request Forgery。

這是一種非常常見的 Web 攻擊方式,其實是很好防御的,但是由于經常被很多開發者忽略,進而導致很多網站實際上都存在 CSRF 攻擊的安全隱患。

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

1.CSRF原理

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

其實這個流程很簡單:

  • 假設用戶打開了招商銀行網上銀行網站,并且登錄。
  • 登錄成功后,網上銀行會返回 Cookie 給前端,瀏覽器將 Cookie 保存下來。
  • 用戶在沒有登出網上銀行的情況下,在瀏覽器里邊打開了一個新的選項卡,然后又去訪問了一個危險網站。
  • 這個危險網站上有一個超鏈接,超鏈接的地址指向了招商銀行網上銀行。
  • 用戶點擊了這個超鏈接,由于這個超鏈接會自動攜帶上瀏覽器中保存的 Cookie,所以用戶不知不覺中就訪問了網上銀行,進而可能給自己造成了損失。

CSRF 的流程大致就是這樣,接下來松哥用一個簡單的例子和小伙伴們展示一下 CSRF 到底是怎么回事。

2.CSRF實踐

接下來,我創建一個名為 csrf-1 的 Spring Boot 項目,這個項目相當于我們上面所說的網上銀行網站,創建項目時引入 Web 和 Spring Security 依賴,如下:

創建成功后,方便起見,我們直接將 Spring Security 用戶名/密碼 配置在 application.properties 文件中:

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

然后我們提供兩個測試接口:

  1. @RestController 
  2. public class HelloController { 
  3.     @PostMapping("/transfer"
  4.     public void transferMoney(String nameInteger 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.     } 

假設 /transfer 是一個轉賬接口(這里是假設,主要是給大家演示 CSRF 攻擊,真實的轉賬接口比這復雜)。

最后我們還需要配置一下 Spring Security,因為 Spring Security 中默認是可以自動防御 CSRF 攻擊的,所以我們要把這個關閉掉:

  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.     } 

配置完成后,我們啟動 csrf-1 項目。

接下來,我們再創建一個 csrf-2 項目,這個項目相當于是一個危險網站,為了方便,這里創建時我們只需要引入 web 依賴即可。

項目創建成功后,首先修改項目端口:

  1. server.port=8081 

然后我們在 resources/static 目錄下創建一個 hello.html ,內容如下:

  1. <body> 
  2. <form action="http://localhost:8080/transfer" method="post"
  3.     <input type="hidden" value="javaboy" name="name"
  4.     <input type="hidden" value="10000" name="money"
  5.     <input type="submit" value="點擊查看美女圖片"
  6. </form> 
  7. </body> 

 

 

 

這里有一個超鏈接,超鏈接的文本是點擊查看美女圖片,當你點擊了超鏈接之后,會自動請求 http://localhost:8080/transfer 接口,同時隱藏域還攜帶了兩個參數。

配置完成后,就可以啟動 csrf-2 項目了。

接下來,用戶首先訪問 csrf-1 項目中的接口,在訪問的時候需要登錄,用戶就執行了登錄操作,訪問完整后,用戶并沒有執行登出操作,然后用戶訪問 csrf-2 中的頁面,看到了超鏈接,好奇這美女到底長啥樣,一點擊,結果錢就被人轉走了。

3.CSRF防御

先來說說防御思路。

CSRF 防御,一個核心思路就是在前端請求中,添加一個隨機數。

因為在 CSRF 攻擊中,黑客網站其實是不知道用戶的 Cookie 具體是什么的,他是讓用戶自己發送請求到網上銀行這個網站的,因為這個過程會自動攜帶上 Cookie 中的信息。

所以我們的防御思路是這樣:用戶在訪問網上銀行時,除了攜帶 Cookie 中的信息之外,還需要攜帶一個隨機數,如果用戶沒有攜帶這個隨機數,則網上銀行網站會拒絕該請求。黑客網站誘導用戶點擊超鏈接時,會自動攜帶上 Cookie 中的信息,但是卻不會自動攜帶隨機數,這樣就成功的避免掉 CSRF 攻擊了。

Spring Security 中對此提供了很好的支持,我們一起來看下。

3.1 默認方案

Spring Security 中默認實際上就提供了 csrf 防御,但是需要開發者做的事情比較多。

首先我們來創建一個新的 Spring Boot 工程,創建時引入 Spring Security、Thymeleaf 和 web 依賴。

項目創建成功后,我們還是在 application.properties 中配置用戶名/密碼:

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

接下來,我們提供一個測試接口:

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

注意,這個測試接口是一個 POST 請求,因為默認情況下,GET、HEAD、TRACE 以及 OPTIONS 是不需要驗證 CSRF 攻擊的。

然后,我們在 resources/templates 目錄下,新建一個 thymeleaf 模版,如下:

  1. <body> 
  2. <form action="/hello" method="post"
  3.     <input type="hidden" th:value="${_csrf.token}" th:name="${_csrf.parameterName}"
  4.     <input type="submit" value="hello"
  5. </form> 
  6. </body> 

 

 

 

注意,在發送 POST 請求的時候,還額外攜帶了一個隱藏域,隱藏域的 key 是 ${_csrf.parameterName},value 則是 ${_csrf.token}。

這兩個值服務端會自動帶過來,我們只需要在前端渲染出來即可。

接下來給前端 hello.html 頁面添加一個控制器,如下:

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

添加完成后,啟動項目,我們訪問 hello 頁面,在訪問時候,需要先登錄,登錄成功之后,我們可以看到登錄請求中也多了一個參數,如下:

可以看到,這里也多了 _csrf 參數。

這里我們用了 Spring Security 的默認登錄頁面,如果大家使用自定義登錄頁面,可以參考上面 hello.html 的寫法,通過一個隱藏域傳遞 _csrf 參數。

訪問到 hello 頁面之后,再去點擊按鈕,就可以訪問到 hello 接口了。

小伙伴們可以自行嘗試在 hello.html 頁面中,去掉 _csrf 參數,看看訪問 hello 接口的效果。

這是 Spring Security 中默認的方案,通過 Model 將相關的數據帶到前端來。

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

3.2 前后端分離方案

如果是前后端分離項目,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.     } 

有小伙伴可能會說放在 Cookie 中不是又被黑客網站盜用了嗎?其實不會的,大家注意如下兩個問題:

  1. 黑客網站根本不知道你的 Cookie 里邊存的啥,他也不需要知道,因為 CSRF 攻擊是瀏覽器自動攜帶上 Cookie 中的數據的。
  2. 我們將服務端生成的隨機數放在 Cookie 中,前端需要從 Cookie 中自己提取出來 _csrf 參數,然后拼接成參數傳遞給后端,單純的將 Cookie 中的數據傳到服務端是沒用的。

理解透了上面兩點,你就會發現 _csrf 放在 Cookie 中是沒有問題的,但是大家注意,配置的時候我們通過 withHttpOnlyFalse 方法獲取了 CookieCsrfTokenRepository 的實例,該方法會設置 Cookie 中的 HttpOnly 屬性為 false,也就是允許前端通過 js 操作 Cookie(否則你就沒有辦法獲取到 _csrf)。

配置完成后,重啟項目,此時我們就發現返回的 Cookie 中多了一項:

接下來,我們通過自定義登錄頁面,來看看前端要如何操作。

首先我們在 resources/static 目錄下新建一個 html 頁面叫做 login.html:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <meta charset="UTF-8"
  5.     <title>Title</title> 
  6.     <script src="js/jquery.min.js"></script> 
  7.     <script src="js/jquery.cookie.js"></script> 
  8. </head> 
  9. <body> 
  10. <div> 
  11.     <input type="text" id="username"
  12.     <input type="password" id="password"
  13.     <input type="button" value="登錄" id="loginBtn"
  14. </div> 
  15. <script> 
  16.     $("#loginBtn").click(function () { 
  17.         let _csrf = $.cookie('XSRF-TOKEN'); 
  18.         $.post('/login.html',{username:$("#username").val(),password:$("#password").val(),_csrf:_csrf},function (data) { 
  19.             alert(data); 
  20.         }) 
  21.     }) 
  22. </script> 
  23. </body> 
  24. </html> 

 

 

 

 

 

這段 html 我給大家解釋下:

  1. 首先引入 jquery 和 jquery.cookie ,方便我們一會操作 Cookie。
  2. 定義三個 input,前兩個是用戶名和密碼,第三個是登錄按鈕。
  3. 點擊登錄按鈕之后,我們先從 Cookie 中提取出 XSRF-TOKEN,這也就是我們要上傳的 csrf 參數。
  4. 通過一個 POST 請求執行登錄操作,注意攜帶上 _csrf 參數。

服務端我們也稍作修改,如下:

  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 文件放行。

另一方面配置一下登錄頁面,以及登錄成功的回調,這里簡單期間,登錄成功的回調我就給一個字符串就可以了。大家感興趣的話,可以查看本系列前面文章,有登錄成功后回調的詳細解釋。

OK,所有事情做完之后,我們訪問 login.html 頁面,輸入用戶名密碼進行登錄,結果如下:

可以看到,我們的 _csrf 配置已經生效了。

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

4.小結

好了,今天主要和小伙伴們介紹了 csrf 攻擊以及如何防御的問題。大家看到,csrf 攻擊主要是借助了瀏覽器默認發送 Cookie 的這一機制,所以如果你的前端是 App、小程序之類的應用,不涉及瀏覽器應用的話,其實可以忽略這個問題,如果你的前端包含瀏覽器應用的話,這個問題就要認真考慮了。

好了 ,本文就說到這里,本文相關案例我已經上傳到 GitHub ,大家可以自行下載:https://github.com/lenve/spring-security-samples

本文轉載自微信公眾號「江南一點雨」,可以通過以下二維碼關注。轉載本文請聯系江南一點雨公眾號。

 

責任編輯:武曉燕 來源: 江南一點雨
相關推薦

2016-09-30 15:59:41

2010-09-13 09:20:21

2009-10-29 17:47:31

2019-02-22 09:00:00

2018-10-12 15:50:02

2021-06-30 07:25:35

開發JavaXSS

2012-11-30 14:54:48

2012-11-30 14:35:17

2012-08-17 09:25:59

2021-06-07 14:06:19

Spring SecuCSRF防御

2024-10-12 10:57:21

2015-07-23 10:18:45

2022-05-19 11:29:14

計時攻擊SpringSecurity

2014-06-26 11:33:42

2013-11-04 09:15:58

2020-12-01 16:50:18

CC攻擊DDoS攻擊網絡攻擊

2018-05-21 15:14:10

2010-09-08 12:35:51

2010-10-08 10:03:16

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人免费在线视频 | 亚洲欧美一区二区三区1000 | 日韩成人一区 | 久久99深爱久久99精品 | 伊人二区| 成人免费看片网 | 欧美精品成人一区二区三区四区 | 亚洲一区二区三区在线播放 | 天天狠狠 | 成人网在线 | 91原创视频在线观看 | 国产一区二区毛片 | 九九99九九精彩46 | 日韩欧美国产精品 | 成人久久久 | 精品九九久久 | 91传媒在线播放 | 国产1区2区3区 | 国产精品久久一区二区三区 | 日日夜夜天天久久 | 81精品国产乱码久久久久久 | 精品一区二区三区在线视频 | 日韩精品免费在线观看 | 久久99精品久久久久久国产越南 | 精品国产第一区二区三区 | 欧美一级在线视频 | 国产精品国产成人国产三级 | 日韩成人国产 | 成人中文字幕在线 | 黄色香蕉视频在线观看 | 天天干免费视频 | 成人欧美| 欧美涩涩网 | 超碰av免费 | 一级aaaaaa毛片免费同男同女 | 自拍视频一区二区三区 | 欧美一区二区三区视频在线播放 | 亚洲一区二区三区在线播放 | av在线伊人| 罗宾被扒开腿做同人网站 | 中文字幕一区二区三区四区五区 |