什么是csrf?
csrf又稱跨域請求偽造,攻擊方通過偽造用戶請求訪問受信任站點。CSRF這種攻擊方式在2000年已經被國外的安全人員提出,但在國內,直到06年才開始被關注,08年,國內外的多個大型社區和交互網站分別爆出CSRF漏洞,如:NYTimes.com(紐約時報)、Metafilter(一個大型的BLOG網站),YouTube和百度HI......而現在,互聯網上的許多站點仍對此毫無防備,以至于安全業界稱CSRF為“沉睡的巨人”。
舉個例子,用戶通過表單發送請求到銀行網站,銀行網站獲取請求參數后對用戶賬戶做出更改。在用戶沒有退出銀行網站情況下,訪問了攻擊網站,攻擊網站中有一段跨域訪問的代碼,可能自動觸發也可能點擊提交按鈕,訪問的url正是銀行網站接受表單的url。因為都來自于用戶的瀏覽器端,銀行將請求看作是用戶發起的,所以對請求進行了處理,造成的結果就是用戶的銀行賬戶被攻擊網站修改。
解決方法基本上都是增加攻擊網站無法獲取到的一些表單信息,比如增加圖片驗證碼,可以杜絕csrf攻擊,但是除了登陸注冊之外,其他的地方都不適合放驗證碼,因為降低了網站易用性
相關介紹:
http://baike.baidu.com/view/1609487.htm?fr=aladdin
spring-servlet中配置csrf
<!-- Spring csrf 攔截器 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/login" /> <bean class="com.wangzhixuan.commons.csrf.CsrfInterceptor" /> </mvc:interceptor> </mvc:interceptors>
在類中聲明Csrf攔截器,用來生成或去除CsrfToken
import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import com.wangzhixuan.commons.scan.ExceptionResolver;import com.wangzhixuan.commons.utils.WebUtils;/** * Csrf攔截器,用來生成或去除CsrfToken * * @author L.cm */public class CsrfInterceptor extends HandlerInterceptorAdapter { private static final Logger logger = LogManager.getLogger(ExceptionResolver.class); @Autowired private CsrfTokenRepository csrfTokenRepository; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; // 非控制器請求直接跳出 if (!(handler instanceof HandlerMethod)) { return true; } CsrfToken csrfToken = handlerMethod.getMethodAnnotation(CsrfToken.class); // 判斷是否含有@CsrfToken注解 if (null == csrfToken) { return true; } // create、remove同時為true時異常 if (csrfToken.create() && csrfToken.remove()) { logger.error("CsrfToken attr create and remove can Not at the same time to true!"); return renderError(request, response, Boolean.FALSE, "CsrfToken attr create and remove can Not at the same time to true!"); } // 創建 if (csrfToken.create()) { CsrfTokenBean token = csrfTokenRepository.generateToken(request); csrfTokenRepository.saveToken(token, request, response); // 緩存一個表單頁面地址的url csrfTokenRepository.cacheUrl(request, response); request.setAttribute(token.getParameterName(), token); return true; } // 判斷是否ajax請求 boolean isAjax = WebUtils.isAjax(handlerMethod); // 校驗,并且清除 CsrfTokenBean tokenBean = csrfTokenRepository.loadToken(request); if (tokenBean == null) { return renderError(request, response, isAjax, "CsrfToken is null!"); } String actualToken = request.getHeader(tokenBean.getHeaderName()); if (actualToken == null) { actualToken = request.getParameter(tokenBean.getParameterName()); } if (!tokenBean.getToken().equals(actualToken)) { return renderError(request, response, isAjax, "CsrfToken not eq!"); } return true; } private boolean renderError(HttpServletRequest request, HttpServletResponse response, boolean isAjax, String message) throws IOException { // 獲取緩存的cacheUrl String cachedUrl = csrfTokenRepository.getRemoveCacheUrl(request, response); // ajax請求直接拋出異常,因為{@link ExceptionResolver}會去處理 if (isAjax) { throw new RuntimeException(message); } // 非ajax CsrfToken校驗異常,先清理token csrfTokenRepository.saveToken(null, request, response); logger.info("Csrf[redirectUrl]:/t" + cachedUrl); response.sendRedirect(cachedUrl); return false; } /** * 用于清理@CsrfToken保證只能請求成功一次 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; // 非控制器請求直接跳出 if (!(handler instanceof HandlerMethod)) { return; } CsrfToken csrfToken = handlerMethod.getMethodAnnotation(CsrfToken.class); if (csrfToken == null || !csrfToken.remove()) { return; } csrfTokenRepository.getRemoveCacheUrl(request, response); csrfTokenRepository.saveToken(null, request, response); }}
新聞熱點
疑難解答