【问题标题】:Autobean and XSS issueAutobean 和 XSS 问题
【发布时间】:2012-05-03 09:52:40
【问题描述】:

我在后端有一个Spring 应用程序,在前端有一个GWT 应用程序。 当用户登录时,''index.jsp'' 会将用户信息作为 javascript 变量输出。

我正在使用AutoBeanFactory将用户信息编码和解码为json。
因为用户可以注册,并且用户信息存储在数据库中,所以我尝试通过在 JSP 页面中转义用户信息来遵循OWASP XSS Preventing cheat sheet

我正在使用 esapi 库进行编码。服务器端代码如下所示:

public static String serializeUserToJson(CustomUser user) {
        String json;
        AppUserProxy appUserProxy = appUserFactory.appuser().as();
        appUserProxy.setFirstname(encoder.encodeForHTML(user.getFirstname()));
        appUserProxy.setLastname(encoder.encodeForHTML(user.getLastname()));
        AutoBean<AppUserProxy> bean = appUserFactory.appuser(appUserProxy);
        json = AutoBeanCodex.encode(bean).getPayload();
        return json;
    }

我尝试使用encodeForHTMLencodeForJavaScript()。 这适用于普通字符,但是一旦我使用变音字符(ü、ä、ö),我就会遇到问题。

如果我使用 encodeforHTML() 函数,javascript 变量看起来像这样(注意名字有一个 ü):

var data = {'user':'{"email":"john.doe&#x40;gmail.com","lastname":"Doe","firstname":"&Uuml;ber"}'};

使用 Autobean 解码工作正常,但字符 ü 未正确显示,但 HTML 转义了一个 (&amp;Uuml;ber)。

当我使用encodeForJavaScript() 函数时,输出如下:

var data = {'user':'{"email":"john.doe&#x40;gmail.com","lastname":"Doe","firstname":"\\xDCber"}'};

当我尝试解码 JSON 字符串时,我遇到了一个奇怪的问题。在开发模式/托管模式下,解码工作正常,元音变音显示正确。 但是,一旦我在生产模式下运行代码,我就会得到一个未捕获的异常:

java.lang.IllegalArgumentException: Error parsing JSON: SyntaxError: Unexpected token x
{"email":"john.doe&#x40;gmail.com","lastname":"Doe","firstname":"\xDCber"}
    at Unknown.java_lang_RuntimeException_RuntimeException__Ljava_lang_String_2V(Unknown Source)
    at Unknown.java_lang_IllegalArgumentException_IllegalArgumentException__Ljava_lang_String_2V(Unknown Source)
    at Unknown.com_google_gwt_core_client_JsonUtils_throwIllegalArgumentException__Ljava_lang_String_2Ljava_lang_String_2V(Unknown Source)
    at Unknown.com_google_gwt_core_client_JsonUtils_safeEval__Ljava_lang_String_2Lcom_google_gwt_core_client_JavaScriptObject_2(Unknown Source)
    at Unknown.com_google_web_bindery_autobean_shared_impl_StringQuoter_split__Ljava_lang_String_2Lcom_google_web_bindery_autobean_shared_Splittable_2(Unknown Source)
    at Unknown.com_google_web_bindery_autobean_shared_AutoBeanCodex_decode__Lcom_google_web_bindery_autobean_shared_AutoBeanFactory_2Ljava_lang_Class_2Ljava_lang_String_2Lcom_google_web_bindery_autobean_shared_AutoBean_2(Unknown Source)
    at Unknown.com_gmi_nordborglab_browser_client_mvp_main_UserInfoPresenter_onBind__V(Unknown Source)

我可以想到以下解决方案:

  1. 仅依赖输入验证(当数据存储在数据库中时)并删除输出编码。但这不是推荐的方法。
  2. 用普通的 ASCII 字符 (ü => ue) 替换元音变音并继续使用输出编码
  3. 使用一些库来转义 XSS 字符但不使用元音变音符号。

感谢您的反馈

更新:根据 Thomas 的建议,我现在从 JSNI 传递 JsoSplittable,然后将其传递给 AutoBeanCodex.decode 函数。它在生产模式下工作正常,但在托管模式下我得到以下 NPE:

java.lang.NullPointerException: null
    at com.google.gwt.dev.shell.CompilingClassLoader$MyInstanceMethodOracle.findOriginalDeclaringClass(CompilingClassLoader.java:428)
    at com.google.gwt.dev.shell.rewrite.WriteJsoImpl.isObjectMethod(WriteJsoImpl.java:307)
    at com.google.gwt.dev.shell.rewrite.WriteJsoImpl.visitMethod(WriteJsoImpl.java:289)
    at com.google.gwt.dev.shell.rewrite.WriteJsoImpl$ForJsoInterface.visitMethod(WriteJsoImpl.java:228)
    at com.google.gwt.dev.asm.ClassAdapter.visitMethod(ClassAdapter.java:115)
    at com.google.gwt.dev.shell.rewrite.RewriteJsniMethods.visitMethod(RewriteJsniMethods.java:350)
    at com.google.gwt.dev.asm.ClassReader.accept(ClassReader.java:774)
    at com.google.gwt.dev.asm.ClassReader.accept(ClassReader.java:420)
    at com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.rewrite(HostedModeClassRewriter.java:251)
    at com.google.gwt.dev.shell.CompilingClassLoader.findClassBytes(CompilingClassLoader.java:1236)
    at com.google.gwt.dev.shell.CompilingClassLoader.findClass(CompilingClassLoader.java:1059)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

导致此异常的代码如下:

private native final JsoSplittable getJsoUserdata() /*-{
    if (typeof $wnd.user   !== 'undefined')
        return $wnd.user;
    return null;
}-*/;

@Override
public JsoSplittable getUserdata() {
    JsoSplittable user = null;
    user = getJsoUserdata();
    if (user != null) {
       String payload = user.getPayload();
       Window.alert(payload);
    }
    return user;
}

Window.alert(payload) 在生产模式下工作正常。在托管模式下,当我进入user.getPayload() 时,我在CompilingClassLoader.javafindOriginalDeclaringClass 函数中得到一个NPE。看来declaringClasses 为空

【问题讨论】:

    标签: java json gwt xss autobean


    【解决方案1】:

    你不应该明确地逃避任何事情; AutoBeans 已经为您做到了。或者更确切地说,如果您想转义某些东西,请转义 AutoBean 的 getPayload() 的输出,而不是内脏。

    您的问题是 AutoBeans 尽可能使用本机 JSON.parse()(出于性能和安全原因),根据规范,它仅支持 \uNNNN 类型的转义,而不支持 encodeForJavaScript 输出的 \xHH。换句话说,ESAPI 需要encodeForJSON

    【讨论】:

    • 感谢托马斯的回复。我尝试在有效载荷上使用encodeForJavaScript(),它似乎工作正常。当 Autobean 已经为我为每个字段(安全方面)进行编码时,对有效负载进行编码是否真的有意义?顺便说一句:wijsmullerbros.nl/content/gwt-hostpage-init-data-encoding
    • 我实际上不明白的是,为什么您(和链接的文章)将 AutoBean 的有效负载用作字符串而不是对象文字。然后,您将对象作为 com.google.web.bindery.autobean.gwt.client.impl.JsoSplittable 从 JSNI 方法(而不是 Dictionary)返回,您甚至不需要 {user: } 包装器:var user = &lt;%= autobeanPayload %&gt;native JsoSplittable getUser() /*-{ return $wnd.user; }-*/;。至于你原来的问题:我不会使用encodeForJavaScript,但你必须小心你的页面编码(虽然应该是UTF-8)
    • 感谢您的建议。我没有想到。我试图直接返回一个Splittable,它在生产模式下工作正常。但是在托管模式下,当我调用 Splittable.getPayload() 时,我会得到一个 NPE(有关异常详细信息,请参阅我的问题)。
    • 您必须明确使用JsoSplittable,否则(使用Splittable)GWT 无法知道它应该是JsoSplittable 还是JsonSplittable;和JavaScriptObjects(如JsoSplittable;又名覆盖类型)真的是特别的野兽:code.google.com/p/google-web-toolkit/wiki/OverlayTypes
    • 我实际上在使用JsoSplittable,但不知何故,当 GWT 编译器为托管模式重写类时,我得到了一个 NPE(老实说,我对 GWT 的内部结构知之甚少,不知道为什么无论如何它正在这样做)。我用一些额外的代码更新了我的答案,并突出显示了导致此 NPE 的调用。这可能是 gwt 开发模式中的错误吗?
    猜你喜欢
    • 1970-01-01
    • 2018-12-22
    • 2012-04-24
    • 2020-11-14
    • 2014-12-26
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    相关资源
    最近更新 更多