[JavaWeb]_[初级]_[对Html特殊符号进行转义防止XSS攻击和反转义]

Posted infoworld

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JavaWeb]_[初级]_[对Html特殊符号进行转义防止XSS攻击和反转义]相关的知识,希望对你有一定的参考价值。

场景

  1. 在开发Java Web程序时,为了防止XSSjavascript攻击, 需要对用户输入转义,使JavaScript脚本不能执行. 在前端可以通过获取<div>innerhtml属性来获取转义内容,但是在服务端如何进行转义?因为客户端是可以绕过的.

说明

  1. HTML内容的转义在开发Web时肯定是必须做的,在入数据库之前得转义,而不是在用的时候再转义。主要是防止在使用这类数据的时候忘记没有转义导致的XSS安全问题.

  2. 转义HTML字符主要涉及到5个字符<>"'&,所以只需要转义这几个即可。要实现转义字符,最基本的做法就是通过逐个分析String里的字符,之后使用转移字符串替换. 看htmlEscape1()方法即是最基本的做法。而另一种做法就是使用htmlEscape2(),它之前讲过的使用正则高效替换字符串的多个占位符为多个值[3]. 这两种方法在进行测试执行时间的时候方法1更快,可见正则匹配更耗费时间。

输出

package com.example.string;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.jupiter.api.Test;

public class HtmlEscapeTest{
    
    public static String htmlEscape1(String str) {

        if(isEmpty(str))
            return str;

        StringBuilder w = new StringBuilder();
        for (int i = 0, len = str.length(); i < len; i++) {
            char cur = str.charAt(i);
            switch (cur) {
                case '<':
                    w.append("&lt;");
                    break;
                case '>':
                    w.append("&gt;");
                    break;
                case '"':
                    w.append("&quot;");
                    break;
                case '\\'':
                    w.append("&#39;");
                    break;
                case '&':
                    w.append("&amp;");
                    break;
                default:
                    w.append(cur);
                    break;
            }
        }
        return w.toString();
    }

    private static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }

    /**
     *
     * StringBuilder sb = new StringBuilder();
     * HashMap<String, String> oldToNew = new HashMap<>();
     * oldToNew.put("$sn",sn);
     * oldToNew.put("$email",mail);
     * StringUtils.replaceOneMore(sb,registertemplate,"[$]sn|[$]email",oldToNew);
     *
     * @param output
     * @param input
     * @param oldRegex
     * @param oldToNew
     */
    public static void replaceOneMore(StringBuilder output, String input,
                                      String oldRegex, Map<String,String> oldToNew){
        Pattern p = Pattern.compile(oldRegex);
        Matcher m = p.matcher(input);

        while (m.find()) {
            String one = m.group();
            if(oldToNew.containsKey(one))
                m.appendReplacement(output, oldToNew.get(one));
        }
        m.appendTail(output);
    }

    public static String htmlEscape2(String source){
        if(isEmpty(source))
            return source;

        StringBuilder builder = new StringBuilder();
        HashMap<String, String> oldToNew = new HashMap<>();
        oldToNew.put("<","&lt;");
        oldToNew.put(">","&gt;");
        oldToNew.put("\\"","&quot;");
        oldToNew.put("'","&#39;");
        oldToNew.put("&","&amp;");
        long start2 = System.currentTimeMillis();
        replaceOneMore(builder,source,"[<]|[>]|[\\"]|[']|[&]",oldToNew);    
        long end2 = System.currentTimeMillis();
        print("replaceOneMore",end2-start2);
        return builder.toString();    
    }

    public static String htmlUnescape(String str){
        if(isEmpty(str))
            return str;

        if(str.indexOf("&") == -1)
            return str;

        StringBuilder sb = new StringBuilder();
        HashMap<String, String> oldToNew = new HashMap<>();
        oldToNew.put("&lt;","<");
        oldToNew.put("&gt;",">");
        oldToNew.put("&quot;","\\"");
        oldToNew.put("&#39;","\\'");
        oldToNew.put("&amp;","&");
        replaceOneMore(sb,str,"[&]lt;|[&]gt;|[&]quot;|[&]#39;|[&]amp;",oldToNew);
        return sb.toString();  
    }

    public static<T> void print(String key,T t){
        System.out.println(key +" : "+t);
    }

    @Test
    public void testEscapeHtml(){
        String str = "<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&"
        +"<a href=\\"http://blog.csdn.net/infoworld?name=tobey&year=2021\\"></a><script>alert('hello')</script>&";
        
        long start1 = System.currentTimeMillis();
        String result1 = htmlEscape1(str);
        long old1 = System.currentTimeMillis();

        print("result1",result1);
        print("duration",old1-start1);

        long start2 = System.currentTimeMillis();
        String result2 = htmlEscape2(str);
        long end2 = System.currentTimeMillis();
        print("result2",result2);
        print("duration",end2-start2);

        assertEquals(result2, result1);
        String source = htmlUnescape(result2);
        assertEquals(source, str);
        print("source",source);
    }
}

输出

result1 : &lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;
duration : 1
replaceOneMore : 8
result2 : &lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;&lt;a href=&quot;http://blog.csdn.net/infoworld?name=tobey&amp;year=2021&quot;&gt;&lt;/a&gt;&lt;script&gt;alert(&#39;hello&#39;)&lt;/script&gt;&amp;
duration : 8
source : <a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&<a href="http://blog.csdn.net/infoworld?name=tobey&year=2021"></a><script>alert('hello')</script>&

参考

  1. Java escape HTML - Stack Overflow

  2. Why to Encode (escape) Special Characters in HTML

  3. 使用正则高效替换字符串的多个占位符为多个值

以上是关于[JavaWeb]_[初级]_[对Html特殊符号进行转义防止XSS攻击和反转义]的主要内容,如果未能解决你的问题,请参考以下文章

[JavaWeb]_[初级]_[对Jfinal框架的Controller进行单元测试]

[JavaWeb]_[初级]_[对Jfinal框架的Controller进行单元测试]

[JavaWeb]_[初级]_[对Jfinal框架的Service层进行单元测试]

[JavaWeb]_[初级]_[对Jfinal框架的Service层进行单元测试]

[JavaWeb]_[初级]_[img标签的值为#时导致重复访问当前页面]

[JavaWeb]_[初级]_[img标签的值为#时导致重复访问当前页面]