Spring-Security對CSRF攻擊的支持


 何時使用CSRF保護
        什么時候應該使用CSRF保護?我們的建議是使用CSRF保護,可以通過瀏覽器處理普通用戶的任何請求。如果你只是創建一個非瀏覽器客戶端使用的服務,你可能會想要禁用CSRF保護。(即所有處理來自瀏覽器的請求需要是CSRF保護,如果后台服務是提供API調用那么可能就要禁用CSRF保護)

配置CSRF保護

CSRF保護默認情況下使用Java配置啟用

@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {


@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();//禁用CSRF保護
}
}

 


前提注意:SpringBoot實例中應用CSRF

The URL that triggers log out to occur (default is /logout). If CSRF protection is enabled (default), then the request must also be a POST. For more information, please consult the JavaDoc.

CSRF在SpringSecurity中默認是啟動的,那么你的退出請求必須改為POST請求。這確保了注銷需要CSRF令牌和一個惡意的用戶不能強制注銷用戶

所以在SpringSecurity中需要重新配置登出

 

package com.niugang.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;


@Configuration // 里面已經包含了@Component 所以不用再上下文中在引入入了
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// spring自帶的
@Autowired
private UserDetailsService userDetailsService;


/**
* configure(HttpSecurity)方法定義了哪些URL路徑應該被保護
*/
@Override

protected void configure(HttpSecurity http) throws Exception {


http.authorizeRequests()// 該方法所返回的對象的方法來配置請求級別的安全細節
.antMatchers("/login").permitAll() // 登錄頁面不攔截
.antMatchers("/api/**").permitAll() //調用api不需要攔截
.antMatchers(HttpMethod.POST, "/checkLogin").permitAll().anyRequest()
.authenticated()// 對於登錄路徑不進行攔截
.and().formLogin()// 配置登錄頁面
.loginPage("/login")// 登錄頁面的訪問路徑;
.loginProcessingUrl("/checkLogin")// 登錄頁面下表單提交的路徑
.failureUrl("/login?paramserror=true")// 登錄失敗后跳轉的路徑,為了給客戶端提示
.defaultSuccessUrl("/index")// 登錄成功后默認跳轉的路徑;
.and().logout()// 用戶退出操作
.logoutRequestMatcher(new AntPathRequestMatcher("/logout","POST"))// 用戶退出所訪問的路徑,需要使用Post方式
.permitAll().logoutSuccessUrl("/login?logout=true")// 退出成功所訪問的路徑
;
}

/**
* 忽略靜態資源
*/


@Override
public void configure(WebSecurity web) throws Exception {
/*
* 在springboot中忽略靜態文件路徑,直接寫靜態文件的文件夾 springboot默認有靜態文件的放置路徑,如果應用spring
* security,配置忽略路徑 不應該從springboot默認的靜態文件開始
* 如:在本項目中,所有的js和css都放在static下,如果配置忽略路徑,則不能以static開始
* 配置成web.ignoring().antMatchers("/static/*");這樣是不起作用的
*/


web.ignoring().antMatchers("/themes/**", "/script/**");


}


/**
* 配置自定義用戶服務
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
// .passwordEncoder(passwordEncoder());


}


/**
* 密碼加密
*/
/*
* @Bean public BCryptPasswordEncoder passwordEncoder() { return new
* BCryptPasswordEncoder(); }
*/
}

 



HTML中需要以表單形式POST提交退出
<form action="logout" method="post">
       <input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" /> 
    <button type='submit' class='btn btn-warning' onclick="logout();">退出</button>
</form>

 


在登錄頁面輸入用戶名和密碼,點擊登錄,頁面報如下錯誤

 

這就是頁面在登錄時沒有向后台傳入后台頒發的令牌,具體代碼如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link href="themes/bootstrap.min.css" rel="stylesheet" />
<script type="text/javascript" src="script/jquery.min.js"></script>
<!--layer彈出框-->
<link rel="stylesheet" href="script/layer/mobile/need/layer.css">
<script type="text/javascript" src="script/layer/layer.js"></script>
</head>
<!-- -->
<style>
form {
width: 60%;
margin: 0 auto;
}
</style>
<body>
<form action="checkLogin" method='post'>
<h2 style="text-align: center">spring boot</h2>
<div class="form-group">
<label for="name">姓名</label> <input type="text" class="form-control"
name="username" placeholder="姓名">
</div>
<div class="form-group">
<label for="password">密碼</label> <input type="password"
class="form-control" name="password" placeholder="密碼">
</div>
         <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> 
<button type="submit" id="btn_save"
class="btn btn-primary form-control">保存</button>
</form>


<script type="text/javascript">
   <#if errorMessage??> 
layer.msg('${errorMessage}', {icon: 4,time:1000,anim: 6});
   
   </#if>

</script>
</body>
</html>

 

這樣才能登錄成功

對於Ajax和JSON的異步請求

<head>
<meta charset="UTF-8">
<meta name="_csrf" content="${_csrf.token}" />
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}" />
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="themes/bootstrap.min.css" />
<script type="text/javascript" src="script/jquery.min.js"></script>
<script type="text/javascript" src="script/bootstrap.js"></script>
<!--layer彈出框-->
<link rel="stylesheet" href="script/layer/mobile/need/layer.css">
<script type="text/javascript" src="script/layer/layer.js"></script>
<style type="text/css">
button {
margin-left: 15px;
}
</style>
</head>

 

每次在提交請求之前先設置header里面的token,這樣才能正常運行

var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});

 

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

//代碼如下:

.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())

 

示例顯式地設置cookieHttpOnly=false. 這是必要的,允許JavaScript(例如AngularJS)讀取它。 如果你不需要使用JavaScript直接讀取cookie的能力,建議省略 cookieHttpOnly=false (通過使用new CookieCsrfTokenRepository()代替) 提高安全性.

 

 

 

The URL that triggers log out to occur (default is /logout). If CSRF protection is enabled (default), then the request must also be a POST. For more information, please consult the JavaDoc.

 

        

 微信公眾號

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM