• Java对类进行XSS过滤


    Jackson对返回数据进行XSS过滤

    定义一个类继承ObjectMapper

    package demo;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.Version;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    import org.springframework.web.util.HtmlUtils;
    
    import java.io.IOException;
    
    public class CustomObjectMapper extends ObjectMapper {
        private static final long serialVersionUID = -3448961813323784217L;
    
        public CustomObjectMapper() {
            SimpleModule module = new SimpleModule("HTML XSS Serializer",
                    new Version(1, 0, 0, "FINAL","com.yihaomen","ep-jsonmodule"));
            module.addSerializer(new JsonHtmlXssSerializer(String.class));
            this.registerModule(module);
        }
    
        class JsonHtmlXssSerializer extends JsonSerializer<String> {
    
            public JsonHtmlXssSerializer(Class<String> string) {
                super();
            }
    
            @Override
            public Class<String> handledType() {
                return String.class;
            }
    
            @Override
            public void serialize(String value, JsonGenerator jsonGenerator,
                                  SerializerProvider serializerProvider) throws IOException,
                    JsonProcessingException {
                if (value != null) {
                    String encodedValue = HtmlUtils.htmlEscape(value.toString());
                    jsonGenerator.writeString(encodedValue);
                }
            }
        }
    }  
    

    在Spring配置文件中进行配置

    <mvc:annotation-driven>
        <mvc:message-converters>
            <bean
                class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>application/json;charset=UTF-8</value>
                        <value>text/html;charset=UTF-8</value>
                    </list>
                </property>
                <property name="objectMapper">
                    <bean class="demo.CustomObjectMapper" />
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    

    添加测试Controller,验证上面配置是否成功

    @RequestMapping("/testXSS")
    @ResponseBody
    public UserDTO testXSS() {
        UserDTO userDTO = new UserDTO();
        userDTO.setFullName("<script>alert(1)</script>");
        return userDTO;
    }
    

    用Postman测试接口,可以看到,fullName字段的数据已经过html编码过滤了

    以上是对jackson返回数据进行xss过滤的配置,下面是我自己通过java代码实现的一种方法

    JAVA反射实现XSS过滤

    package demo;
    
    import org.apache.commons.lang.StringUtils;
    import org.springframework.web.util.HtmlUtils;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * @author zhangkun
     * @date 2020/3/10 11:34
     */
    public class XssUtil {
        public static void xssObject(Object obj) {
            // 获取返回对象类所有字段
            List<Field> fields = new ArrayList<>(Arrays.asList(obj.getClass().getDeclaredFields()));
            // 获取返回对象的父类的所有字段,(如果有的话,根据自己情况删减)
            List<Field> parentFields = new ArrayList<>(Arrays.asList(obj.getClass().getSuperclass().getDeclaredFields()));
            // 合并父类字段和本类字段(如果有的话,根据自己情况删减)
            fields.addAll(parentFields);
    
            // 维护一个以转义的名单列表,避免同一字段重复被转义,因为父类和子类可能存在相同的字段名(没有父类的情况可删减)
            List<String> nameList = new ArrayList<>();
            
            for (Field field : fields) { //遍历所有属性
                String type = field.getGenericType().getTypeName();
                String name = field.getName(); //获取属性的名字
                if (type.equals(String.class.getTypeName()) && !nameList.contains(name)) {
                    // 如果使用到了这个字段,则添加到名单中,以免下次重复被使用
                    nameList.add(name);
                    
                    // 根据javaBean规范,set或get方法字段的首字母大写
                    name = name.substring(0, 1).toUpperCase() + name.substring(1);
    
                    Method getMethod = null;
                    Method setMethod = null;
                    try {
                        // 获取本类的get、set方法
                        getMethod = obj.getClass().getMethod("get" + name);
                        setMethod = obj.getClass().getMethod("set" + name, new Class[]{String.class});
                    } catch (NoSuchMethodException e) {
                        try {
                            // 如果没有获取到则去父类获取(如果有的话,根据自己情况删减)
                            getMethod = obj.getClass().getSuperclass().getMethod("get" + name);
                            setMethod = obj.getClass().getSuperclass().getMethod("set" + name, new Class[]{String.class});
                        } catch (NoSuchMethodException e1) {
                        }
                    }
    				
                    if (getMethod != null && setMethod != null) {
                        String value = null;
                        try { 
                            // 通过get方法获取到值
                            String value = (String) getMethod.invoke(obj);
                            if (StringUtils.isBlank(value)) {
                                continue;
                            }
                            // 对字段进行html编码,然后通过set方法再塞回去
                            String s = HtmlUtils.htmlEscape(value);
                            setMethod.invoke(obj, s);
                        } catch (IllegalAccessException | InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    

    测试Controller

    @RequestMapping("/testXSS")
    @ResponseBody
    public UserDTO testXSS() {
        UserDTO userDTO = new UserDTO();
        userDTO.setFullName("<script>alert("佛山馆所属管'")</script>");
        // 使用我自己写的XSS过滤工具类
        XssUtil.xssObject(userDTO);
        return userDTO;
    }
    

    Postman测试返回结果

    大功告成!

  • 相关阅读:
    ABP 菜单 修改
    C# 过滤器
    RabbitMQ框架构建系列(三)——Net实现RabbitMQ之Producer
    RabbitMQ系列(二)RabbitMQ基础介绍
    RabbitMQ系列(一)AMPQ协议
    MVC 解读WebConfig
    MVC过滤器特性
    asp.net中使用JQueryEasyUI
    asp.net请求到响应的整个过程
    Redis的下载安装部署(Windows)
  • 原文地址:https://www.cnblogs.com/dagger9527/p/12464029.html
Copyright © 2020-2023  润新知