跨站請求偽造防御



title: 跨站請求偽造防御
date: 2017-08-14 16:22:41
categories: 網絡安全
tags: csrf

開發相關

  • jdk1.8
  • springmvc
  • 掃描軟件 Acunetix WVS

背景

最近安全問題越來越多,公司軟件也面臨出海,剛開始公司軟件大部分部在公安內網,安全問題沒有太多重視。最近買了安全公司的掃描軟件,一掃掃出很多安全問題,其中有一個是跨站請求偽造問題。

常見的攻擊模式

GET請求利用

案例二

使用GET請求方式的利用是最簡單的一種利用方式,其隱患的來源主要是由於在開發系統的時候沒有按照HTTP動詞的正確使用方式來使用造成的。對於GET請求來說,它所發起的請求應該是只讀的,不允許對網站的任何內容進行修改。

但是事實上並不是如此,很多網站在開發的時候,研發人員錯誤的認為GET/POST的使用區別僅僅是在於發送請求的數據是在Body中還是在請求地址中,以及請求內容的大小不同。對於一些危險的操作比如刪除文章,用戶授權等允許使用GET方式發送請求,在請求參數中加上文章或者用戶的ID,這樣就造成了只要請求地址被調用,數據就會產生修改。
現在假設攻擊者(用戶ID=121)想將自己的身份添加為網站的管理員,前提是網站使用get方法修改資源,他在網站A上面發了一個帖子,里面包含一張圖片,其地址為 http://a.com/user/grant_super_user/121

<img src="http://a.com/user/grant_super_user/121" />

設想管理員看到這個帖子的時候(之所以必須是網站管理員看到,因為增加管理員可能只有admin有這個權限),這個圖片肯定會自動加載顯示的。於是在管理員不知情的情況下,一個賦予用戶管理員權限的操作已經悄悄的以他的身份執行了。這時候攻擊者121就獲取到了網站的管理員權限。

POST請求利用

相對於GET方式的利用,POST方式的利用更加復雜一些,難度也大了一些。攻擊者需要建立一個釣魚網站,偽造一個表單來發送POST請求。例如首先通過xss拿到你的cookie並鏈接到釣魚網站,此時你剛剛登錄被攻擊網站,session還在,通過誘導你進入釣魚網站,然后用吸引眼球的文字和圖片,誘導你點擊一個按鈕,向被攻擊網站發起post。

<script>
$(function() {
    $('#CSRF_forCSRFm').trigger('submit');
});
</script>
<form action="http://a.com/user/grant_super_user" id="CSRF_form" method="post">
    <input name="uid" value="121" type="hidden">
</form>

只要想辦法實現用戶訪問的時候自動提交表單就可以了。

網上的方案

  • 驗證 HTTP Referer 字段
  • 在請求地址中添加 token 並驗證
  • 在 HTTP 頭中自定義屬性並驗證

三種方案優缺點

驗證 HTTP Referer 字段

  • 容易篡改,低版本瀏覽器不安全,隱私軟件可能禁用referer
  • 公司軟件沒有域名,無法針對域名進行過濾

在請求地址/參數中添加token並驗證

  • 改動接口較多
  • 難以保證token本身安全性

在HTTP 頭中自定義屬性並驗證

  • 改動很大 幾乎要重寫網站

自己的方案

由於寫代碼的時候post get使用比較規范,get方法用於獲取資源,沒有對后台數據修改的,所以掃描的問題絕大多數在post表單提交
針對掃描軟件的掃描報告,跨站腳本攻擊都是由form表單提交的接口發起

為了能減少對代碼的修改,采用注解加攔截器的方式,這樣做的好處是通過攔截器和注解,對特定方法做出一致性處理,減少代碼量
具體流程圖如下

這里寫圖片描述

關鍵代碼CSRFInterceptor

public class CSRFInterceptor implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(CSRFInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        Method method = handlerMethod.getMethod();
        VerifyCSRFToken annotation = method.getAnnotation(VerifyCSRFToken.class);
        if (annotation != null && annotation.verify()) {
            String token = (String)request.getParameter(Constants.CSRF_TOKEN);
            if (token == null || !token.equals(request.getSession(true).getAttribute(Constants.CSRF_TOKEN))) {
                RestResult restResult = new RestResult(false, "CSRF Token Verify fail");
                restResult.putError("message" ,"CSRF Token 驗證失敗,請刷新頁面");
                response.setContentType("text/html; charset=UTF-8");
                response.setCharacterEncoding("UTF-8");
                response.getWriter().append(JsonUtlis.getJsonUtlis().object2String(restResult));
                return false;
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

關鍵代碼VerifyCSRFToken

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VerifyCSRFToken {
    boolean verify() default true;
}

關鍵代碼Controller

public class ScriptController {

    private static final ObjectMapper mapper = new ObjectMapper();

    private Logger logger = LoggerFactory.getLogger(ScriptController.class);

    @GetMapping(value = "")
    public String indexView(HttpServletRequest request, Model model) {
        model.addAttribute(Constants.CSRF_TOKEN, request.getSession(false).getAttribute(Constants.CSRF_TOKEN));
        return "script/script";
    }

	@PostMapping(value = "/upload")
    @VerifyCSRFToken
    public @ResponseBody RestResult uploadScript(@RequestParam("file")MultipartFile file, String type, 	HttpServletResponse response){
    }

參考資料
https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/
https://segmentfault.com/a/1190000008505616
http://blog.csdn.net/jrn1012/article/details/52750883
http://book.51cto.com/art/201102/245185.htm


免責聲明!

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



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