Spring MVC防御CSRF、XSS和SQL注入攻击

栏目: 编程工具 · 发布时间: 7年前

内容简介: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:

Spring MVC防御CSRF、XSS和 <a href='https://www.codercto.com/topics/18630.html'>SQL</a> 注入攻击

其实即使不是在同一个页面打开,在不同的tab打开也是一样可以通过网站登录验证的,因为受害者首先已经登录了网站,在浏览网站的过程中,若网站设置了Session cookie,那么在浏览器进程的生命周期内,即使浏览器同一个窗口打开了新的tab页面,Session cookie也都是有效的,他们在浏览器同一个窗口的多个tab页面里面是共享的(注:现在Gmail支持多个tab同时持有多个SessionID)。所以攻击步骤是,第一,受害者必须在同一浏览器窗口(即使不是同一tab)内访问并登陆目标站点;第二,这使得Session cookie有效,从而利用受害者的身份进行恶意操作。

再举个实际的例子,假设我们界面上有删除某一项的链接,例如:<a href=”javascript:void(0)” onclick=”region_del.do?name=0000001″>Delete</a>;

其Java Spring MVC后台有个函数是删除某个item,注意是GET不是POST:

@RequestMapping(value = region_del.do”, method = RequestMethod.GET)
 public String regionDel(@RequestParam String name, Locale locale)
 {
 //Delete region name=@name….return “redirect:/region.html”;
 }

点击界面上那个<a href=”javascript:void(0)” onclick=”region_del.do?name=0000001″>Delete</a>链接,就后台删除某项,看起来非常正常啊。

好,现在你登录你的网站,然后在另外一个tab打开这个html文件:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
 <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被利用)

Spring MVC防御CSRF、XSS和SQL注入攻击 Spring MVC防御CSRF、XSS和SQL注入攻击

好了,现在 后台改成POST(写操作尽量用POST),前台界面那个删除的链接改成Form提交:

<form action=”region_del.do” method=”POST”>
 <input type=”hidden” name=”name” value=”0000001″>
 <input type=”submit” value=”Delete” />
 </form>

看起来安全多了。OK,现在你登录你的网站,然后在另外一个tab打开这个html文件:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
 <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 onload=’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提交,也是一样的效果:

$.ajax({
 type: “POST”,
 url:….
 });

解决办法就是在 Form表单加一个hidden field,里面是服务端生成的足够随机数的一个Token,使得黑客猜不到也无法仿照Token

先写一个类,生成足够随机数的Token(注:Java的Random UUID已经足够随机了,参考这个和这个)

package com.ibm.cn.web.beans;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:

<input type=”hidden” name=”CSRFToken” value=”${csrf}” />

然后在后台提交的时候验证token :

@RequestMapping(value = region_del.do”, method = RequestMethod.GET)
 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里面:

    var headers = {};
 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里面:

protected boolean isValidCsrfHeaderToken() {
 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加上:

<context-param>
 <param-name>defaultHtmlEscape</param-name>
 <param-value>true</param-value>
 </context-param>

Forms加上:

<spring:htmlEscape defaultHtmlEscape=”true” />

更多信息查看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:

package com.ibm.web.beans;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 :

package com.ibm.web.beans;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>
 <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等的攻击手段,例如:

输入用户名 :    >”‘><script>alert(1779)</script>

输入用户名:     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–>

Web安全漏洞检测工具

推荐使用IBM Rational AppScan(IBM Rational AppScan下载、版权购买和破解、注册码自己解决)

Spring MVC防御CSRF、XSS和SQL注入攻击

可以录制脚本,设置URL,如果网站需要登录,可以设置自动登录:

Spring MVC防御CSRF、XSS和SQL注入攻击

检测结果还可以保持为专业的pdf检测报告

Spring MVC防御CSRF、XSS和SQL注入攻击

业界安全编程标准最佳实践


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Development with Rails 4

Agile Web Development with Rails 4

Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2013-10-11 / USD 43.95

Ruby on Rails helps you produce high-quality, beautiful-looking web applications quickly. You concentrate on creating the application, and Rails takes care of the details. Tens of thousands of deve......一起来看看 《Agile Web Development with Rails 4》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具