转:防止跨站攻击,安全过滤
转:http://blog.csdn.net/zpf0918/article/details/43952511
Spring MVC防御CSRF、XSS和SQL注入攻击
本文说一下SpringMVC如何防御CSRF(Cross-site request forgery跨站请求伪造)和XSS(Cross site script跨站脚本攻击)。
说说CSRF
对CSRF来说,其实Spring3.1、ASP.NET MVC3、Rails、Django等都已经支持自动在涉及POST的地方添加Token(包括FORM表单和AJAX POST等),似乎是一个tag的事情,但如果了解一些实现原理,手工来处理,也是有好处的。因为其实很多人做web开发,但涉及到web安全方面的都是比较资深的开发人员,很多人安全意识非常薄弱,CSRF是什么根本没有听说过。所以对他们来说,CSRF已经是比较高深的东西了。先说说什么是CSRF?你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。CSRF一般都是利用你的已登录已验证的身份来发送恶意请求。比较著名的一个例子就是2009年黑客利用Gmail的一个CSRF漏洞成功获取好莱坞明星Vanessa Hudgens的独家艳照。其攻击过程非常简单,给该明星的gmail账户发了一封email,标题是某大导演邀请你来看看这个电影,里面有个图片:<img src="https://mail.google.com/mail?ui=2&fw=true&fwe=hacker@email.com">,结果她登录Gmail,打开邮件就默默无闻的中招了,所有邮件被转发到黑客的账号。因为当时Gmail设置转发的设置页面有漏洞,其设置方法是打开一个窗口,点击确定后实际URL是https://mail.google.com/mail?ui=2&fw=true&fwe=newMail@email.com:
其实即使不是在同一个页面打开,在不同的tab打开也是一样可以通过网站登录验证的,因为受害者首先已经登录了网站,在浏览网站的过程中,若网站设置了Session cookie,那么在浏览器进程的生命周期内,即使浏览器同一个窗口打开了新的tab页面,Session cookie也都是有效的,他们在浏览器同一个窗口的多个tab页面里面是共享的(注:现在Gmail支持多个tab同时持有多个SessionID)。所以攻击步骤是,第一,受害者必须在同一浏览器窗口(即使不是同一tab)内访问并登陆目标站点;第二,这使得Session cookie有效,从而利用受害者的身份进行恶意操作。
再举个实际的例子,假设我们界面上有删除某一项的链接,例如:<a href="javascript:void(0)" οnclick="region_del.do?name=0000001">Delete</a>;
其Java Spring MVC后台有个函数是删除某个item,注意是GET不是POST:
public String regionDel(@RequestParam String name, Locale locale)
{
//Delete region name=@name....
return "redirect:/region.html";
}
点击界面上那个<a href="javascript:void(0)" οnclick="region_del.do?name=0000001">Delete</a>链接,就后台删除某项,看起来非常正常啊。
好,现在你登录你的网站,然后在另外一个tab打开这个html文件:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>hack</title>
</head>
<body>
<img src="http://localhost/testsite/region_del.do?name=0000001"/>
</body>
</html>
发现同样被删除了某项。试想,如果是网银,你的钱已经被转账......(除了referer不一样,session cookie被利用)
好了,现在 后台改成POST(写操作尽量用POST),前台界面那个删除的链接改成Form提交:
<input type="hidden" name="name" value="0000001">
<input type="submit" value="Delete" />
</form>
看起来安全多了。OK,现在你登录你的网站,然后在另外一个tab打开这个html文件:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Hack</title>
<script>
function steal(){
var mySubmit = document.getElementById('steal_form');
mySubmit.submit();
}
</script>
</head>
<body οnlοad='steal()'>
<form id = "steal_form" method="POST" action="http://localhost/testsite/region_del.do">
<input type="hidden" name="func" value="post">
<input type="hidden" name="name" value="0000001">
</form>
</body>
</html>
当然,你如果前台还是用链接,但改成js,用AJAX POST提交,也是一样的效果:
type: "POST",
url:....
});
解决办法就是在Form表单加一个hidden field,里面是服务端生成的足够随机数的一个Token,使得黑客猜不到也无法仿照Token。
先写一个类,生成足够随机数的Token(注:Java的Random UUID已经足够随机了,参考这个和这个)
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* A manager for the CSRF token for a given session. The {@link #getTokenForSession(HttpSession)} should used to
* obtain the token value for the current session (and this should be the only way to obtain the token value).
* ***/
public final class CSRFTokenManager {
/**
* The token parameter name
*/
static final String CSRF_PARAM_NAME = "CSRFToken";
/**
* The location on the session which stores the token
*/
public static final String CSRF_TOKEN_FOR_SESSION_ATTR_NAME = CSRFTokenManager.class
.getName() + ".tokenval";
public static String getTokenForSession(HttpSession session) {
String token = null;
// I cannot allow more than one token on a session - in the case of two
// requests trying to
// init the token concurrently
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);
}
}
return token;
}
/**
* Extracts the token value from the session
*
* @param request
* @return
*/
public static String getTokenFromRequest(HttpServletRequest request) {
return request.getParameter(CSRF_PARAM_NAME);
}
private CSRFTokenManager() {
};
}
打开Form页面的时候在服务端生成Token并保存到Session中,例如:model.addAttribute("csrf", CSRFTokenManager.getTokenForSession(this.session));
然后在Form中添加Hidden field:
然后在后台提交的时候验证token :
public String regionDel(@RequestParam String name, @RequestParam String CSRFToken, Locale locale)
{
if(CSRFToken == null || !CSRFToken.equals(session.getAttribute(CSRFTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME).toString())){
logger.debug("CSRF attack detected. URL: region_edit.do");
return "redirect:/login.form";
}
//Delete region name=@name....
return "redirect:/region.html";
}
你还可以把上面的步骤写到BaseController里面,或者写到拦截器里面,拦截所有POST请求,验证CSRF Token。这里掠过....
如果你用AJAX POST的方法,那么后台一样,前台也要有Hidden field保存Token,然后在提交AJAX POST的时候加上该csrf参数即可。(更多csrf参考这个和这个。)
AJAX POST的CSRF防御
首先在页面进入的时候从后台生成一个Token(每个session),放到一个Hidden input(用Spring tag或freemarker可以写) 。然后在ajax post提交的时候放到http请求的header里面:
headers['__RequestVerificationToken'] = $("#CSRFToken").val();
$.ajax({
type: "POST",
headers: headers,
cache: false,
url: base + "ajax/domain/delete.do",
data: "id=123",
dataType:"json",
async: true,
error: function(data, error) {},
success: function(data)
{
}
});
然后在后台controller里面校验header里面这个token,也可以把这个函数放到baseController里面:
if (getRequest().getHeader("__RequestVerificationToken") == null
|| session
.getAttribute(CSRFTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME) == null
|| !this.getRequest()
.getHeader("__RequestVerificationToken")
.equals(session
.getAttribute(
CSRFTokenManager.CSRF_TOKEN_FOR_SESSION_ATTR_NAME)
.toString())) {
return false;
}
return true;
}
xss
关于xss的介绍可以看这个和这个网页,具体我就讲讲Spring MVC里面的预防:
web.xml加上:
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
Forms加上:
更多信息查看OWASP的页面
第二种方法是手动escape,例如用户可以输入:<script>alert()</script> 或者输入<h2>abc<h2>,如果有异常,显然有xss漏洞。
首先添加一个jar包:commons-lang-2.5.jar ,然后在后台调用这些函数:StringEscapeUtils.escapeHtml(string); StringEscapeUtils.escapeJavaScript(string); StringEscapeUtils.escapeSql(string);
前台js调用escape函数即可。
第三种方法是后台加Filter,对每个post请求的参数过滤一些关键字,替换成安全的,例如:< > ' " \ / # &
方法是实现一个自定义的HttpServletRequestWrapper,然后在Filter里面调用它,替换掉getParameter函数即可。
首先添加一个XssHttpServletRequestWrapper:
import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values==null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null)
return null;
return cleanXSS(value);
}
private String cleanXSS(String value) {
//You'll need to remove the spaces from the html entities below
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
return value;
}
}
然后添加一个过滤器XssFilter :
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class XssFilter implements Filter {
FilterConfig filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssHttpServletRequestWrapper(
(HttpServletRequest) request), response);
}
}
最后在web.xml里面配置一下,所有的请求的getParameter会被替换,如果参数里面 含有敏感词会被替换掉:
<filter-name>XssSqlFilter</filter-name>
<filter-class>com.ibm.web.beans.XssFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XssSqlFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
(这个Filter也可以防止SQL注入攻击)
登录页面的攻击例子
假设登录页面有个输入用户名和密码的输入框,可以有很多Xss/csrf/注入钓鱼网站/SQL等的攻击手段,例如:
输入用户名: usera>"'><img src="javascript:alert(23664)">
输入用户名: "'><IMG SRC="/WF_XSRF.html--end_hig--begin_highlight_tag--hlight_tag--">
输入用户名: usera'"><iframe src=http://demo.testfire.net--en--begin_highlight_tag--d_highlight_tag-->
转载于:https://www.cnblogs.com/Augur/p/7904288.html
转:防止跨站攻击,安全过滤相关推荐
- xss跨站攻击【网络攻防CTF】(保姆级图文)
目录 什么是xss跨站攻击 实验内容 实验步骤 如何避免xss跨站攻击 总结 欢迎关注 『网络攻防CTF』 系列,持续更新中 欢迎关注 『网络攻防CTF』 系列,持续更新中 什么是xss跨站攻击 跨站 ...
- 总结 XSS 与 CSRF 两种跨站攻击
在那个年代,大家一般用拼接字符串的方式来构造动态 SQL 语句创建应用,于是 SQL 注入成了很流行的攻击方式.在这个年代, 参数化查询 [1] 已经成了普遍用法,我们已经离 SQL 注入很远了.但是 ...
- http referer 验证防御方法_渗透测试 跨站攻击防御与安全检测手法剖析
上一节讲到了渗透测试中xss跨站攻击检测方法和防护,这一节也是关于跨站攻击的另一个手法CSRF,很多客户找到我们想要了解更多的跨站攻击检测方法以及防御此类攻击的办法,想要让网站的安全性更加坚固,对此提 ...
- XSS与CSRF两种跨站攻击比较
XSS:跨站脚本(Cross-site scripting) CSRF:跨站请求伪造(Cross-site request forgery) 在那个年代,大家一般用拼接字符串的方式来构造动态SQL 语 ...
- XSS和CSRF两种跨站攻击比较
以下是我从一个大佬那转过来的 觉得写得非常非常好哈哈哈 忍不住想转载 可惜好像从博客园直接转过来转不过来 这是原文链接 XSS:跨站脚本(Cross-site scripting) CSRF:跨站请求 ...
- 总结XSS与CSRF两种跨站攻击
XSS:跨站脚本(Cross-site scripting),实际应是"CSS",但由于和层叠样式表CSS名称冲突,故改为"XSS" CSRF:跨站请求伪造(C ...
- 渗透测试 跨站攻击手法剖析
上一节讲到了渗透测试中xss跨站攻击检测方法和防护,这一节也是关于跨站攻击的另一个手法CSRF,很多客户找到我们Sinesafe想要了解更多的跨站攻击检测方法以及防御此类攻击的办法,想要让网站的安全性 ...
- Cross-Site Scripting XSS 跨站攻击全攻略
原文:http://a1pass.blog.163.com/blog/static/2971373220087295449497/ 题记:这是我在<黑客X档案>08年第5期发表的一篇文章, ...
- 如何进行渗透测试XSS跨站攻击检测
国庆假期结束,这一节准备XSS跨站攻击渗透测试中的利用点,上一节讲了SQL注入攻击的详细流程,很多朋友想要咨询具体在跨站攻击上是如何实现和利用的,那么我们Sinesafe渗透测试工程师为大家详细的讲讲 ...
- PHP中SQL注入与跨站攻击的防范
SQL injection即SQL注入是我们每个WEB程序员都需要面对的问题,一个WEB应用假如没有起码的安全性,那么其它的一切就可以免谈了.注入问题在ASP上可谓是闹得沸沸扬扬,当然还有不少PHP程 ...
最新文章
- 科大星云诗社动态20210421
- 搭建express框架
- 鼠标手势识别 [Flash]
- 移动云11.11,钜惠High不停!
- 动态定义table每行两列
- SQLSERVER2005的安装目录结构(上)
- 英特尔 XML 安全网关
- 解决电脑右侧数字键盘无法打出数字问题
- 宁向东认为的沟通分类
- stroj uplink
- 2019网络小说十大口碑神作盘点,诡秘剑来谍影覆汉牧神学霸皆在
- 快速配置Tomcat,解决Tomcat卡住不动
- CSS颜色属性、文本文字属性、属性继承
- php 对文件加密,PHP文件加密
- python数据写入csv、csv转excel、用Pandas把数据写入excel简单总结
- Scratch模拟中国嫦娥探月工程,探索月球的背面!
- 超牛逼的性能调优神器 — 火焰图
- Marlin架构解析
- 2022红队必备工具列表总结
- 聊天机器人ChatGPT刷爆网络,我们与它聊了聊量子计算
热门文章
- mysql5 varchar_MYSQL 5.7 VARCHAR 类型实验
- html 用svg缩放拉伸,html – 拉伸SVG以适应其父级的100%高度和宽度
- Redis对象的refcount与lru属性(内存回收、对象共享、空转时长)
- Leetcode226. 翻转二叉树(递归、迭代、层序三种解法)
- 【C++ grammar】常量、指针、Usage of using, typedef, and #define
- Java LinkedList对象的get(int index)方法与示例
- 取地址符和解引用符的区别_(&)和解引用(*)运算符的地址以及C中的指针...
- Java——集合转数组并对其进行遍历
- cigarettes(香烟)
- 达尔豪斯大学计算机科学世界排名,达尔豪斯大学成了全加最好,这又是个什么排名?...