java - Autobean 和 XSS 问题

标签 java json gwt xss autobean

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

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

我正在使用 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 转义了字符 (Ü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 为 null

最佳答案

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

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

关于java - Autobean 和 XSS 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10428997/

相关文章:

java - 在 Java 中,什么时候 {a,b,c,...} 数组简写不合适,为什么?

java - 如何获取客户端系统使用的日期格式?

c++ - 通过 C++ 和 Qt 访问 Googles Book API

asp.net - MVC JSON 操作返回 bool

java - GWT FileUpload Servlet 无法检索文件内容

java - entityManager.flush()会清除二级缓存吗?

java - 数组作为局部变量 - 不遵循 Lambda 中的明确赋值规则

php - MySQL、JSON 和 Fullcalendar

java - 理解GWT AbstractActivity的start方法

java - 我将如何编写一个获取 &lt;script&gt; 标记内容的 Java 正则表达式?