如何防止人们在 Spring MVC 中进行 XSS?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2147958/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I prevent people from doing XSS in Spring MVC?
提问by Doug
What should I do to prevent XSS in Spring MVC? Right now I am just putting all places where I output user text into JSTL <c:out>tags or fn:escapeXml()functions, but this seems error prone as I might miss a place.
我应该怎么做才能防止 Spring MVC 中的 XSS?现在,我只是将输出用户文本的所有位置都放入 JSTL<c:out>标记或fn:escapeXml()函数中,但这似乎很容易出错,因为我可能会错过某个位置。
Is there an easy systematic way to prevent this? Maybe like a filter or something? I'm collecting input by specifying @RequestParamparameters on my controller methods.
有没有一种简单的系统方法来防止这种情况发生?也许像过滤器之类的?我通过@RequestParam在我的控制器方法上指定参数来收集输入。
回答by Tendayi Mawushe
In Spring you can escape the html from JSP pages generated by <form>tags. This closes off a lot avenues for XSS attacks, and can be done automatically in three ways:
在 Spring 中,您可以从<form>标记生成的 JSP 页面中转义 html 。这关闭了 XSS 攻击的很多途径,并且可以通过三种方式自动完成:
For the entire application in the web.xmlfile:
对于web.xml文件中的整个应用程序:
<context-param>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
For all forms on a given page in the file itself:
对于文件本身给定页面上的所有表单:
<spring:htmlEscape defaultHtmlEscape="true" />
For each form:
对于每个表格:
<form:input path="someFormField" htmlEscape="true" />
回答by Grigory Kislin
I use Hibernate Validator via @Validfor all input objects (binding and @RequestBodyjson, see https://dzone.com/articles/spring-31-valid-requestbody). So @org.hibernate.validator.constraints.SafeHtmlis a good solution for me.
我将 Hibernate Validator via@Valid用于所有输入对象(绑定和@RequestBodyjson,请参阅https://dzone.com/articles/spring-31-valid-requestbody)。所以@org.hibernate.validator.constraints.SafeHtml对我来说是一个很好的解决方案。
Hibernate SafeHtmlValidatordepends on org.jsoup, so it's needed to add one more project dependencies:
HibernateSafeHtmlValidator依赖于org.jsoup,因此需要再添加一个项目依赖项:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.1</version>
</dependency>
For bean Userwith field
对于User带字段的bean
@NotEmpty
@SafeHtml
protected String name;
for update attempt with value <script>alert(123)</script>in controller
使用<script>alert(123)</script>控制器中的值进行更新尝试
@PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
public void update(@Valid @RequestBody User user, @PathVariable("id") int id)
or
或者
@PostMapping
public void createOrUpdate(@Valid User user) {
is thrown BindExceptionfor binding and MethodArgumentNotValidExceptionfor @RequestBodywith default message:
是抛出BindException了约束力,MethodArgumentNotValidException对@RequestBody与缺省的消息:
name may have unsafe html content
Validator works as well for binding, as before persisting. Apps could be tested at http://topjava.herokuapp.com/
与持久化之前一样,验证器也适用于绑定。可以在http://topjava.herokuapp.com/测试应用程序
UPDATE: see also comment from @GuyT
更新:另见@GuyT 的评论
CVE-2019-10219 and status of @SafeHtml
We have been made aware of a CVE-2019-10219 related to the @SafeHtml constraint and it was fixed in both 6.0.18.Final and 6.1.0.Final....
However, we came to the conclusion that the @SafeHtml constraint was fragile, highly security-sensitive and depending on an external library that wasn't designed for this purpose. Having it included in core Hibernate Validator was not a very good idea. That's why we deprecated it and marked it for removal.There is no magic plan here so our users will have to maintain this constraint themselves
我们已经注意到与 @SafeHtml 约束相关的 CVE-2019-10219,它在 6.0.18.Final 和 6.1.0.Final 中均已修复....
然而,我们得出的结论是,@SafeHtml 约束是脆弱的、高度安全敏感的,并且依赖于不是为此目的而设计的外部库。将它包含在核心 Hibernate Validator 中并不是一个好主意。这就是我们弃用它并将其标记为删除的原因。这里没有神奇的计划,所以我们的用户必须自己维护这个约束
Resume for myself: it is safe and could be used, until solution better be found.
个人简历:它是安全的,可以使用,直到找到更好的解决方案。
回答by Erlend
When you are trying to prevent XSS, it's important to think of the context. As an example how and what to escape is very different if you are ouputting data inside a variable in a javascript snippet as opposed to outputting data in an HTML tag or an HTML attribute.
当您试图阻止 XSS 时,考虑上下文很重要。例如,如果您在 javascript 片段中的变量中输出数据,而不是在 HTML 标记或 HTML 属性中输出数据,则如何转义以及转义内容是非常不同的。
I have an example of this here: http://erlend.oftedal.no/blog/?blogid=91
我在这里有一个例子:http: //erlend.oftedal.no/blog/?blogid=91
Also checkout the OWASP XSS Prevention Cheat Sheet: http://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
另请查看OWASP XSS 预防备忘单:http: //www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
So the short answer is, make sure you escape output like suggested by Tendayi Mawushe, but take special care when you are outputting data in HTML attributes or javascript.
所以简短的回答是,确保你像 Tendayi Mawushe 建议的那样转义输出,但是当你在 HTML 属性或 javascript 中输出数据时要特别小心。
回答by rjha
Instead of relying only on <c:out />, an antixss library should also be used, which will not only encode but also sanitize malicious script in input. One of the best library available is OWASP Antisamy, it's highly flexible and can be configured(using xml policy files) as per requirement.
而不是仅仅依赖于<c:out />,还应该使用 antixss 库,它不仅可以编码而且可以清理输入中的恶意脚本。可用的最好的库之一是 OWASP Antisamy,它非常灵活,可以根据需要进行配置(使用 xml 策略文件)。
For e.g. if an application supports only text input then most generic policy fileprovided by OWASP can be used which sanitizes and removes most of the html tags. Similarly if application support html editors(such as tinymce) which need all kind of html tags, a more flexible policy can be use such as ebay policy file
例如,如果应用程序仅支持文本输入,则可以使用 OWASP 提供的大多数通用策略文件,它可以清理和删除大部分 html 标签。同样,如果应用程序支持需要各种 html 标签的 html 编辑器(例如 tinymce),则可以使用更灵活的策略,例如ebay 策略文件
回答by GAURAV KUMAR GUPTA
**To avoid XSS security threat in spring application**
solution to the XSS issue is to filter all the textfields in the form at the time of submitting the form.
XSS 问题的解决方案是在提交表单时过滤表单中的所有文本字段。
It needs XML entry in the web.xml file & two simple classes.
java code :-
The code for the first class named CrossScriptingFilter.java is :
package com.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.log4j.Logger;
public class CrossScriptingFilter implements Filter {
private static Logger logger = Logger.getLogger(CrossScriptingFilter.class);
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.info("Inlter CrossScriptingFilter ...............");
chain.doFilter(new RequestWrapper((HttpServletRequest) request), response);
logger.info("Outlter CrossScriptingFilter ...............");
}
}
The code second class named RequestWrapper.java is :
名为 RequestWrapper.java 的第二类代码是:
package com.filter;
包 com.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.log4j.Logger;
public final class RequestWrapper extends HttpServletRequestWrapper {
private static Logger logger = Logger.getLogger(RequestWrapper.class);
public RequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String[] getParameterValues(String parameter) {
logger.info("InarameterValues .. parameter .......");
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
public String getParameter(String parameter) {
logger.info("Inarameter .. parameter .......");
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
logger.info("Inarameter RequestWrapper ........ value .......");
return cleanXSS(value);
}
public String getHeader(String name) {
logger.info("Ineader .. parameter .......");
String value = super.getHeader(name);
if (value == null)
return null;
logger.info("Ineader RequestWrapper ........... value ....");
return cleanXSS(value);
}
private String cleanXSS(String value) {
// You'll need to remove the spaces from the html entities below
logger.info("InnXSS RequestWrapper ..............." + value);
//value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
//value = value.replaceAll("\(", "& #40;").replaceAll("\)", "& #41;");
//value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\((.*)\)", "");
value = value.replaceAll("[\\"\\'][\s]*javascript:(.*)[\\"\\']", "\"\"");
value = value.replaceAll("(?i)<script.*?>.*?<script.*?>", "");
value = value.replaceAll("(?i)<script.*?>.*?</script.*?>", "");
value = value.replaceAll("(?i)<.*?javascript:.*?>.*?</.*?>", "");
value = value.replaceAll("(?i)<.*?\s+on.*?>.*?</.*?>", "");
//value = value.replaceAll("<script>", "");
//value = value.replaceAll("</script>", "");
logger.info("OutnXSS RequestWrapper ........ value ......." + value);
return value;
}
The only thing remained is the XML entry in the web.xml file:
唯一剩下的是 web.xml 文件中的 XML 条目:
<filter>
<filter-name>XSS</filter-name>
<display-name>XSS</display-name>
<description></description>
<filter-class>com.filter.CrossScriptingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>XSS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The /* indicates that for every request made from browser, it will call CrossScriptingFilter class. Which will parse all the components/elements came from the request & will replace all the javascript tags put by hacker with empty string i.e
/* 表示对于浏览器发出的每个请求,它将调用 CrossScriptingFilter 类。它将解析来自请求的所有组件/元素,并将用空字符串替换黑客放置的所有 javascript 标签,即
回答by Ben
How are you collecting user input in the first place? This question / answer may assist if you're using a FormController:
您首先如何收集用户输入?如果您使用的是FormController以下问题/答案可能会有所帮助:
回答by sibidiba
Always check manually the methods, tags you use, and make sure that they always escape (once) in the end. Frameworks have many bugs and differences in this aspect.
始终手动检查您使用的方法、标签,并确保它们最终总是转义(一次)。框架在这方面有许多错误和差异。
An overview: http://www.gablog.eu/online/node/91

