首页 > 代码库 > 跨站脚本漏洞

跨站脚本漏洞

跨站脚本漏洞,首先看一下专业说明:

跨站脚本漏洞可以再分成两类:Stored attack 和 Reflected attack。这两种攻击的主要区别在于有效负荷到达服务器的方式。Stored attack 仅以某种形式存储在目标服务器上(例如在数据库中),或通过提交至公告板或访问者日志来进行存储。如果请求了所存储的信息,受害者将在自己的浏览器中检索和执行攻击代码。而 Reflected attack 则来自其他地方。当通过动态生成的网页中的服务器端,直接将 Web 客户端的用户输入包含在内时,就会出现 Reflected attack。通过某些社会工程手段,例如通过恶意链接或“伪装”表单,攻击者可以哄骗受害者提交信息,然后对信息进行修改以包含攻击代码,并将其发送至合法服务器。注入的代码随后将反射回用户的浏览器,由于此代码来自受信任的服务器,用户的浏览器将会执行此代码。两种攻击的影响都是相同的。

关于XSS 跨站脚本攻击(Cross Site Scripting),最简单直接的就是在输入框中存入例如<script>alert(600)</script>这样的js代码,影响到系统的正常使用,甚至威胁系统安全。想了解更多的专业解释,可以在网上搜索一下,参考百度百科的解释http://baike.baidu.com/view/2161269.htm。

但在实际的应用中如何去防止这种攻击呢,下面给介绍个办法。

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

配置过滤器

技术分享 程序代码
public class XSSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
    }

}


再实现 ServletRequest 的包装类

技术分享 程序代码

import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class XSSRequestWrapper extends HttpServletRequestWrapper {

    public XSSRequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
    }

    @Override
    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] = stripXSS(values[i]);
        }

        return encodedValues;
    }

    @Override
    public String getParameter(String parameter) {
        String value = http://www.mamicode.com/super.getParameter(parameter);

        return stripXSS(value);
    }

    @Override
    public String getHeader(String name) {
        String value = http://www.mamicode.com/super.getHeader(name);
        return stripXSS(value);
    }

    private String stripXSS(String value) {
        if (value != null) {
            // NOTE: It‘s highly recommended to use the ESAPI library and uncomment the following line to
            // avoid encoded attacks.
            // value = http://www.mamicode.com/ESAPI.encoder().canonicalize(value);

            // Avoid null characters
            value = http://www.mamicode.com/value.replaceAll("", "");

            // Avoid anything between script tags
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Avoid anything in a src=http://www.mamicode.com/‘...‘ type of e­xpression
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\‘(.*?)\\\‘", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Remove any lonesome </script> tag
            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Remove any lonesome <script ...> tag
            scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Avoid eval(...) e­xpressions
            scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Avoid e­xpression(...) e­xpressions
            scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Avoid javascript:... e­xpressions
            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Avoid vbscript:... e­xpressions
            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");

            // Avoid onl oad= e­xpressions
            scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = http://www.mamicode.com/scriptPattern.matcher(value).replaceAll("");
        }
        return value;
    }
}


例子中注释的部分,就是采用 ESAPI library 来防止XSS攻击的,推荐使用.
当然,我还看到这样一种办法,将所有的编程全角字符的解决方式,但个人觉得并没有上面这种用正则表达式替换的好

技术分享 程序代码

private static String xssEncode(String s) {
        if (s == null || s.equals("")) {
            return s;
        }
        StringBuilder sb = new StringBuilder(s.length() + 16);
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            switch (c) {
            case ‘>‘:
                sb.append(‘>‘);// 全角大于号
                break;
            case ‘<‘:
                sb.append(‘<‘);// 全角小于号
                break;
            case ‘\‘‘:
                sb.append(‘\\‘);
                sb.append(‘\‘‘);
                sb.append(‘\\‘);
                sb.append(‘\‘‘);
                break;
            case ‘\"‘:
                sb.append(‘\\‘);
                sb.append(‘\"‘);// 全角双引号
                break;
            case ‘&‘:
                sb.append(‘&‘);// 全角
                break;
            case ‘\\‘:
                sb.append(‘\‘);// 全角斜线
                break;
            case ‘#‘:
                sb.append(‘#‘);// 全角井号
                break;
            case ‘:‘:
                sb.append(‘:‘);// 全角冒号
                break;
            case ‘%‘:
                sb.append("\\\\%");
                break;
            default:
                sb.append(c);
                break;
            }
        }
        return sb.toString();
    }



当然,还有如下更简单的方式:

技术分享 程序代码
private String cleanXSS(String value) {
         //You‘ll need to remove the spaces from the html entities below
        value = http://www.mamicode.com/value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
        value = http://www.mamicode.com/value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
        value = http://www.mamicode.com/value.replaceAll("‘", "& #39;");
        value = http://www.mamicode.com/value.replaceAll("eval\\((.*)\\)", "");
        value = http://www.mamicode.com/value.replaceAll("[\\\"\\\‘][\\s]*javascript:(.*)[\\\"\\\‘]", "\"\"");
        value = http://www.mamicode.com/value.replaceAll("script", "");
        return value;
    }


在后台或者用spring 如何实现呢:
首先添加一个jar包:commons-lang-2.5.jar ,然后在后台调用这些函数:

技术分享 程序代码
StringEscapeUtils.escapeHtml(string); 
StringEscapeUtils.escapeJavaScript(string); 
StringEscapeUtils.escapeSql(string);
 

当然,我记得在spring 里面好像有一个 HtmlUtils.htmlEscape , 同样可以做到 过滤 XSS 攻击。从上面的介绍可以看出,防止 XSS 攻击并不难,就是要小心。

跨站脚本漏洞