文档章节

Spring3.x通过配置来防范csrf攻击

java梦想家01
 java梦想家01
发布于 2015/10/16 13:24
字数 1683
阅读 1819
收藏 10

1. [代码]CsrfTokenManager 用于管理csrfToken相关     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
packagecom.uncle5.pubrub.web.common;
 
importjava.util.UUID;
 
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpSession;
 
publicfinalclassCsrfTokenManager {
 
    // 隐藏域参数名称
    staticfinalString CSRF_PARAM_NAME ="CSRFToken";
 
    // session中csrfToken参数名称
    publicstaticfinalString CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CsrfTokenManager.class
            .getName() +".tokenval";
 
    privateCsrfTokenManager() {
    };
 
    // 在session中创建csrfToken
    publicstaticString createTokenForSession(HttpSession session) {
        String token =null;
 
        synchronized(session) {
            token = (String) session
                    .getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);
            if(null== token) {
                token = UUID.randomUUID().toString();
                session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);
            }
        }
        returntoken;
    }
 
    publicstaticString getTokenFromRequest(HttpServletRequest request) {
        returnrequest.getParameter(CSRF_PARAM_NAME);
    }
}

2. [代码]CsrfRequestDataValueProcessor 自动创建hidden的csrfToken域的类     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
packagecom.uncle5.pubrub.web.common;
 
importjava.util.Map;
 
importjavax.servlet.http.HttpServletRequest;
 
importorg.springframework.stereotype.Component;
importorg.springframework.web.servlet.support.RequestDataValueProcessor;
 
importcom.google.common.collect.Maps;
 
@Component("requestDataValueProcessor")
publicclassCsrfRequestDataValueProcessorimplementsRequestDataValueProcessor {
 
    @Override
    publicString processAction(HttpServletRequest request, String action) {
        // TODO 暂时原样返回action
        returnaction;
    }
 
    @Override
    publicString processFormFieldValue(HttpServletRequest request,
            String name, String value, String type) {
        // TODO 暂时原样返回value
        returnvalue;
    }
 
    @Override
    publicMap<String, String> getExtraHiddenFields(HttpServletRequest request) {
        //此处是当使用spring的taglib标签<form:form>创建表单时候,增加的隐藏域参数
        Map<String, String> hiddenFields = Maps.newHashMap();
        hiddenFields.put(CsrfTokenManager.CSRF_PARAM_NAME,
                CsrfTokenManager.createTokenForSession(request.getSession()));
 
        returnhiddenFields;
    }
 
    @Override
    publicString processUrl(HttpServletRequest request, String url) {
        // TODO 暂时原样返回url
        returnurl;
    }
 
}

3. [代码]CsrfInterceptor 对于post请求进行拦截,检测csrfToken是否匹配     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
packagecom.uncle5.pubrub.web.security;
 
importjava.net.URLEncoder;
 
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
 
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.util.StringUtils;
importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
importcom.uncle5.pubrub.web.common.CsrfTokenManager;
importcom.uncle5.pubrub.web.common.WebUser;
 
publicclassCsrfInterceptorextendsHandlerInterceptorAdapter {
 
    privatestaticfinalLogger logger = LoggerFactory
            .getLogger(CsrfInterceptor.class);
 
    @Autowired
    WebUser webUser;
 
    @Override
    publicbooleanpreHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler)throwsException {
 
        if("POST".equalsIgnoreCase(request.getMethod())) {
            String CsrfToken = CsrfTokenManager.getTokenFromRequest(request);
            if(CsrfToken ==null
                    || !CsrfToken.equals(request.getSession().getAttribute(
                            CsrfTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME))) {
                String reLoginUrl ="/login?backurl="
                        + URLEncoder.encode(getCurrentUrl(request),"utf-8");
 
                response.sendRedirect(reLoginUrl);
                returnfalse;
            }
        }
 
        returntrue;
    }
 
    privateString getCurrentUrl(HttpServletRequest request) {
        String currentUrl = request.getRequestURL().toString();
        if(!StringUtils.isEmpty(request.getQueryString())) {
            currentUrl +="?"+ request.getQueryString();
        }
 
        returncurrentUrl;
    }
}

4. [代码]springMVC 配置文件,增加需要进行拦截的url     

?
1
2
3
4
5
6
7
8
<!-- 安全拦截用的 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mappingpath="/forum/post"/>
            <mvc:mappingpath="/forum/reply/*"/>
            <beanclass="com.uncle5.pubrub.web.security.CsrfInterceptor"/>
        </mvc:interceptor>       
    </mvc:interceptors>

5. [代码]jsp页面,需要注意的是必须使用spring的form标签     

?
1
2
3
4
5
6
7
8
9
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
 
<divstyle="margin: 0 auto; border: 1px solid orange; width: 80%; height: 400px;">
        <form:formaction="/forum/post"method="post">
            <span>标题:</span><inputtype="text"name="title"id="title">
            <textareaname="content"id="content"rows="30"cols="40"></textarea>
            <inputtype="submit"name="submit"value="submit">
        </form:form>
    </div>

6. [代码]jsp页面 查看源码会发现已经添加上了hidden字段     

?
1
2
3
4
5
6
7
8
<divstyle="margin: 0 auto; border: 1px solid orange; width: 80%; height: 400px;">
        <formid="command"action="/forum/post"method="post">
            <span>标题:</span><inputtype="text"name="title"id="title">
            <textareaname="content"id="content"rows="30"cols="40"></textarea>          
            <inputtype="submit"name="submit"value="submit">
        <inputtype="hidden"name="CSRFToken"value="35afec82-da7b-449e-9ae9-b38664b5af63"/>
</form>
    </div>

7. [代码]相关原理说明     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1.只有当使用spring的form标签时候,才会在渲染jsp页面时候触发
org.springframework.web.servlet.tags.form.FormTag 类中的
 
@Override
    publicintdoEndTag()throwsJspException {
        RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
        ServletRequest request =this.pageContext.getRequest();
        if((processor !=null) && (requestinstanceofHttpServletRequest)) {
            writeHiddenFields(processor.getExtraHiddenFields((HttpServletRequest) request));
        }
        this.tagWriter.endTag();
        returnEVAL_PAGE;
    }
该方法会调用上文中所说的CsrfRequestDataValueProcessor中的创建隐藏域的方法getExtraHiddenFields来创建csrfToken隐藏域。
 
2.对相关需要进行防范csrf攻击的post请求地址进行拦截,此处是依赖springMVC中提供的拦截器机制来操作的
<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/forum/post"/>
            <mvc:mapping path="/forum/reply/*"/>
            <beanclass="com.uncle5.pubrub.web.security.CsrfInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
当用户访问"/forum/post"这个请求时候,会直接进入CsrfInterceptor的preHandle方法,此处针对post请求

1. [代码]CsrfTokenManager 用于管理csrfToken相关     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
packagecom.uncle5.pubrub.web.common;
 
importjava.util.UUID;
 
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpSession;
 
publicfinalclassCsrfTokenManager {
 
    // 隐藏域参数名称
    staticfinalString CSRF_PARAM_NAME ="CSRFToken";
 
    // session中csrfToken参数名称
    publicstaticfinalString CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CsrfTokenManager.class
            .getName() +".tokenval";
 
    privateCsrfTokenManager() {
    };
 
    // 在session中创建csrfToken
    publicstaticString createTokenForSession(HttpSession session) {
        String token =null;
 
        synchronized(session) {
            token = (String) session
                    .getAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME);
            if(null== token) {
                token = UUID.randomUUID().toString();
                session.setAttribute(CSRF_TOKEN_FOR_SESSION_ATTR_NAME, token);
            }
        }
        returntoken;
    }
 
    publicstaticString getTokenFromRequest(HttpServletRequest request) {
        returnrequest.getParameter(CSRF_PARAM_NAME);
    }
}

2. [代码]CsrfRequestDataValueProcessor 自动创建hidden的csrfToken域的类     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
packagecom.uncle5.pubrub.web.common;
 
importjava.util.Map;
 
importjavax.servlet.http.HttpServletRequest;
 
importorg.springframework.stereotype.Component;
importorg.springframework.web.servlet.support.RequestDataValueProcessor;
 
importcom.google.common.collect.Maps;
 
@Component("requestDataValueProcessor")
publicclassCsrfRequestDataValueProcessorimplementsRequestDataValueProcessor {
 
    @Override
    publicString processAction(HttpServletRequest request, String action) {
        // TODO 暂时原样返回action
        returnaction;
    }
 
    @Override
    publicString processFormFieldValue(HttpServletRequest request,
            String name, String value, String type) {
        // TODO 暂时原样返回value
        returnvalue;
    }
 
    @Override
    publicMap<String, String> getExtraHiddenFields(HttpServletRequest request) {
        //此处是当使用spring的taglib标签<form:form>创建表单时候,增加的隐藏域参数
        Map<String, String> hiddenFields = Maps.newHashMap();
        hiddenFields.put(CsrfTokenManager.CSRF_PARAM_NAME,
                CsrfTokenManager.createTokenForSession(request.getSession()));
 
        returnhiddenFields;
    }
 
    @Override
    publicString processUrl(HttpServletRequest request, String url) {
        // TODO 暂时原样返回url
        returnurl;
    }
 
}

3. [代码]CsrfInterceptor 对于post请求进行拦截,检测csrfToken是否匹配     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
packagecom.uncle5.pubrub.web.security;
 
importjava.net.URLEncoder;
 
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
 
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.util.StringUtils;
importorg.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 
importcom.uncle5.pubrub.web.common.CsrfTokenManager;
importcom.uncle5.pubrub.web.common.WebUser;
 
publicclassCsrfInterceptorextendsHandlerInterceptorAdapter {
 
    privatestaticfinalLogger logger = LoggerFactory
            .getLogger(CsrfInterceptor.class);
 
    @Autowired
    WebUser webUser;
 
    @Override
    publicbooleanpreHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler)throwsException {
 
        if("POST".equalsIgnoreCase(request.getMethod())) {
            String CsrfToken = CsrfTokenManager.getTokenFromRequest(request);
            if(CsrfToken ==null
                    || !CsrfToken.equals(request.getSession().getAttribute(
                            CsrfTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME))) {
                String reLoginUrl ="/login?backurl="
                        + URLEncoder.encode(getCurrentUrl(request),"utf-8");
 
                response.sendRedirect(reLoginUrl);
                returnfalse;
            }
        }
 
        returntrue;
    }
 
    privateString getCurrentUrl(HttpServletRequest request) {
        String currentUrl = request.getRequestURL().toString();
        if(!StringUtils.isEmpty(request.getQueryString())) {
            currentUrl +="?"+ request.getQueryString();
        }
 
        returncurrentUrl;
    }
}

4. [代码]springMVC 配置文件,增加需要进行拦截的url     

?
1
2
3
4
5
6
7
8
<!-- 安全拦截用的 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mappingpath="/forum/post"/>
            <mvc:mappingpath="/forum/reply/*"/>
            <beanclass="com.uncle5.pubrub.web.security.CsrfInterceptor"/>
        </mvc:interceptor>       
    </mvc:interceptors>

5. [代码]jsp页面,需要注意的是必须使用spring的form标签     

?
1
2
3
4
5
6
7
8
9
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
 
<divstyle="margin: 0 auto; border: 1px solid orange; width: 80%; height: 400px;">
        <form:formaction="/forum/post"method="post">
            <span>标题:</span><inputtype="text"name="title"id="title">
            <textareaname="content"id="content"rows="30"cols="40"></textarea>
            <inputtype="submit"name="submit"value="submit">
        </form:form>
    </div>

6. [代码]jsp页面 查看源码会发现已经添加上了hidden字段     

?
1
2
3
4
5
6
7
8
<divstyle="margin: 0 auto; border: 1px solid orange; width: 80%; height: 400px;">
        <formid="command"action="/forum/post"method="post">
            <span>标题:</span><inputtype="text"name="title"id="title">
            <textareaname="content"id="content"rows="30"cols="40"></textarea>          
            <inputtype="submit"name="submit"value="submit">
        <inputtype="hidden"name="CSRFToken"value="35afec82-da7b-449e-9ae9-b38664b5af63"/>
</form>
    </div>

7. [代码]相关原理说明     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1.只有当使用spring的form标签时候,才会在渲染jsp页面时候触发
org.springframework.web.servlet.tags.form.FormTag 类中的
 
@Override
    publicintdoEndTag()throwsJspException {
        RequestDataValueProcessor processor = getRequestContext().getRequestDataValueProcessor();
        ServletRequest request =this.pageContext.getRequest();
        if((processor !=null) && (requestinstanceofHttpServletRequest)) {
            writeHiddenFields(processor.getExtraHiddenFields((HttpServletRequest) request));
        }
        this.tagWriter.endTag();
        returnEVAL_PAGE;
    }
该方法会调用上文中所说的CsrfRequestDataValueProcessor中的创建隐藏域的方法getExtraHiddenFields来创建csrfToken隐藏域。
 
2.对相关需要进行防范csrf攻击的post请求地址进行拦截,此处是依赖springMVC中提供的拦截器机制来操作的
<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/forum/post"/>
            <mvc:mapping path="/forum/reply/*"/>
            <beanclass="com.uncle5.pubrub.web.security.CsrfInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
当用户访问"/forum/post"这个请求时候,会直接进入CsrfInterceptor的preHandle方法,此处针对post请求

本文转载自:http://www.oschina.net/code/snippet_1029551_27153

共有 人打赏支持
java梦想家01
粉丝 11
博文 61
码字总数 14212
作品 0
海淀
对CSRF你了解多少

CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它...

FantJ
2017/11/28
0
0
01-Spring Security框架学习--入门(二)

一、入门案例 Spring Security 自定义登录界面 通过之前的一节 01-Spring Security框架学习--入门(一)的简单演示,Spring security 使用框架自带的登录界面,下面的案例将使用自己定义的登...

weir_will
08/07
0
0
经常被忽视的攻击 —— CSRF (跨站请求伪造)

CSRF(Cross-site request forgery 跨站请求伪造,也被称成为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它...

oschina
2012/10/06
5.6K
9
CSRF/XSRF 跨站请求伪造

CSRF(Cross Site Request Forgery, 跨站域请求伪造)也称 XSRF, 是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一。其他安全隐患,比如 SQL 脚本注入,跨站域脚本攻击...

给你添麻烦了
01/13
0
0
面试宝典系列-Web安全与攻击

一、SQL注入攻击(SQL Injection) 攻击者把SQL命令插入到Web表单的输入域或页面请求的字符串,欺骗服务器执行恶意的SQL命令。 防范方法: 1.检查变量数据类型和格式 2.过滤特殊符号 3.绑定变量...

suyain
09/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

jQuery学习笔记180923

射手

颖伙虫
5分钟前
0
0
[python] colorama 模块 - 改变控制台输出文本的颜色

除了使用 PyQt 这样的图形化开发框架外,基本上 python 程序都是跑在控制台中的。很多时候,单纯使用黑白的文字不能很好地突出我们要显示的信息。有时候我们需要将错误的提示使用红色标注,而...

cometeme
10分钟前
0
0
Makefile 学习 2 - 基于若干 Blog 的汇总

基于若干 Blog 汇总的 makefile 教程 陈皓 https://blog.csdn.net/haoel/article/details/2886 Makefile 进阶 1. Makefile 中的内容 显式规则。显式规则说明了,如何生成一个或多的的目标文件...

公孙衍
25分钟前
0
0
NIO与BIO的区别、NIO的运行原理和并发使用场景

NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,成为解决高并发与大量连接、I/O处理问题的...

Java干货分享
43分钟前
1
0
72.告警系统邮件引擎 运行告警系统

20.23/20.24/20.25 告警系统邮件引擎 20.26 运行告警系统 20.23/20.24/20.25 告警系统邮件引擎 邮件首先要有一个mail.py,以下。 因为我们之前zabbix的时候做过,就可以直接拷贝过来 mail.s...

王鑫linux
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部