Java JSP/Servlet Web 应用程序中的 XSS 预防
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2658922/
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
XSS prevention in JSP/Servlet web application
提问by newbie
How can I prevent XSS attacks in a JSP/Servlet web application?
如何防止 JSP/Servlet Web 应用程序中的 XSS 攻击?
采纳答案by BalusC
XSS can be prevented in JSP by using JSTL<c:out>
tag or fn:escapeXml()
EL function when (re)displaying user-controlled input. This includes request parameters, headers, cookies, URL, body, etc. Anything which you extract from the request object. Also the user-controlled input from previous requests which is stored in a database needs to be escaped during redisplaying.
当(重新)显示用户控制的输入时,可以通过使用JSTL<c:out>
标记或fn:escapeXml()
EL 函数来防止 JSP 中的 XSS 。这包括请求参数、标头、cookie、URL、正文等。您从请求对象中提取的任何内容。此外,在重新显示期间,需要对存储在数据库中的先前请求的用户控制输入进行转义。
For example:
例如:
<p><c:out value="${bean.userControlledValue}"></p>
<p><input name="foo" value="${fn:escapeXml(param.foo)}"></p>
This will escape characters which may malform the rendered HTML such as <
, >
, "
, '
and &
into HTML/XML entitiessuch as <
, >
, "
, '
and &
.
这将逃脱这可能malform渲染HTML,如人物<
,>
,"
,'
和&
成HTML / XML实体,如<
,>
,"
,'
和&
。
Note that you don't need to escape them in the Java (Servlet) code, since they are harmless over there. Some may opt to escape them during requestprocessing (as you do in Servlet or Filter) instead of responseprocessing (as you do in JSP), but this way you may risk that the data unnecessarily get double-escaped (e.g. &
becomes &amp;
instead of &
and ultimately the enduser would see &
being presented), or that the DB-stored data becomes unportable (e.g. when exporting data to JSON, CSV, XLS, PDF, etc which doesn't require HTML-escaping at all). You'll also lose social control because you don't know anymore what the user has actually filled in. You'd as being a site admin really like to know which users/IPs are trying to perform XSS, so that you can easily track them and take actions accordingly. Escaping during request processing should only and only be used as latest resort when you really need to fix a train wreck of a badly developed legacy web application in the shortest time as possible. Still, you should ultimately rewrite your JSP files to become XSS-safe.
请注意,您不需要在 Java (Servlet) 代码中对它们进行转义,因为它们在那里是无害的。有些人可能会选择在请求处理期间(如在 Servlet 或 Filter 中所做的那样)而不是响应处理(如在 JSP 中所做的那样)对它们进行转义,但是这样您可能会冒着数据不必要地被双重转义的风险(例如&
变成&amp;
而不是&
和最终用户会看到&
被呈现),或者 DB 存储的数据变得不可移植(例如,将数据导出到 JSON、CSV、XLS、PDF 等时,根本不需要 HTML 转义)。您还将失去社交控制,因为您不再知道用户实际填写了什么。作为站点管理员,您真的很想知道哪些用户/IP 正在尝试执行 XSS,以便您可以轻松跟踪并采取相应的行动。当您确实需要在尽可能短的时间内修复严重开发的遗留 Web 应用程序的火车残骸时,应该并且仅将请求处理期间的转义用作最新的手段。尽管如此,您最终还是应该重写 JSP 文件以使其成为 XSS 安全的。
If you'd like to redisplay user-controlled input as HTML wherein you would like to allow only a specific subset of HTML tags like <b>
, <i>
, <u>
, etc, then you need to sanitize the input by a whitelist. You can use a HTML parser like Jsoupfor this. But, much better is to introduce a human friendly markup language such as Markdown (also used here on Stack Overflow). Then you can use a Markdown parser like CommonMarkfor this. It has also builtin HTML sanitizing capabilities. See also I'm looking for a Java HTML encoder.
如果你想重新显示用户控制输入为HTML,其中你想只允许HTML标签,如的特定子集<b>
,<i>
,<u>
,等等,那么你需要通过一个白名单来净化输入。为此,您可以使用像Jsoup这样的 HTML 解析器。但是,更好的是引入一种人类友好的标记语言,例如 Markdown(也在 Stack Overflow 上使用)。然后你可以使用像CommonMark这样的 Markdown 解析器。它还具有内置的 HTML 清理功能。另请参阅我正在寻找 Java HTML 编码器。
The only concern in the server side with regard to databases is SQL injectionprevention. You need to make sure that you never string-concatenate user-controlled input straight in the SQL or JPQL query and that you're using parameterized queries all the way. In JDBC terms, this means that you should use PreparedStatement
instead of Statement
. In JPA terms, use Query
.
服务器端与数据库相关的唯一问题是SQL 注入预防。您需要确保您永远不会直接在 SQL 或 JPQL 查询中字符串连接用户控制的输入,并且您一直在使用参数化查询。在 JDBC 术语中,这意味着您应该使用PreparedStatement
代替Statement
。在 JPA 术语中,使用Query
.
An alternative would be to migrate from JSP/Servlet to Java EE's MVC framework JSF. It has builtin XSS (and CSRF!) prevention over all place. See also CSRF, XSS and SQL Injection attack prevention in JSF.
另一种方法是从 JSP/Servlet 迁移到 Java EE 的 MVC 框架JSF。它在所有地方都有内置的 XSS(和 CSRF!)预防。另请参阅JSF 中的 CSRF、XSS 和 SQL 注入攻击预防。
回答by Sripathi Krishnan
The how-to-prevent-xss has been asked several times. You will find a lot of information in StackOverflow. Also, OWASP website has an XSS prevention cheat sheetthat you should go through.
已多次询问如何防止 xss。你会在 StackOverflow 中找到很多信息。此外,OWASP 网站有一个 XSS 预防备忘单,您应该仔细阅读。
On the libraries to use, OWASP's ESAPI libraryhas a java flavour. You should try that out. Besides that, every framework that you use has some protection against XSS. Again, OWASP website has information on most popular frameworks, so I would recommend going through their site.
在要使用的库上,OWASP 的 ESAPI 库具有 Java 风格。你应该试试看。除此之外,您使用的每个框架都有一些针对 XSS 的保护。同样,OWASP 网站有关于最流行框架的信息,所以我建议浏览他们的网站。
回答by Sean Reilly
I would suggest regularly testing for vulnerabilities using an automated tool, and fixing whatever it finds. It's a lot easier to suggest a library to help with a specific vulnerability then for all XSS attacks in general.
我建议使用自动化工具定期测试漏洞,并修复发现的任何漏洞。建议一个库来帮助解决特定的漏洞比一般的所有 XSS 攻击要容易得多。
Skipfishis an open source tool from Google that I've been investigating: it finds quite a lot of stuff, and seems worth using.
Skipfish是一个来自 Google 的开源工具,我一直在研究它:它发现了很多东西,而且似乎值得使用。
回答by Tom Hawtin - tackline
My personal opinion is that you should avoid using JSP/ASP/PHP/etc pages. Instead output to an API similar to SAX (only designed for calling rather than handling). That way there is a single layer that has to create well formed output.
我个人的意见是,你应该避免使用 JSP/ASP/PHP/etc 页面。而是输出到类似于 SAX 的 API(仅设计用于调用而不是处理)。这样就有一个单层必须创建格式良好的输出。
回答by Adam Gent
I had great luck with OWASP Anti-Samy and an AspectJ advisor on all my Spring Controllers that blocks XSS from getting in.
我很幸运使用 OWASP Anti-Samy 和 AspectJ 顾问在我的所有 Spring 控制器上阻止 XSS 进入。
public class UserInputSanitizer {
private static Policy policy;
private static AntiSamy antiSamy;
private static AntiSamy getAntiSamy() throws PolicyException {
if (antiSamy == null) {
policy = getPolicy("evocatus-default");
antiSamy = new AntiSamy();
}
return antiSamy;
}
public static String sanitize(String input) {
CleanResults cr;
try {
cr = getAntiSamy().scan(input, policy);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cr.getCleanHTML();
}
private static Policy getPolicy(String name) throws PolicyException {
Policy policy =
Policy.getInstance(Policy.class.getResourceAsStream("/META-INF/antisamy/" + name + ".xml"));
return policy;
}
}
You can get the AspectJ advisor from the this stackoverflow post
您可以从这个 stackoverflow 帖子中获取 AspectJ 顾问
I think this is a better approach then c:out particular if you do a lot of javascript.
我认为这是一种比 c:out 更好的方法,特别是如果你做了很多 javascript。
回答by brett.carr
There is no easy, out of the box solution against XSS. The OWASP ESAPI API has some support for the escaping that is very usefull, and they have tag libraries.
没有简单的、开箱即用的 XSS 解决方案。OWASP ESAPI API 有一些非常有用的转义支持,并且它们有标签库。
My approach was to basically to extend the stuts 2 tags in following ways.
我的方法基本上是通过以下方式扩展 stuts 2 标签。
- Modify s:property tag so it can take extra attributes stating what sort of escaping is required (escapeHtmlAttribute="true" etc.). This involves creating a new Property and PropertyTag classes. The Property class uses OWASP ESAPI api for the escaping.
- Change freemarker templates to use the new version of s:property and set the escaping.
- 修改 s:property 标签,以便它可以采用额外的属性来说明需要什么样的转义(escapeHtmlAttribute="true" 等)。这涉及创建新的 Property 和 PropertyTag 类。Property 类使用 OWASP ESAPI api 进行转义。
- 更改 freemarker 模板以使用新版本的 s:property 并设置转义。
If you didn't want to modify the classes in step 1, another approach would be to import the ESAPI tags into the freemarker templates and escape as needed. Then if you need to use a s:property tag in your JSP, wrap it with and ESAPI tag.
如果您不想修改步骤 1 中的类,另一种方法是将 ESAPI 标签导入 freemarker 模板并根据需要进行转义。然后如果你需要在你的 JSP 中使用 as:property 标签,用和 ESAPI 标签包装它。
I have written a more detailed explanation here.
我在这里写了更详细的解释。
http://www.nutshellsoftware.org/software/securing-struts-2-using-esapi-part-1-securing-outputs/
http://www.nutshellsoftware.org/software/securing-struts-2-using-esapi-part-1-securing-outputs/
I agree escaping inputs is not ideal.
我同意转义输入并不理想。
回答by Brad Parks
If you want to automatically escape allJSP variables without having to explicitly wrap each variable, you can use an EL resolver as detailed here with full source and an example (JSP 2.0 or newer), and discussed in more detail here:
如果您想自动转义所有JSP 变量而不必显式包装每个变量,您可以使用此处详细说明的 EL 解析器以及完整源代码和示例(JSP 2.0 或更新版本),并在此处进行更详细的讨论:
For example, by using the above mentioned EL resolver, your JSP code will remain like so, but each variable will be automatically escaped by the resolver
例如,通过使用上面提到的 EL 解析器,您的 JSP 代码将保持原样,但每个变量都会被解析器自动转义
...
<c:forEach items="${orders}" var="item">
<p>${item.name}</p>
<p>${item.price}</p>
<p>${item.description}</p>
</c:forEach>
...
If you want to force escaping by default in Spring, you could consider this as well, but it doesn't escape EL expressions, just tag output, I think:
如果你想在 Spring 中默认强制转义,你也可以考虑这个,但它不会转义 EL 表达式,只是标记输出,我认为:
http://forum.springsource.org/showthread.php?61418-Spring-cross-site-scripting&p=205646#post205646
http://forum.springsource.org/showthread.php?61418-Spring-cross-site-scripting&p=205646#post205646
Note: Another approach to EL escaping that uses XSL transformations to preprocess JSP files can be found here:
注意:另一种使用 XSL 转换来预处理 JSP 文件的 EL 转义方法可以在这里找到:
http://therning.org/niklas/2007/09/preprocessing-jsp-files-to-automatically-escape-el-expressions/
http://therning.org/niklas/2007/09/preprocessing-jsp-files-to-automatically-escape-el-expressions/
回答by MasterV
Managing XSS requires multiple validations, data from the client side.
管理 XSS 需要多次验证,来自客户端的数据。
- Input Validations(form validation) on the Server side. There are multiple ways of going about it. You can try JSR 303 bean validation(hibernate validator), or ESAPI Input Validation framework. Though I've not tried it myself (yet), there is an annotation that checks for safe html (@SafeHtml). You could in fact use Hibernate validator with Spring MVC for bean validations -> Ref
- Escaping URL requests- For all your HTTP requests, use some sort of XSS filter. I've used the following for our web app and it takes care of cleaning up the HTTP URL request - http://www.servletsuite.com/servlets/xssflt.htm
- Escaping data/htmlreturned to the client (look above at @BalusC explanation).
- 服务器端的输入验证(表单验证)。有多种方法可以解决这个问题。您可以尝试 JSR 303 bean 验证(休眠验证器)或ESAPI 输入验证框架。虽然我自己还没有尝试过(还没有),但有一个注释可以检查安全的 html (@SafeHtml)。实际上,您可以将 Hibernate 验证器与 Spring MVC 一起用于 bean 验证 -> Ref
- 转义 URL 请求- 对于所有 HTTP 请求,使用某种 XSS 过滤器。我在我们的网络应用程序中使用了以下内容,它负责清理 HTTP URL 请求 - http://www.servletsuite.com/servlets/xssflt.htm
- 转义返回给客户端的数据/html(查看上面的@BalusC 解释)。
回答by Alireza Fattahi
If you want to make sure that your $
operator does not suffer from XSS hack you can implement ServletContextListener
and do some checks there.
如果您想确保您的$
操作员不会遭受 XSS 黑客攻击,您可以ServletContextListener
在那里实施并进行一些检查。
The complete solution at: http://pukkaone.github.io/2011/01/03/jsp-cross-site-scripting-elresolver.html
完整的解决方案:http: //pukkaone.github.io/2011/01/03/jsp-cross-site-scripting-elresolver.html
@WebListener
public class EscapeXmlELResolverListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory.getLogger(EscapeXmlELResolverListener.class);
@Override
public void contextInitialized(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener initialized ...");
JspFactory.getDefaultFactory()
.getJspApplicationContext(event.getServletContext())
.addELResolver(new EscapeXmlELResolver());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener destroyed");
}
/**
* {@link ELResolver} which escapes XML in String values.
*/
public class EscapeXmlELResolver extends ELResolver {
private ThreadLocal<Boolean> excludeMe = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
@Override
public Object getValue(ELContext context, Object base, Object property) {
try {
if (excludeMe.get()) {
return null;
}
// This resolver is in the original resolver chain. To prevent
// infinite recursion, set a flag to prevent this resolver from
// invoking the original resolver chain again when its turn in the
// chain comes around.
excludeMe.set(Boolean.TRUE);
Object value = context.getELResolver().getValue(
context, base, property);
if (value instanceof String) {
value = StringEscapeUtils.escapeHtml4((String) value);
}
return value;
} finally {
excludeMe.remove();
}
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base){
return null;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
@Override
public void setValue(ELContext context, Object base, Object property, Object value){
throw new UnsupportedOperationException();
}
}
}
Again: This only guards the $
. Please also see other answers.
再说一遍:这只保护$
. 另请参阅其他答案。