Spring REST 配置CSRF防禦

Spring REST 配置CSRF防禦

內容從如下幾個方面展開

  • 什麼是CSRF防禦
  • 如何運用CSRF進行防護(WEB)
  • 如何將CSRF防護,運用到REST中 

1.什麼是CSRF

CSRF 攻擊簡單來講,是多Tab頁面瀏覽器的一個安全漏洞,好比你正在訪問A網站,此時若是瀏覽器有你的cookie,而且session沒有過時,此時你去訪問B網站,那麼B網站能夠直接調用A網站的接口,而A網站則認爲是你本人進行的操做。如下是圖示:java

2.如何進行防護

對CSRF進行防護,能夠經過加Token.也就是當你訪問A網站的時候,A會給你一個token,而後,接下去的post請求,你須要把token帶上,否則服務器則拒絕接收這個請求。 
- 1. token的產生:spring-security 4.0以後默認開啓csrf,能夠直接產生csrf token。 
- 2. token的存儲:這裏存儲是指服務端的存儲,token是存儲在session中。 
- 3. token的傳送:token能夠經過cookie,也能夠放在header中自定義的屬性中。 
- 4. token的接收和返回:前段收到http respon 以後,須要把相應的token返回回來。 
- 5. token校驗:服務器端對本身持有的token和客戶端反饋回來的token進行校驗,決定是否拒絕服務(拒絕服務能夠自定義)。web

3.REST 的CSRF防護

通常寫REST服務(也就是直接@ResponseBody)返回json字符串,則能夠把token加在header裏頭的自定義屬性中,爲何不能直接加在header中的cooike裏,spring-sercurity官方給出的答案:spring

One might ask why the expected CsrfToken isn’t stored in a cookie by default. This is because there are known exploits in which headers (i.e. specify the cookies) can be set by another domain. This is the same reason Ruby on Rails no longer skips CSRF checks when the header X-Requested-With is present. See this webappsec.org thread for details on how to perform the exploit. Another disadvantage is that by removing the state (i.e. the timeout) you lose the ability to forcibly terminate the token if it is compromised.json

翻譯一下: 
- 1.cookie能夠被其餘域設置 
- 2.cookie是沒有狀態的,可是若是是session(含有過時時間),則可使session過時,從而使token失效。(若有出入,歡迎拍磚)promise

既然如此,那麼須要在header中加入token,咱們只要註冊一個Filter,就能夠完成這個功能: 
- STEP 1 建立Filter瀏覽器

/** * * "將CSRF TOKEN加入到header中" * * Created by hzlaojiaqi on 2016/9/13. */
public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
    protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
    protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
    protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
    protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
        CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);

        if (token != null) {
            response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
            response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
            response.setHeader(RESPONSE_TOKEN_NAME , token.getToken());
        }

        filterChain.doFilter(request, response);
    }
}

 

  • STEP 2 加入到過濾器中安全

    @Configuration
    @EnableWebSecurity
    public class SecurityConfigure extends WebSecurityConfigurerAdapter {
    
    private static final Logger THIRDPARTY_LOG = LoggerFactory.getLogger("THIRDPARTY_LOGGER");
    
    @Autowired
    UserService userService;
    
    protected  void configure(HttpSecurity httpSecurity) throws Exception {
        CsrfTokenResponseHeaderBindingFilter csrfTokenFilter = new CsrfTokenResponseHeaderBindingFilter();
        CustomAccessDeniedHandler accessDeniedHandler=new CustomAccessDeniedHandler();
        httpSecurity.addFilterAfter(csrfTokenFilter,CsrfFilter.class);
    }
    }

實驗

    1. 首先進行Get請求,獲取header中CSRF的token(圖片忘記保存了)
    1. 在header中加入token,發起post請求
    1. 不在header中加入token,發起post請求

狀況2 帶header發起token服務器

 
能夠看到,服務器端正確返回數據。cookie

狀況3 不帶header發起tokensession

  能夠看到,服務器端 拒絕了咱們的請求。

相關文章
相關標籤/搜索