Reputation: 17489
I have a Spring
application on the backend and a GWT
application on the frontend.
When the user is logged in ''index.jsp'' will output the user information as a javascript variable.
I am using AutoBeanFactory
to encode and decode the user information as json.
Because the user can register and the user information are stored in the database I try to follow the OWASP XSS Preventing cheat sheet by escaping the user information in the JSP page.
I am using the esapi library to do the encoding. The server side code looks like this:
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;
}
I tried to use encodeForHTML
and encodeForJavaScript()
.
This works fine for normal characters however as soon as I use Umlaute characters (ü, ä, ö) I run into problems.
If I use the encodeforHTML()
function the javascript variable looks like this (note firstname has an ü):
var data = {'user':'{"email":"john.doe@gmail.com","lastname":"Doe","firstname":"Über"}'};
Decoding with Autobean works fine however the character ü is not displayed properly but the HTML escaped one (Über
).
When I use the encodeForJavaScript()
function the output is as follows:
var data = {'user':'{"email":"john.doe@gmail.com","lastname":"Doe","firstname":"\\xDCber"}'};
When I try to decode the JSON string I run into a weird problem. In Development Mode/Hosted Mode decoding works fine and the Umlaut is properly displayed. However as soon as I run the code in Production Mode I get an uncaught 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)
I can think of following solutions:
I am thankful for some feedback
Update: Based on Thomas suggestions I am now passing a JsoSplittable
from JSNI and then passing this to the AutoBeanCodex.decode
function. It works fine in Production Mode however in Hosted Mode I get following 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)
The code which causes this exception is following:
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) works fine in production mode. In Hosted mode when I step into user.getPayload()
I get a NPE in findOriginalDeclaringClass
function of the CompilingClassLoader.java
. It seems that declaringClasses
is null
Upvotes: 1
Views: 1303
Reputation: 64541
You shouldn't explicitly escape anything; AutoBeans do it for you already. Or rather, if you want to escape something, escape the output of AutoBean's getPayload()
, not the innards.
Your problem is that AutoBeans uses native JSON.parse()
when possible (for both performance and safety reasons) which, per spec, only supports \uNNNN
kinds of escapes, and not the \xHH
that encodeForJavaScript
outputs. In other words, ESAPI would need an encodeForJSON
.
Upvotes: 2