Java 从 HttpServletRequestWrapper 覆盖 getInputStream 以在 JSON 中转义 HTML
Java Overide getInputStream from HttpServletRequestWrapper to escape HTML in JSON
我正在尝试覆盖 HttpServletRequestWrapper#getInputStream()。我正在尝试读取正文中的 JSON 并转义 HTML 标签以防止 XSS。我正在处理具有多个端点的大型应用程序。我正在使用 JacksonMapper 将 JASON 转换为 POJO,因此想在实际映射之前清理输入。我的代码看起来像
@Override
public ServletInputStream getInputStream() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> jsonMap = mapper.readValue(super.getInputStream(),
Map.class);
for (String key : jsonMap.keySet()) {
if (jsonMap.get(key) != null) {
if (jsonMap.get(key).getClass() == String.class)
jsonMap.put(key, (Object) StringEscapeUtils.escapeHtml((String) jsonMap.get(key)));
}
}
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
mapper.writeValue(out, jsonMap);
final ByteArrayInputStream byteIn = new ByteArrayInputStream(
byteOut.toByteArray());
ServletInputStream inputStream = new ServletInputStream() {
@Override
public int read() throws IOException {
return byteIn.read();
}
};
return inputStream;
}
我收到如下 Jackson 映射异常:
8:29:20,323 WARN [org.jboss.resteasy.core.SynchronousDispatcher] (http-/0.0.0.0:7080-7) Failed executing PUT /portal/api/tenant/2: org.jboss.resteasy.spi.ReaderException:
org.codehaus.jackson.JsonParseException: Unexpected character ('¬' (code 172)):
expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: com.dell.em.controller.RequestWrapper@4ed35486; line: 1, column: 2]
at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:202) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:136) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:159) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:269) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:227) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
我不确定字符来自哪里。我有一个简单的 json 作为输入:
{"id":2,"tenantName":"Test","tenantLogo":null,"address1":"<script>alert(\"o1\")</script>","city":"test","state":"Alabama","zip":"78769","country":"United States","timezone":"US/Central","contactFirstName":"Test","contactLastName":"Test","contactEmail":"Test@rest.com","contactPhone":"9794444444","address2":null,"domainName":null}
以防有人遇到同样的问题。我必须对新的 InputStream 进行编码,而不是 writeVAlue 我需要 writeValueAsString 来在 json.
周围加上引号
@Override
public ServletInputStream getInputStream() throws IOException {
ObjectMapper mapper = new ObjectMapper();
InputStream in = super.getInputStream();
Map<String, Object> jsonMap = mapper.readValue(in, Map.class);
for (String key : jsonMap.keySet()) {
if (jsonMap.get(key) != null) {
if (jsonMap.get(key).getClass() == String.class)
jsonMap.put(key, (Object) StringEscapeUtils
.escapeHtml((String) jsonMap.get(key)));
}
}
final ByteArrayInputStream byteIn = new ByteArrayInputStream(Charset
.forName("UTF-16").encode(mapper.writeValueAsString(jsonMap))
.array());
ServletInputStream inputStream = new ServletInputStream() {
@Override
public int read() throws IOException {
return byteIn.read();
}
};
return inputStream;
}
我已经修改了@Rahul Dhar 的解决方案以适合我的情况,因为我有几个休息服务接受常规输入以及 json 输入(比如接受正文作为用户的 ID )
@Override
public ServletInputStream getInputStream() throws IOException {
ObjectMapper mapper = new ObjectMapper();
InputStream in = super.getInputStream();
String inputString = IOUtils.toString(in, "utf-8");
if (inputString.contains("{")) { // is JSON
@SuppressWarnings("unchecked")
Map<String, Object> jsonMap = mapper.readValue(inputString, Map.class);
for (String key : jsonMap.keySet()) {
Object value = jsonMap.get(key);
if (value != null) {
if (value.getClass() == String.class)
jsonMap.put(key, (Object) stripXSS((String) value)); // (stripXSS is a private method that do spit out xss characters)
}
}
return new CustomServletInputStream(
Charset.forName("utf-8").encode(mapper.writeValueAsString(jsonMap)).array());
} else {
return new CustomServletInputStream(Charset.forName("utf-8").encode(inputString).array());
}
}
我正在尝试覆盖 HttpServletRequestWrapper#getInputStream()。我正在尝试读取正文中的 JSON 并转义 HTML 标签以防止 XSS。我正在处理具有多个端点的大型应用程序。我正在使用 JacksonMapper 将 JASON 转换为 POJO,因此想在实际映射之前清理输入。我的代码看起来像
@Override
public ServletInputStream getInputStream() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> jsonMap = mapper.readValue(super.getInputStream(),
Map.class);
for (String key : jsonMap.keySet()) {
if (jsonMap.get(key) != null) {
if (jsonMap.get(key).getClass() == String.class)
jsonMap.put(key, (Object) StringEscapeUtils.escapeHtml((String) jsonMap.get(key)));
}
}
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
mapper.writeValue(out, jsonMap);
final ByteArrayInputStream byteIn = new ByteArrayInputStream(
byteOut.toByteArray());
ServletInputStream inputStream = new ServletInputStream() {
@Override
public int read() throws IOException {
return byteIn.read();
}
};
return inputStream;
}
我收到如下 Jackson 映射异常:
8:29:20,323 WARN [org.jboss.resteasy.core.SynchronousDispatcher] (http-/0.0.0.0:7080-7) Failed executing PUT /portal/api/tenant/2: org.jboss.resteasy.spi.ReaderException:
org.codehaus.jackson.JsonParseException: Unexpected character ('¬' (code 172)):
expected a valid value (number, String, array, object, 'true', 'false' or 'null')
at [Source: com.dell.em.controller.RequestWrapper@4ed35486; line: 1, column: 2]
at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:202) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:136) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:159) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.ResourceMethod.invokeOnTarget(ResourceMethod.java:269) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
at org.jboss.resteasy.core.ResourceMethod.invoke(ResourceMethod.java:227) [resteasy-jaxrs-2.3.6.Final-redhat-1.jar:2.3.6.Final-redhat-1]
我不确定字符来自哪里。我有一个简单的 json 作为输入:
{"id":2,"tenantName":"Test","tenantLogo":null,"address1":"<script>alert(\"o1\")</script>","city":"test","state":"Alabama","zip":"78769","country":"United States","timezone":"US/Central","contactFirstName":"Test","contactLastName":"Test","contactEmail":"Test@rest.com","contactPhone":"9794444444","address2":null,"domainName":null}
以防有人遇到同样的问题。我必须对新的 InputStream 进行编码,而不是 writeVAlue 我需要 writeValueAsString 来在 json.
周围加上引号@Override
public ServletInputStream getInputStream() throws IOException {
ObjectMapper mapper = new ObjectMapper();
InputStream in = super.getInputStream();
Map<String, Object> jsonMap = mapper.readValue(in, Map.class);
for (String key : jsonMap.keySet()) {
if (jsonMap.get(key) != null) {
if (jsonMap.get(key).getClass() == String.class)
jsonMap.put(key, (Object) StringEscapeUtils
.escapeHtml((String) jsonMap.get(key)));
}
}
final ByteArrayInputStream byteIn = new ByteArrayInputStream(Charset
.forName("UTF-16").encode(mapper.writeValueAsString(jsonMap))
.array());
ServletInputStream inputStream = new ServletInputStream() {
@Override
public int read() throws IOException {
return byteIn.read();
}
};
return inputStream;
}
我已经修改了@Rahul Dhar 的解决方案以适合我的情况,因为我有几个休息服务接受常规输入以及 json 输入(比如接受正文作为用户的 ID )
@Override
public ServletInputStream getInputStream() throws IOException {
ObjectMapper mapper = new ObjectMapper();
InputStream in = super.getInputStream();
String inputString = IOUtils.toString(in, "utf-8");
if (inputString.contains("{")) { // is JSON
@SuppressWarnings("unchecked")
Map<String, Object> jsonMap = mapper.readValue(inputString, Map.class);
for (String key : jsonMap.keySet()) {
Object value = jsonMap.get(key);
if (value != null) {
if (value.getClass() == String.class)
jsonMap.put(key, (Object) stripXSS((String) value)); // (stripXSS is a private method that do spit out xss characters)
}
}
return new CustomServletInputStream(
Charset.forName("utf-8").encode(mapper.writeValueAsString(jsonMap)).array());
} else {
return new CustomServletInputStream(Charset.forName("utf-8").encode(inputString).array());
}
}