JSF中的CSRF、XSS和SQL注入攻击防范
Posted
技术标签:
【中文标题】JSF中的CSRF、XSS和SQL注入攻击防范【英文标题】:CSRF, XSS and SQL Injection attack prevention in JSF 【发布时间】:2011-12-05 01:10:19 【问题描述】:我有一个基于 JSF 的 Web 应用程序,使用 mysql 作为数据库。我已经在我的应用程序中实现了防止 CSRF 的代码。
现在由于我的底层框架是 JSF,我想我不必处理 XSS 攻击,因为它已经由 UIComponent
处理。我没有在任何视图页面中使用任何 javascript。即使我使用了,我真的需要实现代码来防止 XSS 攻击吗?
对于 DB,我们在所有 DB 交互中使用准备好的语句和存储过程。
为了防止这 3 种常见的攻击,还有什么其他需要处理的吗? 我已经浏览过OWASP 网站和他们的cheat sheets。
我是否需要注意任何其他潜在的攻击媒介?
【问题讨论】:
【参考方案1】:我没有在任何视图页面中使用任何 JavaScript。即使我使用了,我是否真的需要实现代码来绕过 XSS 攻击。
即使您没有在页面中使用 JavaScript,您也可能容易受到 XSS 攻击。当您在没有正确编码的情况下合并由攻击者控制的内容时,就会发生 XSS。
只要你做类似的事情
response.write("<b>" + x + "</b>")
如果攻击者可以使x
包含包含 JavaScript 的 html,那么您很容易受到 XSS 攻击。
解决方案通常是不要编写大量代码。通常,解决方案是对$x
和攻击者控制的任何其他值进行编码,然后再将它们包含在您生成的 HTML 中。
response.write("<b>" + escapePlainTextToHtml(x) + "</b>")
过滤或净化输入有助于提供额外的保护层。
<shameless-plug>
您还可以使用自动编码输出的模板语言来防止 XSS。
Closure Template 是 Java 的此类选项之一。
上下文自动转义通过增加闭包模板来根据其出现的上下文正确编码每个动态值,从而防御攻击者控制的值中的 XSS 漏洞。
编辑
由于您使用的是 JSF,因此您应该阅读XSS mitigation in JSF:
转义输出文本
<h:outputText/>
和<h:outputLabel/>
默认将转义属性设置为 True。通过使用此标签显示输出,您可以缓解大部分 XSS 漏洞。SeamTextParser 和
<s:formattedText/>
如果您想允许用户使用一些基本的 html 标签来自定义他们的输入,JBoss Seam 提供了一个
<s:formattedText/>
标签,允许用户指定一些基本的 html 标签和样式。
【讨论】:
@ankit,有什么特别的句子让你感到困惑吗? 问题是我正在使用 JSF,我想就像其他框架一样它会自动生成 HTML..所以我仍然对你写的内容一无所知..我也经历了闭包模板..就是这样对我来说是新的...... 还要添加:- 我的 GUI 将不允许用户输入尖括号标签。它将无法通过客户端验证并且请求将不会被处理..据我所知,如果我允许用户在我的 GUI 中输入 HTML 标签,然后我需要使用闭包模板来确保哪些都是有效标签,哪些都是无效的……如果有误,请纠正我。 @ankit,我编辑添加了指向 JSF 中 XSS 缓解的一些最佳实践的指针。 与老式 JSP/Servlet 不同,JSF 并没有真正的response.write(foo)
概念。对于 JSF 2.x 的新用户来说,这个答案有点令人困惑。【参考方案2】:
XSS
JSF 旨在具有内置的 XSS 预防功能。使用任何 JSF 组件。
<h:outputText value="#user.name" />
<h:outputText value="#user.name" escape="true" />
<h:inputText value="#user.name" />
etc...
请注意,当您在 Facelets 上使用 JSF 2.0 时,您可以像这样在模板文本中使用 EL:
<p>Welcome, #user.name</p>
这也将被隐式转义。此处不一定需要<h:outputText>
。
仅当您使用 escape="false"
明确取消转义用户控制的输入时:
<h:outputText value="#user.name" escape="false" />
那么你就有一个潜在的 XSS 攻击漏洞!
如果您希望将用户控制的输入重新显示为 HTML,其中您希望仅允许特定的 HTML 标签子集,如 <b>
、<i>
、<u>
等,那么您需要清理通过白名单输入。 HTML解析器Jsoup在这很helpful。
itemLabelEscaped
Mojarra 中的错误
较旧的 Mojarra 版本之前 2.2.6 存在以下错误:当通过 <f:selectItems var>
而不是 List<SelectItem>
或 SelectItem[]
作为值提供 List<T>
时,<f:selectItems itemLabel>
错误地呈现未转义的标签(issue 3143)。换句话说,如果您通过List<T>
将用户控制的数据重新显示为项目标签,那么您就有一个潜在的 XSS 漏洞。如果不能选择至少升级到 Mojarra 2.2.6,那么您需要将 itemLabelEscaped
属性显式设置为 true
以防止这种情况发生。
<f:selectItems value="#bean.entities" var="entity" itemValue="#entity"
itemLabel="#entity.someUserControlledProperty" itemLabelEscaped="true" />
CSRF
JSF 2.x 已经在使用服务器端状态保存时在表单中以javax.faces.ViewState
隐藏字段的形式内置了 CSRF 预防。在 JSF 1.x 中,这个值非常弱且太容易预测(它实际上从未打算用作 CSRF 预防)。在 JSF 2.0 中,这已通过使用长而强的自动生成值而不是相当可预测的序列值来改进,从而使其成为一种强大的 CSRF 预防措施。
在 JSF 2.2 中,这甚至通过将其作为 JSF 规范的必需部分以及用于加密客户端状态的可配置 AES 密钥来进一步改进,以防启用客户端状态保存。另见JSF spec issue 869 和Reusing ViewState value in other session (CSRF)。 JSF 2.2 中的新功能是对<protected-views>
的 GET 请求的 CSRF 保护。
只有当您使用<f:view transient="true">
中的无状态视图,或者应用程序中存在 XSS 攻击漏洞时,您才有潜在的 CSRF 攻击漏洞。
SQL 注入
这不是 JSF 的责任。如何防止这种情况取决于您使用的持久性 API(原始 JDBC、现代 JPA 或良好的 ol'Hibernate),但归根结底,您应该从不将用户控制的输入连接到 SQL 字符串中,例如所以
String sql = "SELECT * FROM user WHERE username = '" + username + "' AND password = md5(" + password + ")";
String jpql = "SELECT u FROM User u WHERE u.username = '" + username + "' AND u.password = md5('" + password + "')";
想象一下如果最终用户选择以下名称会发生什么:
x'; DROP TABLE user; --
您应该始终在适用的情况下使用参数化查询。
String sql = "SELECT * FROM user WHERE username = ? AND password = md5(?)";
String jpql = "SELECT u FROM User u WHERE u.username = ?1 AND u.password = md5(?2)";
在普通 JDBC 中,您需要使用 PreparedStatement
来填充参数值,而在 JPA(和 Hibernate)中,Query
对象也为此提供了设置器。
【讨论】:
我要补充一点,与普遍认为的相反,使用存储过程不会自动使您免受 SQL 注入攻击:我已经看到存储过程通过连接和创建 SQL 语句那个 同样容易受到 SQL 注入攻击!如果您使用错误,使用 PreparedStatements 不会自动使您免受 SQL 注入攻击,这与使用它们的方式相同! @BalusC 好吧,我非常感谢你对这个很棒的解释..但我有一些疑问。在我的 GUI 中,我使用escape="false"
。或者,如果您想允许某些 HTML,请使用 Jsoup。你只需要做String safe = Jsoup.clean(unsafe, Whitelist.basic());
。另见this guide。您可以在将输入保存到 DB 之前直接执行此操作。至于 JSF 1.x 中的 CSRF 预防,您应该在表单中维护一个基于会话的反 CSRF 令牌(基本上,一个具有长/自动生成/不可预测值的隐藏输入字段)。 Seam 框架有类似的组件<s:token>
: seamframework.org/Documentation/CrossSiteRequestForgery
@BalusC 如果您看一下OWASP Dokument about ORM Injection,您可以阅读the current Oracle JDBC driver escapes input for prepared statements and parameterized stored procedures.
,这意味着您可以安全注射,对吧?【参考方案3】:
当使用带有非转义值的<h:outputText escape="false">
时(例如来自 html 文本编辑器),您可能会受到令人讨厌的 XSS 攻击。在这种情况下,我使用了一个 JSF 转换器,它使用 Jsoup 从文本中删除 javascript,使 HTML 保持不变。转换器也可用于清理用户输入。你可以这样使用它:
<h:outputText value="bean.value" escape="false" converter="htmlSanitizingConverter"/>
还有转换器本身:
/**
* Prevents from XSS attack if output text is not escaped.
*/
@FacesConverter("htmlSanitizingConverter")
public class HtmlSanitizingConverter implements Converter
private static final Whitelist JSOUP_WHITELIST = Whitelist.relaxed()
.preserveRelativeLinks(true)
.addAttributes(":all","style");
/*
Optionally - add support for hyperlinks and base64 encoded images.
.addTags("img")
.addAttributes("img", "height", "src", "width")
.addAttributes("a", "href")
.addProtocols("img", "src", "http", "https", "data");
*/
@Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue)
return (submittedValue != null) ? Jsoup.clean(submittedValue, JSOUP_WHITELIST) : null;
@Override
public String getAsString(FacesContext context, UIComponent component, Object value)
return (value != null) ? Jsoup.clean(value.toString(), JSOUP_WHITELIST) : "";
注意:
当您将 JSF 与 PrimeFaces 一起使用时,请注意 <p:textEditor>
- older versions(6.2 之前的版本)默认情况下不会清理用户输入。
【讨论】:
1:单个组件不应作为通用问题的答案。 2:该问题在 7.0 中得到修复,该组件可以配置为进行清理,在 7.1 中它甚至会成为默认值。 @Kukeltje 转换器是解决此问题的通用解决方案,无论使用何种技术。我只是指出这个 PF 问题,因为它是最流行的 JSF 组件库,而且旧版本的 PF 仍然被大量使用(在大多数情况下,由于兼容性问题不会更新)。 我不是说你的回答没有价值,我认为是,只是它不直接属于这里。 *** 允许(甚至鼓励)您创建问题并自己回答。例如。 '如何在 p:textEditor 中防止 XSS' 并用这个答案自己回答。它受到高度赞赏,并保持清晰、分离等。 我知道转换器是通用的,但在使用纯文本区域和自定义 js html 编辑器插件(或降价,甚至在文本区域中输入纯 html)时也是如此。因此,您也可以通过关注不同的输入方式来使其更通用(在那里指的是p:textEditor
)。现在答案看起来只关注p:textEditor
,而解决方案在显示中而不是“输入数据”(您也可以在输入上使用转换器......更干净......如果有人没有风险忘记将其应用于输出以上是关于JSF中的CSRF、XSS和SQL注入攻击防范的主要内容,如果未能解决你的问题,请参考以下文章