跨站請求僞造防護


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

開發相關

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

    背景

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

常見的攻擊模式

GET請求利用

案例二

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

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

<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>

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

網上的方案

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

三種方案優缺點

驗證 HTTP Referer 字段

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

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

  • 改動接口較多
  • 難以保證token自己安全性

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

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

本身的方案

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

爲了能減小對代碼的修改,採用註解加攔截器的方式,這樣作的好處是經過攔截器和註解,對特定方法作出一致性處理,減小代碼量
具體流程圖以下session

這裏寫圖片描述

關鍵代碼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

相關文章
相關標籤/搜索