SpringBoot 通過攔截器驗證Referer 防禦CSRF攻擊

問題:

**CSRF概念:**CSRF跨站點請求僞造(Cross—Site Request Forgery),跟XSS攻擊一樣,存在巨大的危害性,你可以這樣來理解:
攻擊者盜用了你的身份,以你的名義發送惡意請求,對服務器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義發送郵件、發消息,盜取你的賬號,添加系統管理員,甚至於購買商品、虛擬貨幣轉賬等。

如下:其中Web A爲存在CSRF漏洞的網站,Web B爲攻擊者構建的惡意網站,User C爲Web A網站的合法用戶。

  1. 首先用戶C瀏覽並登錄了受信任站點A;
  2. 登錄信息驗證通過以後,站點A會在返回給瀏覽器的信息中帶上已登錄的cookie,cookie信息會在瀏覽器端保存一定時間(根據服務端設置而定);
  3. 完成這一步以後,用戶在沒有登出(清除站點A的cookie)站點A的情況下,訪問惡意站點B;
  4. 這時惡意站點 B的某個頁面向站點A發起請求,而這個請求會帶上瀏覽器端所保存的站點 A 的cookie;
  5. 站點A根據請求所帶的 cookie,判斷此請求爲用戶C所發送的。

因此,站點A會報據用戶C的權限來處理惡意站點B所發起的請求,而這個請求可能以用戶C的身份發送 郵件、短信、消息,以及進行轉賬支付等操作,這樣惡意站點B就達到了僞造用戶C請求站點 A的目的。

受害者只需要做下面兩件事情,攻擊者就能夠完成CSRF攻擊:

  • 登錄受信任站點 A,並在本地生成cookie;
  • 在不登出站點A(清除站點A的cookie)的情況下,訪問惡意站點B。

通過Referer識別 進行CSRF防禦

在springboot項目中 ,通過增加攔截器,識別refer 即可防禦csrf 攻擊。配置自己信任的白名單“Referer”

新建攔截器配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
    @Autowired
    private RefererInterceptor refererInterceptor;
    /**
     * 添加過濾器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(refererInterceptor).addPathPatterns("/**").excludePathPatterns("/", "/login", "/logout");
    }

    @Bean
    public RefererInterceptor getInterceptor() {
        return new RefererInterceptor();
    }
}

新建攔截器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.MalformedURLException;
@Component
public class RefererInterceptor extends HandlerInterceptorAdapter {
    /**
     * 白名單
     */
    private String[] refererDomain = new String[]{"www.baidu.com","xxx.xxx.xx"};
    /**
     * 是否開啓referer校驗
     */
    private Boolean check =true;


    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        if (!check) {
            return true;
        }
        String referer = req.getHeader("referer");
        String host = req.getServerName();
        // 驗證非get請求
        if (!"GET".equals(req.getMethod())) {
            if (referer == null) {
                // 狀態置爲404
                resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return false;
            }
            java.net.URL url = null;
            try {
                url = new java.net.URL(referer);
            } catch (MalformedURLException e) {
                // URL解析異常,也置爲404
                resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return false;
            }
            // 首先判斷請求域名和referer域名是否相同
            if (!host.equals(url.getHost())) {
                // 如果不等,判斷是否在白名單中
                if (refererDomain != null) {
                    for (String s : refererDomain) {
                        if (s.equals(url.getHost())) {
                            return true;
                        }
                    }
                }
                return false;
            }
        }
        return true;
    }
}

參考:
https://blog.csdn.net/junmoxi/article/details/89208311

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章