Autobean和XSS问题

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

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

我正在使用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 bean = appUserFactory.appuser(appUserProxy); json = AutoBeanCodex.encode(bean).getPayload(); return json; } 

我尝试使用encodeForHTMLencodeForJavaScript() 。 这适用于普通字符但是只要我使用Umlaute字符(ü,ä,ö)我遇到问题。

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

 var data = {'user':'{"email":"john.doe@gmail.com","lastname":"Doe","firstname":"Über"}'}; 

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

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

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

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

 java.lang.IllegalArgumentException: Error parsing JSON: SyntaxError: Unexpected token x {"email":"john.doe@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. 仅依赖于输入validation(当数据存储在db中时)并删除输出编码。 但这不是推荐的方法。
  2. 用正常的ASCII字符(ü=> ue)替换Umlaute并继续使用输出编码
  3. 使用一些逃避XSS字符的库,但单独留下Umlaute。

我很感谢一些反馈

更新 :根据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) 

导致此exception的代码如下:

 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)在生产模式下工作正常。 在Hosted模式下,当我进入user.getPayload()我在findOriginalDeclaringClass函数中得到一个NPE。 似乎declaringClasses为null

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

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

Interesting Posts