I am having a @RequestBody
annotated argument in my method like this:
我在我的方法中有一个@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 {
.....
}
Then I have a @InitBinder
annotated method in the same controller:
然后我在同一个控制器中有一个@InitBinder注释方法:
@InitBinder
public void initBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(AddCommentForm.class, new StringEscapeEditor());
}
My StringEscapeEditor
is not running. But my initBinder
method is. So it does not mapping my form to the escape editor. This seems right after reading this thread (Where it seems like @RequestMapping
is not supported by @InitBinder
):
我的StringEscapeEditor没有运行。但我的initBinder方法是。所以它没有将我的表单映射到转义编辑器。这似乎是在阅读此线程后(@InitBinder不支持@RequestMapping):
spring mvc @InitBinder is not called when processing ajax request
处理ajax请求时不调用spring mvc @InitBinder
And i tested to map a @PathVariable
string and then my editor is working.
我测试了映射@PathVariable字符串,然后我的编辑器工作。
This is a big deal in my application since most of my bindings is done with @RequestBody
and it would be great if i could apply some custom bindings to it.
这在我的应用程序中是一个大问题,因为我的大多数绑定都是使用@RequestBody完成的,如果我可以应用一些自定义绑定,那将会很棒。
What is the most common way to solve this problem? and to escape my input data for script attacks.
解决这个问题最常见的方法是什么?并且为了脚本攻击而逃避我的输入数据。
1 个解决方案
#1
7
To escape XSS I suggest that escaping is done while outputting the data, because correct escaping depends on the output document.
为了逃避XSS,我建议在输出数据时完成转义,因为正确的转义取决于输出文档。
If JSON response generated by @ResponseBody
is consumed directly by the client and there is no opportunity to XSS escape the content, then JacksonMessageConverter can be customised to perform XSS escaping on strings.
如果@ResponseBody生成的JSON响应由客户端直接使用,并且没有机会让XSS转义内容,则可以自定义JacksonMessageConverter以对字符串执行XSS转义。
One can customise JacksonMessageConverter like this:
可以像这样自定义JacksonMessageConverter:
1) First we create ObjectMapper factory that will create our custom object mapper:
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)));
}
}
}
(inspiration for HtmlCharacterEscapes came from this question: HTML escape with Spring MVC and Jackson Mapper)
(HtmlCharacterEscapes的灵感来自于这个问题:使用Spring MVC和Jackson Mapper进行HTML转义)
2) Then we register the message converter that uses our custom object mapper (example in xml config):
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>
Now all the JSON messages created by @ResponseBody
should have strings escaped as specified in HTMLCharacterEscapes.
现在,由@ResponseBody创建的所有JSON消息都应该按照HTMLCharacterEscapes中的指定转义字符串。
Alternative solutions to the problem:
该问题的替代解决方案:
- XSS escape what you need in the controller body after the objects have been deserialised
- maybe XSS escape in javascript on the client before outputting the content
在反序列化对象后,XSS将在控制器主体中转义所需的内容
也许XSS在输出内容之前在客户端的javascript中转义
In addition to doing output escaping, it may be useful to also do some input validation (using standard Spring validation methods) to block some of the content that you don't want to be entered into the system / database.
除了执行输出转义之外,还可以使用一些输入验证(使用标准的Spring验证方法)来阻止您不希望输入系统/数据库的一些内容。
EDIT: JavaConfig
I haven't tried this out but in Java config it should work like this (you won't need Factory Bean from above because you can set up everything in config in this case):
我没有尝试过这个,但是在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;
}
Please be aware that any other non-json default message converters that would normally be configured will now be lost (e.g. XML converters etc..) and if you need them, you will need to add them manually (you can see what's active by default here in section 2.2: http://www.baeldung.com/spring-httpmessageconverter-rest)
请注意,通常配置的任何其他非json默认消息转换器现在都将丢失(例如XML转换器等)。如果您需要它们,您需要手动添加它们(您可以看到默认情况下处于活动状态)这里在2.2节:http://www.baeldung.com/spring-httpmessageconverter-rest)
#1
7
To escape XSS I suggest that escaping is done while outputting the data, because correct escaping depends on the output document.
为了逃避XSS,我建议在输出数据时完成转义,因为正确的转义取决于输出文档。
If JSON response generated by @ResponseBody
is consumed directly by the client and there is no opportunity to XSS escape the content, then JacksonMessageConverter can be customised to perform XSS escaping on strings.
如果@ResponseBody生成的JSON响应由客户端直接使用,并且没有机会让XSS转义内容,则可以自定义JacksonMessageConverter以对字符串执行XSS转义。
One can customise JacksonMessageConverter like this:
可以像这样自定义JacksonMessageConverter:
1) First we create ObjectMapper factory that will create our custom object mapper:
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)));
}
}
}
(inspiration for HtmlCharacterEscapes came from this question: HTML escape with Spring MVC and Jackson Mapper)
(HtmlCharacterEscapes的灵感来自于这个问题:使用Spring MVC和Jackson Mapper进行HTML转义)
2) Then we register the message converter that uses our custom object mapper (example in xml config):
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>
Now all the JSON messages created by @ResponseBody
should have strings escaped as specified in HTMLCharacterEscapes.
现在,由@ResponseBody创建的所有JSON消息都应该按照HTMLCharacterEscapes中的指定转义字符串。
Alternative solutions to the problem:
该问题的替代解决方案:
- XSS escape what you need in the controller body after the objects have been deserialised
- maybe XSS escape in javascript on the client before outputting the content
在反序列化对象后,XSS将在控制器主体中转义所需的内容
也许XSS在输出内容之前在客户端的javascript中转义
In addition to doing output escaping, it may be useful to also do some input validation (using standard Spring validation methods) to block some of the content that you don't want to be entered into the system / database.
除了执行输出转义之外,还可以使用一些输入验证(使用标准的Spring验证方法)来阻止您不希望输入系统/数据库的一些内容。
EDIT: JavaConfig
I haven't tried this out but in Java config it should work like this (you won't need Factory Bean from above because you can set up everything in config in this case):
我没有尝试过这个,但是在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;
}
Please be aware that any other non-json default message converters that would normally be configured will now be lost (e.g. XML converters etc..) and if you need them, you will need to add them manually (you can see what's active by default here in section 2.2: http://www.baeldung.com/spring-httpmessageconverter-rest)
请注意,通常配置的任何其他非json默认消息转换器现在都将丢失(例如XML转换器等)。如果您需要它们,您需要手动添加它们(您可以看到默认情况下处于活动状态)这里在2.2节:http://www.baeldung.com/spring-httpmessageconverter-rest)