如何使用 Java 防止 XSS 攻击或 Rest API JSON 中的不可信数据?
Posted
技术标签:
【中文标题】如何使用 Java 防止 XSS 攻击或 Rest API JSON 中的不可信数据?【英文标题】:How to prevent XSS attacks or untrusted data in Rest API JSON using Java? 【发布时间】:2020-03-14 13:59:27 【问题描述】:我开发了一个 Rest API 应用程序,并使用自定义 JWT 处理了身份验证和授权。 我想进一步使应用程序免受 XSS 攻击或验证不受信任的数据,这些数据可以针对 JSON 请求的每个字段进行处理。
我能否在这方面获得一些帮助,以便在请求的入门级进行有效的数据处理,而无需触及内部业务验证?
【问题讨论】:
【参考方案1】:您不会在 Restful API 中过滤或转义数据。 API 应该与客户端无关。提供 XSS 保护是客户的责任。如果客户正确地完成了他们的工作,您最终会得到双重转义的数据。请记住,潜在客户可以是:
移动应用 后端 Web 服务器 网络浏览器 桌面应用程序 嵌入式系统/物联网在上述情况下,只有有限数量的客户端和配置容易受到 XSS 攻击。
【讨论】:
【参考方案2】:需要覆盖 Servlet 过滤器中的 HttpServletRequest(如果您使用的是 Servlet)。
扩展存储 JSON 正文的 HttpServletRequestWrapper(目的是清理 JSON 正文)。
剥离/转义符合条件的 JSON 值
扩展的“HttpServletRequestWrapper”:
public class SanitizationRequestWrapper extends HttpServletRequestWrapper
public byte[] getBody()
return body;
public void setBody(byte[] body)
this.body = body;
private byte[] body;
public SanitizationRequestWrapper(HttpServletRequest request) throws IOException
super(request);
try
body = IOUtils.toByteArray(super.getInputStream());
catch (NullPointerException e)
@Override
public ServletInputStream getInputStream() throws IOException
return new ServletInputStreamImpl(new ByteArrayInputStream(body));
@Override
public BufferedReader getReader() throws IOException
String enc = getCharacterEncoding();
if (enc == null) enc = "UTF-8";
return new BufferedReader(new InputStreamReader(getInputStream(), enc));
private class ServletInputStreamImpl extends ServletInputStream
private InputStream is;
public ServletInputStreamImpl(InputStream is)
this.is = is;
public int read() throws IOException
return is.read();
public boolean markSupported()
return false;
public synchronized void mark(int i)
throw new RuntimeException(new IOException("mark/reset not supported"));
public synchronized void reset() throws IOException
throw new IOException("mark/reset not supported");
净化请求正文的 Servlet 过滤器:
public class XSSSanitizeFilters implements Filter
@Override
public void destroy()
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
SanitizationRequestWrapper sanitizeRequest = new SanitizationRequestWrapper(request);
if (null != sanitizeRequest.getBody())
try
sanitizeJson(sanitizeRequest);
catch (ParseException e)
LOG.error("Unable to Sanitize the provided JSON .");
arg2.doFilter(sanitizeRequest, arg1);
else
arg2.doFilter(arg0, arg1);
public void init(FilterConfig filterConfig) throws ServletException
private void sanitizeJson(SanitizationRequestWrapper sanitizeRequest ) throws IOException, ParseException
JSONParser parser= new JSONParser();
Object obj = parser.parse(sanitizeRequest.getReader());
ObjectMapper oMapper = new ObjectMapper();
Map <String, Object> map = oMapper.convertValue(obj, Map.class);
sanitizeRequest.setBody((new JSONObject(map)).toString().getBytes());
【讨论】:
感谢 Shantimoy!这非常适合我的要求。 "您需要覆盖 Servlet 过滤器中的 HttpServletRequest。" - 这个问题并不表明他们甚至在使用 servlet。 @JeffScottBrown:已更正!虽然示例使用的是servlet过滤器,但无论servlet如何,都可以使用“sanitizeJson()”方法。 @SHANTIMOYBANERJEE:这段代码非常适合我。我想了解正文中如何仍然存储请求正文流(json)。您已经使用了将引用传递给 HttpServletRequestWrapper 的 super(request)。一旦我们使用 IoUtils,它就会在内部调用 reader() 并且请求正文为空。所以在 SanitizationRequestWrapper 中,我们不应该有请求正文吗?当我们将新请求传递给 doFilter() 时,它是在内部使用在 SanitizationRequestWrapper 中创建的 body 属性,还是这里发生了其他事情? 如果 API 被提供自己的 XSS 清理或移动应用程序的 Web 服务器使用怎么办?这个问题专门针对 RESTful JSON API。你不应该为 XSS 清理输入或输出。【参考方案3】:如果您使用的是 Spring,Spring 安全性可以保证基本级别的 XSS 攻击保护。你也可以使用
@Safehtml
private String value;
您还需要添加 org.jsoup 依赖项。
【讨论】:
【参考方案4】:如果您的 API 不接受任何 HTML 字符,那么您可以遵循以下逻辑。
您可以使用 EncodeHtml 清理输入有效负载并将其与提供的有效负载进行比较。
如果 Sanitized Payload 和 Provided payload 不匹配,则存在一些 Html 内容,直接抛出异常。
String unsanitizedPayload = IOUtils.toString(multiReadRequest.getReader());
String sanitizedPayload = Encode.forHtmlContent(unsanitizedPayload);
if(!unsanitizedPayload.equals(sanitizedPayload))
throw new Exception("Improper Payload");
【讨论】:
【参考方案5】:为此,您需要使用 HTMLUtils 过滤 XSS 过滤器,该过滤器将过滤任何注入的脚本并阻止您的站点。完整的代码和实现请参考我的回答https://***.com/a/55741351/10232467。
【讨论】:
此解决方案适用于与请求标头一起传递的查询参数,但是我需要在 JSON 正文中的每个字段中删除相同的 PUT 或 POST 请求。以上是关于如何使用 Java 防止 XSS 攻击或 Rest API JSON 中的不可信数据?的主要内容,如果未能解决你的问题,请参考以下文章