我应该怎么做才能阻止Spring MVC中的XSS?现在我只是将输出用户文本的所有地方放到JSTL <c:out>
标签或fn:escapeXml()
函数中,但这似乎很容易出错,因为我可能会错过一个地方。
有一种简单的系统方法可以防止这种情况发生吗?也许像过滤器或什么?我通过在控制器方法上指定@RequestParam
参数来收集输入。
答案 0 :(得分:53)
在Spring中,您可以从<form>
标记生成的JSP页面中转义html。这为XSS攻击提供了很多途径,可以通过三种方式自动完成:
对于web.xml
文件中的整个应用程序:
<context-param>
<param-name>defaultHtmlEscape</param-name>
<param-value>true</param-value>
</context-param>
对于文件本身中给定页面上的所有表单:
<spring:htmlEscape defaultHtmlEscape="true" />
每种表格:
<form:input path="someFormField" htmlEscape="true" />
答案 1 :(得分:8)
尝试XSSFilter。
答案 2 :(得分:7)
我通过@Valid
使用Hibernate Validator获取所有输入对象(绑定和@RequestBody
json,请参阅https://dzone.com/articles/spring-31-valid-requestbody)。所以@org.hibernate.validator.constraints.SafeHtml
对我来说是一个很好的解决方案。
Hibernate SafeHtmlValidator
取决于org.jsoup
,因此需要再添加一个项目依赖项:
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.1</version>
</dependency>
对于带有字段
的beanUser
@NotEmpty
@SafeHtml
protected String name;
在控制器中使用值<script>alert(123)</script>
进行更新尝试
@PutMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
public void update(@Valid @RequestBody User user, @PathVariable("id") int id)
或
@PostMapping
public void createOrUpdate(@Valid User user) {
用于绑定BindException
,MethodArgumentNotValidException
用@RequestBody
抛出默认消息:
name may have unsafe html content
Validator也适用于绑定,就像之前的持久化一样。 可以在http://topjava.herokuapp.com/
上测试应用答案 3 :(得分:6)
当您尝试阻止XSS时,考虑上下文非常重要。例如,如果您在javascript片段中输出变量中的数据而不是在HTML标记或HTML属性中输出数据,那么如何以及要逃避的内容就会大不相同。
我在这里有一个例子:http://erlend.oftedal.no/blog/?blogid=91
同时查看OWASP XSS预防备忘单:http://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet
所以简短的回答是,确保你像Tendayi Mawushe建议的那样逃避输出,但在输出HTML属性或javascript中的数据时要特别小心。
答案 4 :(得分:0)
您是如何首先收集用户输入的?如果您使用FormController
:
答案 5 :(得分:0)
始终手动检查您使用的方法,标签,并确保它们总是在最后逃逸(一次)。框架在这方面存在许多缺陷和差异。
答案 6 :(得分:0)
不应仅依赖于<c:out />
,还应使用反编译库,它不仅可以编码,还可以清理输入中的恶意脚本。可用的最好的库之一是OWASP Antisamy,它非常灵活,可以根据需要配置(使用xml策略文件)。
例如如果应用程序仅支持文本输入,则可以使用OWASP提供的大多数通用policy file来清理和删除大多数html标记。类似地,如果应用程序支持需要所有类型的html标记的html编辑器(例如tinymce),则可以使用更灵活的策略,例如ebay policy file
答案 7 :(得分:0)
library(dplyr)
library(ggplot2)
# use mtcars data set
data <- mtcars
# aggregate data by grouping variables
aggregate_data<- data%>%
group_by(gear,cyl, carb)%>%
summarize(mpg=mean(mpg))%>%
ungroup
# get total for gear
data_tot_cyl<- data%>%
group_by(cyl, carb)%>%
summarize(mpg=mean(mpg))%>%
ungroup%>%
mutate(gear='total')
# get total for cyl
data_tot_gear<- data%>%
group_by(gear, carb)%>%
summarize(mpg=mean(mpg))%>%
ungroup%>%
mutate(cyl='total')
# get total for total-total
data_tot_tot<- data%>%
group_by(carb)%>%
summarize(mpg=mean(mpg))%>%
ungroup%>%
mutate(cyl='total', gear='total')
# get data frame with all total's data.
new_data<-data_tot_tot%>%
bind_rows(data_tot_gear%>%mutate(gear=as.character(gear)))%>%
bind_rows(data_tot_cyl%>%mutate(cyl=as.character(cyl)))%>%
bind_rows(aggregate_data%>%mutate_at(vars(gear, cyl), funs(as.character)))
# Arghh, gotta order the levels so total is at the end.
new_data$cyl <- factor(new_data$cyl,
levels=c('4','6','8','total'),ordered=T)
new_data$gear <- factor(new_data$gear,
levels=c('3','4','5','total'),ordered=T)
# Finally after over 20 additional lines of code, I get the
# faceted plot with totals for x and y facets.
p<-ggplot(new_data, aes(x=carb, y=mpg))+
geom_bar(stat='identity')+
facet_grid(cyl~gear)+
geom_text(aes(label=round(mpg,1), y=0),
col='white', size=3,hjust=-0.3, angle=90)+
ggtitle('Average MPG vs Num Carbs, by Num Cylinders & Num Gears')
print(p)
XSS问题的解决方案是过滤表单中的所有文本字段 在提交表格时。
**To avoid XSS security threat in spring application**
名为RequestWrapper.java的代码第二类是:
package com.filter;
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 ...............");
}
}
唯一剩下的就是web.xml文件中的XML条目:
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;
}
/ *表示对于浏览器发出的每个请求,它都会调用 CrossScriptingFilter类。这将解析所有组件/元素来自请求&amp; 将用空字符串替换黑客提出的所有javascript标签,即