@InitBinder与@RequestBody在Spring 3.2.4中转义XSS

nil*_*lsi 4 ajax spring spring-mvc spring-data

@RequestBody在我的方法中有一个带注释的参数,如下所示:

@RequestMapping(value = "/courses/{courseId}/{name}/comment", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public @ResponseBody CommentContainer addComment(@PathVariable Long courseId,
                          @ActiveAccount Account currentUser,
                          @Valid @RequestBody AddCommentForm form,
                          BindingResult formBinding,
                          HttpServletRequest request) throws RequestValidationException {

.....
}
Run Code Online (Sandbox Code Playgroud)

然后我@InitBinder在同一个控制器中有一个带注释的方法:

@InitBinder
public void initBinder(WebDataBinder dataBinder) {
    dataBinder.registerCustomEditor(AddCommentForm.class, new StringEscapeEditor());
}
Run Code Online (Sandbox Code Playgroud)

StringEscapeEditor没跑.但我的initBinder方法是.所以它没有将我的表单映射到转义编辑器.这似乎是在阅读此线程后(似乎@RequestMapping不支持@InitBinder):

处理ajax请求时不调用spring mvc @InitBinder

我测试了映射@PathVariable字符串,然后我的编辑器正在工作.

这在我的应用程序中是一个大问题,因为我的大多数绑定都已完成,@RequestBody如果我可以应用一些自定义绑定,那将是很好的.

解决这个问题最常用的方法是什么?并且为了脚本攻击而逃避我的输入数据.

Kre*_*sek 7

为了逃避XSS,我建议在输出数据时进行转义,因为正确的转义取决于输出文档.

如果生成的JSON响应由@ResponseBody客户端直接使用,并且没有机会让XSS转义内容,则可以自定义JacksonMessageConverter以对字符串执行XSS转义.

可以像这样自定义JacksonMessageConverter:

1)首先我们创建ObjectMapper工厂,它将创建我们的自定义对象映射器:

public class HtmlEscapingObjectMapperFactory implements FactoryBean<ObjectMapper> {

    private final ObjectMapper objectMapper;

    public HtmlEscapingObjectMapperFactory() {
        objectMapper = new ObjectMapper();
        objectMapper.getJsonFactory().setCharacterEscapes(new HTMLCharacterEscapes());
    }

    @Override
    public ObjectMapper getObject() throws Exception {
        return objectMapper;
    }

    @Override
    public Class<?> getObjectType() {
        return ObjectMapper.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public static class HTMLCharacterEscapes extends CharacterEscapes {

        private final int[] asciiEscapes;

        public HTMLCharacterEscapes() {
            // start with set of characters known to require escaping (double-quote, backslash etc)
            asciiEscapes = CharacterEscapes.standardAsciiEscapesForJSON();
            // and force escaping of a few others:
            asciiEscapes['<'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['>'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['&'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['"'] = CharacterEscapes.ESCAPE_CUSTOM;
            asciiEscapes['\''] = CharacterEscapes.ESCAPE_CUSTOM;
        }


        @Override
        public int[] getEscapeCodesForAscii() {
            return asciiEscapes;
        }

        // and this for others; we don't need anything special here
        @Override
        public SerializableString getEscapeSequence(int ch) {
            return new SerializedString(StringEscapeUtils.escapeHtml4(Character.toString((char) ch)));

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(HtmlCharacterEscapes的灵感来自于这个问题:使用Spring MVC和Jackson Mapper进行HTML转义)

2)然后我们注册使用我们的自定义对象映射器的消息转换器(xml配置中的示例):

<bean id="htmlEscapingObjectMapper" class="com.example.HtmlEscapingObjectMapperFactory" />

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" p:objectMapper-ref="htmlEscapingObjectMapper" />
    </mvc:message-converters>
</mvc:annotation-driven>
Run Code Online (Sandbox Code Playgroud)

现在,所有创建的JSON消息@ResponseBody都应该按照HTMLCharacterEscapes中的指定转义字符串.

该问题的替代解决方案:

  • 在反序列化对象后,XSS将在控制器主体中转义所需的内容
  • 也许XSS在输出内容之前在客户端的javascript中转义

除了执行输出转义之外,还可以使用一些输入验证(使用标准的Spring验证方法)来阻止您不希望输入系统/数据库的一些内容.

编辑:JavaConfig

我没有试过这个,但是在Java配置中它应该像这样工作(你不需要上面的Factory Bean,因为在这种情况下你可以在config中设置所有内容):

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    super.configureMessageConverters(converters);
    converters.add(buildHtmlEscapingJsonConverter());

}

private MappingJacksonHttpMessageConverter buildHtmlEscapingJsonConverter() {
    MappingJacksonHttpMessageConverter htmlEscapingConverter = new MappingJacksonHttpMessageConverter();
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.getJsonFactory().setCharacterEscapes(new HTMLCharacterEscapes());
    htmlEscapingConverter.setObjectMapper(objectMapper);
    return htmlEscapingConverter;       
}
Run Code Online (Sandbox Code Playgroud)

请注意,通常配置的任何其他非json默认消息转换器现在都将丢失(例如XML转换器等).如果您需要它们,您需要手动添加它们(您可以看到默认情况下处于活动状态)这里在2.2节:http://www.baeldung.com/spring-httpmessageconverter-rest)