xss 攻击过程

跨站脚本攻击(Cross Site Scripting), 恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的特殊目的。

java存储map JAVA存储型XSS漏洞_java存储map

xss 的危害

XSS攻击的危害

这些危害包括但不局限于∶盗取管理员或普通用户cookie、session ;
读取、篡改、添加、删除敏感数据;
网站挂马;
非法转账;
控制受害者机器向其它网站发起攻击

xss 的三种类型

反射型XSS:

只是简单地把用户输入的数据反射给浏览器,黑客需要诱使用户点击链接。当目标用户访问该链接时,服务器接收该用户目标的请求并进行处理,然后服务器把带有XSS代码的数据发送给目标用户的浏览器,浏览器解析这段带有XSS代码的恶意脚本后,就会触发XSS漏洞。反射型XSS又称为非持久性XSS,这种攻击方式具有一次性。

存储型XSS:

把用户输入的数据”存储“在服务器端。这种XSS具有很强的稳定性。比较常见的一个场景是,攻击者写下一篇包含恶意Javascript代码的博客文章,文章发表后,所有访问
该博客文章的用户,都会在他们的浏览器中执行这段恶意的Javascript代码。黑客把恶意的脚本保存在服务器端。存储型XSS也叫持久性XSS。

DOM based XSS:

DOM全称Document Object Model,使用DOM可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式;

DOM型XSS从效果上来说也是一种反射型XSS,是基于DOM文档对象模型的一种漏洞;
HTML的标签都是节点,这些节点组成了DOM的整体结构—节点树。通过HTML DOM,树中的所有节点均可通过JavaScript进行访问。所有HTML元素(节点)均可被修改,也可以创建或删除节点。

实现原因

存入–数据库–编译–执行

必须具备以上几个条件xss攻击才会产生,即服务器原样编译了用户输入的js或者HTML

假如有下面一个textbox

<input type="text" name="address1" value="value1from">

value1from是来自用户的输入,如果用户不是输入value1from,而是输入

"/><script>alert(document.cookie)</script><!- 那么就会变成
<input type="text" name="address1" value=""/><script>alert(document.cookie)</script><!- ">

嵌入的JavaScript代码将会被执行或者用户输入的是
“οnfοcus=”alert(document.cookie) 那么就会变成

<input type="text" name="address1" value="" onfocus="alert(document.cookie)">

事件被触发的时候嵌入的JavaScript代码将会被执行攻击的威力,取决于用户输入了什么样的脚本,当然用户提交的数据还可以通QueryString(放在URL中)和Cookie发送给服务器。

xss 的防御

XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的”中括号”, “单引号”,“引号” 之类的特殊字符进行编码。

java存储map JAVA存储型XSS漏洞_java_02

xss的三种防范方式

1、编码:

对用户输入的数据进行HTML Entity 编码。把字符转换成 转义字符。Encode的作用是将$var等一些字符进行转化,使得浏览器在最终输出结果上是一样的。
比如说这段代码:’<‘script>alert(1)’<’/script>
若不进行任何处理,则浏览器会执行alert的js操作,实现XSS注入。进行编码处理之后,L在浏览器中的显示结果就是这个文本,将变量作为纯文本进行输出,且不引起JavaScript的执行。

2、过滤:

移除用户输入的和事件相关的属性。如onerror可以自动触发攻击,还有onclick等。(总而言是,过滤掉一些不安全的内容)移除用户输入的Style节点、Script节点、Iframe节点。(尤其是Script节点,它可是支持跨域的呀,一定要移除)。

3、校正:

避免直接对HTML Entity进行解码。使用DOM Parse转换,校正不配对的DOM标签。(DOM Parse:它的作用是把文本解析成DOM结构)
常见2种方法:a.第一步的编码转成文本,然后第三步转成DOM对象,然后经过第二步的过滤。 b.还有一种更简洁:首先是encode,如果是富文本,就白名单

Java代码解决方案

1、自己写 filter 拦截来实现,但要注意的时,在WEB.XML 中配置 filter 的时候,将这个 filter 放在第一位。

package com.mtlk.wd;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CharFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        MyRequestWrapper rw = new MyRequestWrapper(request);

        filterChain.doFilter(rw,response);

    }


    @Override
    public void destroy() {

    }
}

2、继承HttpServletRequestWrapper,实现对请求参数的过滤

/**
 * xss请求适配器
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
    }

    /**
     * 对数组参数进行特殊字符过滤
     */
    @Override
    public String[] getParameterValues(String name) {
        String[] values = super.getParameterValues(name);
        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;
    }

    /**
     * 对参数中特殊字符进行过滤
     */
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(name);
        if (value == null) {
            return null;
        }
        return cleanXSS(value);
    }

    /**
     * 获取attribute,特殊字符过滤
     */
    @Override
    public Object getAttribute(String name) {
        Object value = super.getAttribute(name);
        if (value != null && value instanceof String) {
            cleanXSS((String) value);
        }
        return value;
    }

    /**
     * 对请求头部进行特殊字符过滤
     */
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        if (value == null) {
            return null;
        }
        return cleanXSS(value);
    }

    /**
     * 转义字符,使用该方法存在一定的弊端
     * 
     * @param value
     * @return
     */
    private String cleanXSS2(String value) {
        // 移除特殊标签
        value = value.replaceAll("<", "<").replaceAll(">", ">");
        value = value.replaceAll("\\(", "(").replaceAll("\\)", ")");
        value = value.replaceAll("'", "'");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        value = value.replaceAll("script", "");
        return value;
    }

    private String cleanXSS(String value) {
        if (value != null) {
            //推荐使用ESAPI库来避免脚本攻击,value = ESAPI.encoder().canonicalize(value);
            // 避免空字符串
            value = value.replaceAll(" ", "");
            // 避免script 标签
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免src形式的表达式
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 删除单个的 </script> 标签
            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 删除单个的<script ...> 标签
            scriptPattern = Pattern.compile("<script(.*?)>",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 eval(...) 形式表达式
            scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 e­xpression(...) 表达式
            scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 javascript: 表达式
            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 vbscript:表达式
            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 οnlοad= 表达式
            scriptPattern = Pattern.compile("onload(.*?)=",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
        }
        return value;
    }

}