title: 跨站請求僞造防護
date: 2017-08-14 16:22:41
categories: 網絡安全
tags: csrf
---html
掃描軟件 Acunetix WVSjava
最近安全問題愈來愈多,公司軟件也面臨出海,剛開始公司軟件大部分部在公安內網,安全問題沒有太多重視。最近買了安全公司的掃描軟件,一掃掃出不少安全問題,其中有一個是跨站請求僞造問題。web
使用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就獲取到了網站的管理員權限。瀏覽器
相對於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
因爲寫代碼的時候post get使用比較規範,get方法用於獲取資源,沒有對後臺數據修改的,因此掃描的問題絕大多數在post表單提交
針對掃描軟件的掃描報告,跨站腳本攻擊都是由form表單提交的接口發起網絡
爲了能減小對代碼的修改,採用註解加攔截器的方式,這樣作的好處是經過攔截器和註解,對特定方法作出一致性處理,減小代碼量
具體流程圖以下session
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 { } }
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface VerifyCSRFToken { boolean verify() default true; }
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