JSF 中的 CSRF、XSS 和 SQL 注入攻击防护

CSRF, XSS and SQL Injection attack prevention in JSF

提问人:AngelsandDemons 提问时间:10/11/2011 最后编辑:Antti Haapala -- Слава УкраїніAngelsandDemons 更新时间:10/3/2019 访问量:49792

问:

我有一个基于 JSF 构建的 Web 应用程序,将 MySQL 作为数据库。我已经在我的应用程序中实现了防止 CSRF 的代码。

现在,由于我的底层框架是 JSF,我想我不必处理 XSS 攻击,因为它已经由 处理了。我没有在任何视图页面中使用任何 JavaScript。即使我使用,我真的需要实现代码来防止 XSS 攻击吗?UIComponent

对于 DB,我们在所有 DB 交互中使用预处理语句和存储过程。

还有什么需要处理来防止这 3 种常见攻击吗? 我已经浏览了OWASP网站和他们的备忘单

我是否需要处理任何其他潜在的攻击媒介?

JSF XSS SQL 注入 CSRF OWASP

评论


答:

8赞 Mike Samuel 10/11/2011 #1

我没有在任何视图页面中使用任何 JavaScript。即使我使用,我也确实需要实现代码来绕过 XSS 攻击。

即使您在页面中不使用 JavaScript,也可能容易受到 XSS 的攻击。当您合并攻击者控制的内容而未对其进行正确编码时,就会发生 XSS。

任何时候你做类似的事情

response.write("<b>" + x + "</b>")

如果攻击者可能导致包含包含 JavaScript 的 HTML,则容易受到 XSS 的攻击。x

解决方案通常是不编写大量代码。通常,解决方案是对攻击者控制的任何其他值进行编码,然后再将它们包含在生成的 HTML 中。$x

response.write("<b>" + escapePlainTextToHtml(x) + "</b>")

过滤或清理输入有助于提供额外的保护层。

<shameless-plug>

您还可以使用自动编码输出的模板语言来防止 XSS。

Closure Template 就是这样一种 Java 选项。

上下文自动转义的工作原理是增强闭包模板,以根据每个动态值出现的上下文正确编码每个动态值,从而防御攻击者控制的值中的 XSS 漏洞。

编辑

由于您使用的是 JSF,因此应该阅读 JSF 中的 XSS 缓解

转义输出文本

<h:outputText/>默认情况下,转义属性设置为 True。通过使用此标记显示输出,您可以缓解大多数 XSS 漏洞。<h:outputLabel/>

SeamTextParser 和 <s:formattedText/>

如果你想允许用户使用一些基本的 html 标签来自定义他们的输入,JBoss Seam 提供了一个标签,允许用户指定的一些基本的 html 标签和样式。<s:formattedText/>

评论

0赞 Mike Samuel 10/11/2011
@ankit,有没有一个特别的句子让你感到困惑?
0赞 AngelsandDemons 10/11/2011
问题是我正在使用 JSF,我想就像其他框架一样,它会自动生成 HTML。所以我对你写的东西仍然一无所知。我还浏览了关闭模板。这对我来说太新鲜了......
1赞 AngelsandDemons 10/11/2011
还要补充:- 我的 GUI 将不允许用户输入尖括号标签<>。它将无法通过客户端验证,并且不会处理请求。据我了解,如果我允许用户在我的 GUI 中输入 HTML 标签,那么我需要使用闭包模板来确保哪些都是有效的标签,哪些都是无效的......如果我错了,请纠正我。
0赞 Mike Samuel 10/11/2011
@ankit,我进行了编辑,添加了指向 JSF 中 XSS 缓解的一些最佳实践的指针。
3赞 BalusC 10/11/2011
与老式的 JSP/Servlet 不同,JSF 实际上没有 .对于刚接触 JSF 2.x 的用户来说,这个答案有点令人困惑。response.write(foo)
122赞 BalusC 10/11/2011 #2

XSS的

JSF 被设计为具有内置的 XSS 防护。您可以使用任何 JSF 组件安全地重新显示所有用户控制的输入(请求标头(包括 cookie!)、请求参数(也包括保存在 DB 中的参数!)和请求正文(上传的文本文件等)。

<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 标记的特定子集,如 、 、 等,那么您需要通过白名单清理输入。HTML 解析器 Jsoup 在这方面非常有用<b><i><u>

itemLabelEscapedMojarra < 2.2.6 中的错误

2.2.6 之前的旧 Mojarra 版本存在一个错误,即当提供 via 而不是 or as 值时,错误地将标签呈现为未转义(问题 3143)。换言之,如果您通过 将用户控制的数据重新显示为项目标签,那么您就有一个潜在的 XSS 漏洞。如果升级到至少 Mojarra 2.2.6 不是一个选项,那么您需要显式设置 attribute to 以防止这种情况发生。<f:selectItems itemLabel>List<T><f:selectItems var>List<SelectItem>SelectItem[]List<T>itemLabelEscapedtrue

<f:selectItems value="#{bean.entities}" var="entity" itemValue="#{entity}"
    itemLabel="#{entity.someUserControlledProperty}" itemLabelEscaped="true" />

CSRF的

JSF 2.x 在使用服务器端状态保存时,已经以隐藏字段的形式内置了 CSRF 预防。在 JSF 1.x 中,这个值非常弱,而且太容易预测了(实际上它从来都不是用来预防 CSRF 的)。在 JSF 2.0 中,通过使用长而强大的自动生成值而不是相当可预测的序列值,对此进行了改进,从而使其成为一种强大的 CSRF 预防。javax.faces.ViewState

在 JSF 2.2 中,这甚至得到了进一步的改进,使其成为 JSF 规范的必需部分,以及一个可配置的 AES 密钥来加密客户端状态,以防启用客户端状态保存。另请参阅 JSF 规范问题 869 和在其他会话中重用 ViewState 值 (CSRF)。JSF 2.2 中的新功能是 <protected-views> 对 GET 请求的 CSRF 保护。

只有当您使用无状态视图时,或者应用程序中的某个位置存在 XSS 攻击漏洞时,您才有一个潜在的 CSRF 攻击漏洞。<f:view transient="true">


SQL注入

这不是 JSF 的责任。如何防止这种情况取决于你使用的持久性 API(原始 JDBC、现代 JPA 或良好的 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 对象也为此提供了 setter。

评论

5赞 Joachim Sauer 10/11/2011
我要补充一点,与普遍的看法相反,使用存储过程并不能自动使您免受 SQL 注入攻击:我见过存储过程通过串联创建 SQL 语句,同样容易受到 SQL 注入的攻击!这与使用 PreparedStatements 不会自动使您免受 SQL 注入攻击的方式相同,如果您使用错误的话!
1赞 AngelsandDemons 10/12/2011
@BalusC好吧,我不能感谢你这个很棒的解释。但我有一些疑问。在我的 GUI 中,我使用 <h:outputText value=“#{user.name}” escape=“false” /> 在 GUI 上显示。现在这是一个潜在的XSS攻击。我该如何避免它??.其次,我正在使用 JSF 1.2,那么我该如何处理 CSRF?我使用WebScrarab工具拦截了Http请求并修改了值,它确实成功了。这是否意味着应用程序容易受到攻击,我该如何避免它。我已经处理过SQL注入。到目前为止,我唯一需要担心的是 XSS 和 CSRF。请帮忙。
0赞 AngelsandDemons 10/12/2011
@BalusC 此外,Samuel 提供的解释建议我看一下用于清理 HTML 输入的闭包模板。但是我听说关闭模板有严重的性能问题,而且它来自 Google Labs,所以它几乎是 Beta 版本,因此不稳定......您会推荐哪一个用于 HTMl santizing..Jsoup 或闭合..我对这种 santizing 和解析绝对陌生,因此我更喜欢易于学习和实现的东西。
3赞 BalusC 10/12/2011
至于 XSS,只需删除 .或者,如果你想允许某些 HTML,那么使用 Jsoup。你只需要做.另请参阅本指南。您可以在将输入保存到 DB 中之前直接执行此操作。至于 JSF 1.x 中的 CSRF 预防,您应该以以下形式维护一个基于会话的反 CSRF 令牌(基本上是一个具有长/自动生成/不可预测值的隐藏输入字段)。Seam 框架有类似的组件: seamframework.org/Documentation/CrossSiteRequestForgeryescape="false"String safe = Jsoup.clean(unsafe, Whitelist.basic());<s:token>
0赞 Joergi 3/9/2012
@BalusC,如果您要查看有关ORM注入的OWASP文档,则可以阅读,这意味着,您不会进行注射,对吗?the current Oracle JDBC driver escapes input for prepared statements and parameterized stored procedures.
1赞 Michał Stochmal 9/27/2019 #3

当使用未转义的值(例如来自html文本编辑器)时,您可能会受到讨厌的XSS攻击。在这种情况下,我使用JSF转换器,它使用Jsoup从文本中删除javascript,使HTML保持不变。转换器也可用于清理用户输入。你可以像这样使用它:<h:outputText escape="false">

<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 一起使用时,请注意 - 默认情况下,旧版本(6.2 之前)不会清理用户输入。<p:textEditor>

评论

1赞 Kukeltje 9/27/2019
1:单个组件不应是通用问题的答案。2:该问题在 7.0 中已修复,因为可以将组件配置为进行清理,而在 7.1 中它甚至将成为默认值。
0赞 Michał Stochmal 9/27/2019
无论使用何种技术,@Kukeltje转换器都是解决此问题的通用解决方案。我只是指出这个 PF 问题,因为它是最流行的 JSF 组件库,并且旧版本的 PF 仍然被大量使用(并且在大多数情况下由于兼容性问题不会更新)。
0赞 Kukeltje 9/27/2019
我并不是说你的答案没有价值,我认为是,只是它不直接属于这里。在 Stackoverflow 中,您可以(甚至鼓励)自己创建问题并回答问题。例如,“如何在 p:textEditor 中防止 XSS”,然后用这个答案自己回答。它受到高度赞赏,并使事情保持清晰、分离等。
1赞 Kukeltje 9/27/2019
我知道转换器是通用的,但是当使用纯文本区域和自定义 js html 编辑器插件(或 markdown 甚至在文本区域中输入纯 html 时)时也是如此。因此,您也可以通过关注不同的输入方式(其中指的是 to)来使其更通用。现在,答案似乎只集中在解决方案在显示屏上,而不是“输入数据”(您也可以在输入上使用转换器......更干净...如果有人忘记将其应用于输出,则没有风险p:textEditorp:textEditor