java安全(二) --自编写字符串过滤-(防XSS攻击)

前言:

       最近项目中遇到很无语的XSS攻击问题,网上也有很多解决方案,一般也有用httponly来防止XSS拿到cookie的。

没办法,前端输入的数据都是不可信的数据,需要对传入后端的数据做处理,针对数据过滤,本着造轮子的原则,我写了一套过滤规则。可以过滤常见的XSS脚本。当然,如果想要完善的,可以使用springboot提供的XSS过滤。

 

简单一点上代码:

package com.information.student.utils;

import com.information.student.form.StudentInfoForm;


import java.lang.reflect.Field;

import java.lang.reflect.Method;
import java.util.*;

/**
 * @date 2018/11/13 
 * @author Gentle
 */
public class XssHandler {


    public static void main(String[] args) throws Exception {
        StudentInfoForm studentInfoForm = new StudentInfoForm();
        studentInfoForm.setSiIdcard("使用javascript脚本:" + "<scrpit>123</script>");
        studentInfoForm.setSiName("使用非法sql注入类字符:" + "#   %  <>");
        System.out.println(studentInfoForm.getSiIdcard());
        Object o = checkString(studentInfoForm);
        System.out.println(o);
        String[] a = new String[1];
        a[0]="<script>";
        checkString(a);
        System.out.println(a[0]);
    }

    /**
     * 校验数组,并且进行过滤
     * @param strings
     * @return
     */

    public static String[] checkString(String[] strings) {

        if (strings == null || strings.length <= 0) {
            throw new NullPointerException("传入数组不能为空");
        }
        for (int i = 0; i < strings.length; i++) {
            strings[i]=xssEncode(strings[i]);
        }
        return strings;
    }

    /**
     *  校验对象中String类型的字段。并且进行过滤
     * @param o
     * @return
     * @throws Exception
     */

    public static Object checkString(Object o) throws Exception {

        if (o instanceof Collection) {
            throw new RuntimeException("传入的类型有误,不能为集合类型");
        }

        Class<?> aClass = o.getClass();

        Field[] field = aClass.getDeclaredFields();
        List<String> list = new ArrayList();
        //找出所有String类型的字段
        for (Field field1 : field) {
            if (field1.getType().equals(String.class)) {
                list.add(field1.getName());
            }
        }
        for (int i = 0; i < list.size(); i++) {
            //获取get方法
            Method declaredMethod = aClass.getDeclaredMethod(getGetMethod(list.get(i)));
            //用get方法拿到属性值
            Object o1 = declaredMethod.invoke(o);
            //获得set方法。注入一般是字符串类型。所以写死String了
            Method declaredMethod1 = aClass.getDeclaredMethod(getSetMethod(list.get(i)), String.class);
            //用set方法将拿到的属性值进行过滤后放回
            declaredMethod1.invoke(o, new String[]{xssEncode(String.valueOf(o1))});
        }

        return o;
    }

    /**
     *  获得set方法。
     * @param key
     * @return
     * @throws Exception
     */
    private static String getSetMethod(String key) throws Exception {

        return "set" + Character.toUpperCase(key.charAt(0)) + key.substring(1);
    }

    private static String getGetMethod(String key) throws Exception {

        return "get" + Character.toUpperCase(key.charAt(0)) + key.substring(1);
    }


    /**
     * 将容易引起xss漏洞的半角字符直接替换成全角字符
     * @param s
     * @return
     */
    private static String xssEncode(String s) {
        if (s == null || s.isEmpty()) {
            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('‘');// 全角单引号
                    break;
                case '\"':
                    sb.append('“');// 全角双引号
                    break;
                case '&':
                    sb.append('&');// 全角
                    break;
                case '\\':
                    sb.append('\');// 全角斜线
                    break;
                case '#':
                    sb.append('#');// 全角井号
                    break;
                case '%':    // < 字符的 URL 编码形式表示的 ASCII 字符(十六进制格式) 是: %3c
                    processUrlEncoder(sb, s, i);
                    break;
                default:
                    sb.append(c);
                    break;
            }
        }
        return sb.toString();
    }

    public static void processUrlEncoder(StringBuilder sb, String s, int index) {
        if (s.length() >= index + 2) {
            if (s.charAt(index + 1) == '3' && (s.charAt(index + 2) == 'c' || s.charAt(index + 2) == 'C')) {    // %3c, %3C
                sb.append('<');
                return;
            }
            if (s.charAt(index + 1) == '6' && s.charAt(index + 2) == '0') {    // %3c (0x3c=60)
                sb.append('<');
                return;
            }
            if (s.charAt(index + 1) == '3' && (s.charAt(index + 2) == 'e' || s.charAt(index + 2) == 'E')) {    // %3e, %3E
                sb.append('>');
                return;
            }
            if (s.charAt(index + 1) == '6' && s.charAt(index + 2) == '2') {    // %3e (0x3e=62)
                sb.append('>');
                return;
            }
        }
        sb.append(s.charAt(index));
    }

}

用来被处理的对象:

package com.information.student.form;

import lombok.Data;

import java.util.Date;

/**
 * 学生信息表单
 * @author CCJ
 * @date 2018/11/10 17:38
 **/
@Data
public class StudentInfoForm {

    /** 学生姓名 **/
    private String siName;

    /** 学号 **/
    private String siNumber;

    /** 学生状态 **/
    private Integer siStatus;

    /** 学生身份证号码 **/
    private String siIdcard;

    /** 学生所属系别 **/
    private Integer siDept;

    /** 学生毕业时间 **/
    private Date siGraduationTime;


}

 

简单做一下测试:

 

      我们输入的<script> 字符串全部被转成圆角的。这样展示的就是就不会被浏览器认为是一个标签了。

 

总结:

       XSS攻击很烦,关键是还没有很好的防御方案。最好的也是给攻击者造成攻击麻烦,如果有毅力的攻击者一样可以攻击到,只不过是时间问题。我的技术有限,如果有好的方案,欢迎一起交流学习。

 

 

程序人生,与君共勉~!

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值