一、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",所以該請求會被攔截住!