我在后端有一个 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;
}
我尝试使用encodeForHTML
和encodeForJavaScript()
。
这对于普通字符来说效果很好,但是一旦我使用元音变音字符(ü、ä、ö),我就会遇到问题。
如果我使用 encodeforHTML()
函数,javascript 变量看起来像这样(注意名字有一个 ü):
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 字符串时,遇到了一个奇怪的问题。在开发模式/托管模式下,解码工作正常并且元音变音正确显示。 然而,一旦我在生产模式下运行代码,我就会得到一个未捕获的异常:
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)
我可以想到以下解决方案:
- 仅依赖输入验证(当数据存储在数据库中时)并删除输出编码。但这不是推荐的方法。
- 将元音变音替换为普通 ASCII 字符 (ü => ue) 并继续使用输出编码
- 使用一些转义 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.java
的 findOriginalDeclaringClass
函数中得到一个 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/