1. 程式人生 > >一、Springboot安全之防CSRF攻擊

一、Springboot安全之防CSRF攻擊

(一)簡要介紹
  跨站請求偽造(Cross-site request fogery),也被稱為one-click attack或者session riding,通常縮寫為CSRF或者XSRF,是一種挾制使用者在當前已登入的WEB應用程式上執行非本意的操作的攻擊方法。

  舉個栗子:

  • 使用者小z登入了網站A,同時開啟網站B
  • 網站B隱蔽的傳送一個請求至網站A
  • 網站A通過session、cookie等身份標記判斷是使用者小z,執行對應操作

  這樣網站B內的非法程式碼就盜用了使用者小z的身份,在小z不知情的情況下執行了攻擊者需要的操作,這就是跨站請求偽造。

(二)術語解釋:

CSRF Token
  服務端為客戶端生成令牌,這個令牌將用於請求合法性校驗,一般通過請求頭或請求引數傳遞到服務端。

CSRF Token倉庫
  服務端元件,用於從請求載入或生成CSRF Token。Spring Security提供了Cookie和HttpSession兩種實現。

CSRF請求校驗匹配器
  服務端元件,用於判斷請求是否需要CSRF校驗。

(三)防止攻擊邏輯

  • 利用CSRF Token倉庫將Http請求獲取CSRF Token(該過程可以理解為Web服務端針對當前請求獲取CSRF Token)。
  • 通過CSRF Token校驗請求匹配器來判斷當前請求是否需要CSRF Token校驗,若需要,執行下一步;否則,跳過校驗。
  • 先從請求頭中獲取CSRF Token值,若不存在,再從請求引數中獲取。(該過程可以理解為獲取Web客戶端請求中的CSRF Token):
      若均未獲取到,將會轉向錯誤頁面,並且相應頭狀態碼為:403;
      若CSRF Token值獲取到,執行下一步。
  • 將第1步CSRF Token倉庫獲取的CSRF Token與客戶端請求中的CSRF Token進行比較:
       若兩值相同,校驗通過;
       若不相同,校驗失敗,將會轉向錯誤頁面,並且相應狀態碼為:403。

(四)CSRF Token倉庫
  介面:org.springframework.security.web.csrf.CsrfTokenRepository

Cookie型別(預設)
  實現類:org.springframework.security.web.csrf.CookieCsrfTokenRepository
  CSRF Token儲存:客戶端,Web瀏覽器Cookie
  有效時間:Web瀏覽器會話期間
  特別注意:Cookie方式安全係數相對較低

HttpSession型別
  實現類:org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository
  CSRF Token儲存:服務端,HttpSession(Servlet容器)
  有效時間:HttpSession 最大不活動時間間隔(#setMaxInactiveInterval(int) )
  特別注意:Servlet 容器需要支援HttpSession複製(分散式HttpSession)

(五)案例演示
新增依賴:

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

1、建立login.html頁面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登入頁面</title>
</head>
<body>
<form id="form" method="post">
    <label>使用者名稱:</label><input name="username" type="text" value="" />
    <label>密碼:</label><input name="password" type="text" value="" />
    <!--csrf驗證需要-->
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
    <br/>
    <input type="submit" value="登入">
</form>
</body>
</html>

2、建立Web 安全配置類

@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().csrfTokenRepository(new CookieCsrfTokenRepository())
                .requireCsrfProtectionMatcher(
                        /**
                         * 攔截“/login”開頭的訪問路徑,不讓訪問
                         * 攔截所有“POST”請求,不讓訪問
                         */
//                        httpServletRequest -> httpServletRequest.getRequestURI().startsWith("/login")
//                                && httpServletRequest.getMethod().equals("POST")
                        httpServletRequest -> httpServletRequest.getMethod().equals("POST")
                );
    }
}

3、建立Controller

@Controller
public class SecurityController {
    @GetMapping("/login")
    public String login(){
        return "login";
    }
    @GetMapping("/index")
    public String index(){
        return "index";
    }
}

4、案例演示效果
  在我們提交表單的時候,由於請求方法時"POST",所以該請求會被攔截住!