转:防止跨站攻击,安全过滤

转: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:

复制代码
@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)" οnclick="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 ο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提交,也是一样的效果:

 

$.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-->
   

转载于:https://www.cnblogs.com/Augur/p/7904288.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/390700.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux c编程

c语言标准 ANSI CPOSIX&#xff08;提高UNIX程序可移植性&#xff09;SVID&#xff08;POSIX的扩展超集&#xff09;XPG&#xff08;X/Open可移植性指南&#xff09;GNU C&#xff08;唯一能编译Linux内核的编译器&#xff09; gcc 简介 名称&#xff1a; GNU project C an…

html怎么注释掉代码_HTML注释:如何注释掉您HTML代码

html怎么注释掉代码HTML中的注释 (Comments in HTML) The comment tag is an element used to leave notes, mostly related to the project or the website. This tag is frequently used to explain something in the code or leave some recommendations about the project.…

k均值算法 二分k均值算法_使用K均值对加勒比珊瑚礁进行分类

k均值算法 二分k均值算法Have you ever seen a Caribbean reef? Well if you haven’t, prepare yourself.您见过加勒比礁吗&#xff1f; 好吧&#xff0c;如果没有&#xff0c;请做好准备。 Today, we will be answering a question that, at face value, appears quite sim…

您好,这是我的第一篇文章

您好我是CYL 这是一个辣鸡博客 欢迎指教 转载于:https://www.cnblogs.com/pigba/p/8823472.html

08_MySQL DQL_SQL99标准中的多表查询(内连接)

# sql99语法/*语法&#xff1a; select 查询列表 from 表1 别名 【连接类型】 join 表2 别名 on 连接条件 【where 筛选条件】 【group by 分组】 【having 分组后筛选】 【order by 排序列表】分类内连接&#xff08;重点&#xff09;&#xff1a; inner外连接 左外&#xff0…

java中抽象类继承抽象类_Java中的抽象类用示例解释

java中抽象类继承抽象类Abstract classes are classes declared with abstract. They can be subclassed or extended, but cannot be instantiated. You can think of them as a class version of interfaces, or as an interface with actual code attached to the methods.抽…

新建VUX项目

使用Vue-cli安装Vux2 特别注意配置vux-loader。来自为知笔记(Wiz)

衡量试卷难度信度_我们可以通过数字来衡量语言难度吗?

衡量试卷难度信度Without a doubt, the world is “growing smaller” in terms of our access to people and content from other countries and cultures. Even the COVID-19 pandemic, which has curtailed international travel, has led to increasing virtual interactio…

Linux 题目总结

守护进程的工作就是打开一个端口&#xff0c;并且等待&#xff08;Listen&#xff09;进入连接。 如果客户端发起一个连接请求&#xff0c;守护进程就创建&#xff08;Fork&#xff09;一个子进程响应这个连接&#xff0c;而主进程继续监听其他的服务请求。 xinetd能够同时监听…

《精通Spring4.X企业应用开发实战》读后感第二章

一、配置Maven\tomcat https://www.cnblogs.com/Miracle-Maker/articles/6476687.html https://www.cnblogs.com/Knowledge-has-no-limit/p/7240585.html 二、创建数据库表 DROP DATABASE IF EXISTS sampledb; CREATE DATABASE sampledb DEFAULT CHARACTER SET utf8; USE sampl…

换了电脑如何使用hexo继续写博客

前言 我们知道&#xff0c;使用 Githubhexo 搭建一个个人博客确实需要花不少时间的&#xff0c;我们搭好博客后使用的挺好&#xff0c;但是如果我们有一天电脑突然坏了&#xff0c;或者换了系统&#xff0c;那么我们怎么使用 hexo 再发布文章到个人博客呢&#xff1f; 如果我们…

leetcode 525. 连续数组

给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组&#xff0c;并返回该子数组的长度。 示例 1: 输入: nums [0,1] 输出: 2 说明: [0, 1] 是具有相同数量 0 和 1 的最长连续子数组。 示例 2: 输入: nums [0,1,0] 输出: 2 说明: [0, 1] (或 [1, 0]) 是…

实践作业2:黑盒测试实践(小组作业)每日任务记录1

会议时间&#xff1a;2017年11月24日20:00 – 20:30 会议地点&#xff1a;在线讨论 主 持 人&#xff1a;王晨懿 参会人员&#xff1a;王晨懿、余晨晨、郑锦波、杨潇、侯欢、汪元 记 录 人&#xff1a;杨潇 会议议题&#xff1a;软件测试课程作业-黑盒测试实践的启动计划 会议内…

视图可视化 后台_如何在单视图中可视化复杂的多层主题

视图可视化 后台Sometimes a dataset can tell many stories. Trying to show them all in a single visualization is great, but can be too much of a good thing. How do you avoid information overload without oversimplification?有时数据集可以讲述许多故事。 试图在…

iam身份验证以及访问控制_如何将受限访问IAM用户添加到EKS群集

iam身份验证以及访问控制介绍 (Introduction) Elastic Kubernetes Service (EKS) is the fully managed Kubernetes service from AWS. It is deeply integrated with many AWS services, such as AWS Identity and Access Management (IAM) (for authentication to the cluste…

一步一步构建自己的管理系统①

2019独角兽企业重金招聘Python工程师标准>>> 系统肯定要先选一个基础框架。 还算比较熟悉Spring. 就选Spring boot postgres mybatis. 前端用Angular. 开始搭开发环境&#xff0c;开在window上整的。 到时候再放到服务器上。 自己也去整了个小服务器&#xff0c;…

面向对象面向过程

1、面向语句&#xff1a; 直接写原生的sql语句&#xff0c;但是这样代码不容易维护。改一个方法会导致整个项目都要改动&#xff0c; 2、面向过程 定义一些函数&#xff0c;用的时候就调用不用就不调用。但是这也有解决不了的问题&#xff0c;如果要维护需要改动代码&#xff0…

python边玩边学_边听边学数据科学

python边玩边学Podcasts are a fun way to learn new stuff about the topics you like. Podcast hosts have to find a way to explain complex ideas in simple terms because no one would understand them otherwise &#x1f642; In this article I present a few episod…

react css多个变量_如何使用CSS变量和React上下文创建主题引擎

react css多个变量CSS variables are really cool. You can use them for a lot of things, like applying themes in your application with ease. CSS变量真的很棒。 您可以将它们用于很多事情&#xff0c;例如轻松地在应用程序中应用主题。 In this tutorial Ill show you …

vue 自定义 移动端筛选条件

1.创建组件 components/FilterBar/FilterBar.vue <template><div class"filterbar" :style"{top: top px}"><div class"container"><div class"row"><divclass"col":class"{selected: ind…