`

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

 
阅读更多

转;http://www.cnblogs.com/Mainz/archive/2012/11/01/2749874.html

 

本文说一下SpringMVC如何防御CSRF(Cross-site request forgery跨站请求伪造)和XSS(Cross site script跨站脚本攻击)。

说说CSRF

CSRF来说,其实Spring3.1ASP.NET MVC3RailsDjango等 都已经支持自动在涉及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)" 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被利用)

 

好了,现在 后台改成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下载、版权购买和破解、注册码自己解决)

 

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

 

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

 

 

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

 
分享到:
评论

相关推荐

    Spring mvc简单的登陆注册功能

    登录和注册功能需要考虑的安全问题包括但不限于:密码加密存储,防止SQL注入,XSS攻击防护,CSRF(跨站请求伪造)防御,以及合适的错误消息展示,避免泄露敏感信息。 7. **异常处理**: 使用Spring MVC的异常...

    spring mvc 完整示例 前台+后台

    对于登录功能,还需要考虑安全措施,如CSRF防护、XSS防护和防止SQL注入。Spring Security是一个可选的组件,可以提供这些安全功能,但在这个简单的示例中可能并未涉及。 总结,"spring mvc 完整示例 前台+后台"项目...

    202305-Spring MVC面试题(2023最新版)思维导图.zip

    1. Java基础知识: - 语法 ...- XSS、CSRF、SQL注入等常见安全漏洞 - Spring Security安全框架 以上是Java后端必会的所有技能,掌握这些技能可以帮助开发人员在Java后端开发领域更加得心应手。

    SpringBoot +esapi 实现防止xss攻击 实战代码,满满干货

    在网络安全领域,XSS(Cross-Site Scripting)攻击是一种常见的威胁,...在实际开发中,还应关注其他安全方面,比如SQL注入、CSRF攻击等,同时遵循OWASP(开放网络应用安全项目)的最佳实践,以提升应用的整体安全性。

    基于 _Excel_ 的web的报表项目,使用spring mvc

    4. **Spring Security**:Spring Security是一个强大的安全框架,用于保护Web应用免受攻击,如未经授权的访问、XSS(跨站脚本)和CSRF(跨站请求伪造)。在这个项目中,Spring Security可能被用来确保只有经过身份...

    Java Web XSS安全防御

    10. **测试和监控**:进行渗透测试,利用工具(如Burp Suite)模拟XSS攻击,确保防御机制的有效性。同时,部署日志和监控系统,及时发现异常行为。 总之,防御XSS攻击需要从多个层面进行,包括但不限于输入验证、...

    202318-Spring Cloud面试题(2023最新版)思维导图.zip

    1. Java基础知识: - 语法 ...- XSS、CSRF、SQL注入等常见安全漏洞 - Spring Security安全框架 以上是Java后端必会的所有技能,掌握这些技能可以帮助开发人员在Java后端开发领域更加得心应手。

    springmvc+springSecurity+mybatis

    它提供了一套全面的框架来保护Web应用免受常见的安全威胁,如CSRF(跨站请求伪造)、XSS(跨站脚本攻击)等。Spring Security可以通过配置或注解的方式,轻松实现用户登录、权限控制等功能,使得开发者无需深入理解...

    SpringMVC+springAOP+spring security+Hibernate整合实例代码

    Spring Security可以保护你的应用免受各种攻击,如跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等。在这个整合实例中,Spring Security可能会配置用户登录、权限控制和URL访问过滤,以确保只有授权的用户能访问特定...

    202306-Spring面试题((2023最新版)思维导图.zip

    1. Java基础知识: - 语法 ...- XSS、CSRF、SQL注入等常见安全漏洞 - Spring Security安全框架 以上是Java后端必会的所有技能,掌握这些技能可以帮助开发人员在Java后端开发领域更加得心应手。

    最新SSM+SS整合框架,并附带sql文件

    它可以保护Web应用免受常见攻击,如跨站脚本(XSS)、跨站请求伪造(CSRF)等。通过配置,Spring Security可以实现用户登录、权限控制、会话管理等功能,确保应用的数据和操作安全。 整合SSM+SS框架的过程通常包括...

    Spring4 整合SpringMVC, Hibernate5, SpringSecurity4.2 源码

    Spring Security可以保护Web应用免受常见的攻击,如跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等。它通过Filter Chain进行安全拦截,支持多种认证机制,如基于表单、OAuth2、JWT等,并提供细粒度的访问控制。 这个...

    Spring+Hibernate+SQL Server 电子商城

    在开发过程中,需要考虑的关键点包括性能优化(如数据库设计、缓存策略)、安全性(防止XSS、CSRF攻击,保护用户数据)、扩展性(设计模块化、服务化,便于后期添加新功能)和用户体验(如页面加载速度、交互设计)...

    maven+springmvc+springSecurity

    Spring Security可以保护Web应用免受各种攻击,如CSRF(跨站请求伪造)、XSS(跨站脚本攻击)等。它通过拦截HTTP请求,执行安全检查,并根据用户的角色和权限决定是否允许访问资源。Spring Security可以与Spring MVC...

    Spring3_权威开发指南 Spring3Security-3.0.1中文官方文档

    这是一套强大且高度可配置的安全框架,可以用于保护Web应用免受各种攻击,如跨站脚本(XSS)、SQL注入、会话劫持等。文档将详细介绍如何配置Spring Security来实现用户认证(Authentication)和授权(Authorization...

    Spring

    Spring Security是一个强大的安全框架,用于保护Spring应用免受常见的攻击,如SQL注入、XSS(跨站脚本攻击)和CSRF(跨站请求伪造)。它提供了认证和授权机制,可以轻松集成到Spring应用中,确保系统的安全性。 **...

    Java Spring 的框架简介外文文献加翻译

    它可以帮助开发者保护Web应用免受各种攻击,如CSRF(跨站请求伪造)和XSS(跨站脚本)。 **文档和翻译** "Introducing the Spring Framework" 是一篇关于Spring框架的入门文章,对于初学者来说,它提供了一个了解...

    springmvc+spring+ibaits+spring security

    它可以保护应用程序免受常见的攻击,如跨站脚本(XSS)、跨站请求伪造(CSRF)等。Spring Security提供了一套全面的访问控制机制,可以定义哪些用户对哪些资源有权限,同时支持基于角色的访问控制(RBAC)和其他高级...

    2016 page220 Spring Security Essentials - Nanda Nachimuthu.pdf )

    Spring Security致力于防御各种常见的Web攻击,包括SQL注入和跨站脚本攻击(XSS)。它通过限制输入的处理和编码输出来提供额外的安全层。 9. 测试支持(Testing Support): 对于开发高质量的安全应用程序来说,...

    基于Springboot+Mybatis+SpringMvc+springsecrity+Redis完整网站后台管理系统.zip

    Spring Security是Spring生态系统中的安全模块,它提供了全面的安全管理解决方案,包括认证、授权、CSRF防护、XSS防护等。在这个系统中,Spring Security负责用户身份验证和权限控制,确保只有经过授权的用户才能...

Global site tag (gtag.js) - Google Analytics