Autobean and XSS issue - java

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:
Rely only on input validation (when the data is stored in the db) and remove the output encoding. But that's not the recommended approach.
Replace the Umlaute with normal ASCII characters (ü => ue) and continue to use output encoding
use some library which escapes the XSS characters but leaves the Umlaute alone.
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

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.

Related

python: Send string value without using string

I'm setting a python application that uses an external module padelpy that wraps the access to a rest API: from padelpy import padeldescriptor
I have a dictionary with settings names and values:
settings = {
'fingerprints': False,
'd2_d': False,
...
}
I loop through the received POST.request parameters to check which setting(s) to communicate as true:
for setting in settings.keys():
if setting in request.POST:
settings.update({setting: request.POST.get(setting)})
str_conf = '%s=TRUE' % setting
padeldescriptor(str_conf)
if I use
padeldescriptor(fingerprints=TRUE)
it works
but if I use
padeldescriptor(str_conf)
it's the same as sending padeldescriptor("fingerprints=TRUE")
and I get an error back from the server:
Exception in thread "main" java.lang.NumberFormatException: For input string: "fingerprints=TRUE"
How can I send the settings without using strings?
Thanks
You can use Dictionary unpacking to do this
padeldescriptor(**settings) should work. What that does is unpack everything in your dictionary as keyword arguments to that function.

Is there any substitute for UrlUtil.encodeQuery/URIUtil.decode?

I have an url, that contains Russian symbols and for encoding/decoding I use URIUtil.encodeQuery/decode. For example this piece of code
String url =
"https://dom.sakh.com/flat/sell?s[layout][]=102 серия&s[layout][]=138 серия&s[layout][]=306 серия&s[layout][]=97 серия&s[layout][]=97-С серия&s[layout][]=брежневка&s[layout][]=гостинка&s[layout][]=индивидуальная&s[layout][]=новая пл.&s[layout][]=сталинка&s[layout][]=хрущевка&s[price][min]=0&s[price][max]=10000000000";
System.out.println(URIUtil.encodeQuery(url));
It will display the following string
https://dom.sakh.com/flat/sell?s%5Blayout%5D%5B%5D=102%20%D1%81%D0%B5%D1%80%D0%B8%D1%8F&s%5Blayout%5D%5B%5D=138%20%D1%81%D0%B5%D1%80%D0%B8%D1%8F&s%5Blayout%5D%5B%5D=306%20%D1%81%D0%B5%D1%80%D0%B8%D1%8F&s%5Blayout%5D%5B%5D=97%20%D1%81%D0%B5%D1%80%D0%B8%D1%8F&s%5Blayout%5D%5B%5D=97-%D0%A1%20%D1%81%D0%B5%D1%80%D0%B8%D1%8F&s%5Blayout%5D%5B%5D=%D0%B1%D1%80%D0%B5%D0%B6%D0%BD%D0%B5%D0%B2%D0%BA%D0%B0&s%5Blayout%5D%5B%5D=%D0%B3%D0%BE%D1%81%D1%82%D0%B8%D0%BD%D0%BA%D0%B0&s%5Blayout%5D%5B%5D=%D0%B8%D0%BD%D0%B4%D0%B8%D0%B2%D0%B8%D0%B4%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F&s%5Blayout%5D%5B%5D=%D0%BD%D0%BE%D0%B2%D0%B0%D1%8F%20%D0%BF%D0%BB.&s%5Blayout%5D%5B%5D=%D1%81%D1%82%D0%B0%D0%BB%D0%B8%D0%BD%D0%BA%D0%B0&s%5Blayout%5D%5B%5D=%D1%85%D1%80%D1%83%D1%89%D0%B5%D0%B2%D0%BA%D0%B0&s%5Bprice%5D%5Bmin%5D=0&s%5Bprice%5D%5Bmax%5D=5000000000
And if I apply a method URIUtil.decode to this url i will get back:
https://dom.sakh.com/flat/sell?s[layout][]=102 серия&s[layout][]=138 серия&s[layout][]=306 серия&s[layout][]=97 серия&s[layout][]=97-С серия&s[layout][]=брежневка&s[layout][]=гостинка&s[layout][]=индивидуальнаяs[layout][]=новая пл.&s[layout][]=сталинка&s[layout][]=хрущевка&s[price][min]=0&s[price][max]=10000000000
But these methods are a bit old (httpclient's (3.1) URIUtil.encodeQuery() is gone in org.apache.httpcomponents (4.4.1) and i am trying to replace thsese methods). So my question is how to change my code saving the behavior? What to use? Provide an example, please, if it is possible.

HtmlUnit and HTTPS pages

I'm trying to make a program that checks avaliable positions and books the first avaliable one. I started writing it and i ran into a problem pretty early.
The problem is that when I try to connect with the site (which is https) the program doesn't do anything. It doesn't throw an error, it doesn't crash. And the weirdest thing is that it works with some https websites and with some it doesn't.
I've spent countless hours trying to resolve this problem. I tried using htmlunitdriver and it still doesn't work. Please help.
private final WebClient webc = new WebClient(BrowserVersion.CHROME);
webc.getCookieManager().setCookiesEnabled(true);
HtmlPage loginpage = webc.getPage(loginurl);
System.out.println(loginpage.getTitleText());
I'm getting really frustrated with this. Thank you in advance.
As far as i can see this has nothing to do with HttpS. It is a good idea to do some traffic analysis using Charles or Fiddler.
What you can see....
The page returned from the server as response to your first call to https://online.enel.pl/ loads some external javascript. And then the story begins:
This JS looks like
(function() {
var z = "";
var b = "766172205f3078666.....";
eval((function() {
for (var i = 0; i < b.length; i += 2) {
z += String.fromCharCode(parseInt(b.substring(i, i + 2), 16));
}
return z;
})());
})();
As you can see someone likes to hide the real javascript that gets processed.
Next step is to check the javascript after this simple decoding
It is really huge and looks like this
var _0xfbfd = ['\x77\x71\x30\x6b\x77 ....
(function (_0x2ea96d, _0x460da4) {
var _0x1da805 = function (_0x55e996) {
while (--_0x55e996) {
_0x2ea96d['\x70\x75\x73\x68'](_0x2ea96d['\x73\x68\x69\x66\x74']());
}
};
.....
Ok now we have obfuscated javascript. If you like you can start with http://ddecode.com/hexdecoder/ to get some more readable text but this was the step where i have stopped my analysis. Looks like this script does some really bad things or someone still believes in security by obscurity.
If you run this with HtmlUnit, this codes gets interpreted - yes the decoding works and the code runs. Sadly this code runs endless (maybe because of an error or some incompatibility with real browsers).
If you like to get this working, you have to figure out, where the error is and open an bug report for HtmlUnit. For this you can simply start with a small local HtmlFile and include the code from the first external javascript. Then add some log statements to get the decoded version. Then replace this with the decoded version and try to understand what is going on. You can start adding alert statements and check if the code in HtmlUnit follows the same path as browsers do. Sorry but my time is to limited to do all this work but i really like to help/fix if you can point to a specific function in HtmlUnit that works different from real browsers.
Without the URL that you are querying it is dificult to say what could be wrong. However, having worked with HTML unit some time back I found that it was failing with many sites that I needed to get data from. The site owners will do many things to avoid you using programs to access them and you might have to resort to using some lower level library like Apache HTTP components where you have more control over what is going on under the hood.
Also check if the website is constructed using JavaScript which is getting more and more popular but making it increasingly dificult to use programs to interrogate the content.

how do I link to a servlet within javascript code

I got an XLS pic inside of an HTML link, and i need to verify some information first before calling to the servlet, that's why i'm not including the servlet inside of the href="". So i've created a javascript function that verifies the input information in order to be used by the servlet.
(The Servlet returns a XLS in order to be saved by the user).
Tried this:
document.location.href = 'saveExcelServlet.do?' + <<GET method attributes>>;
But it didn't work.
It says:
Problem accessing /wscall-metrics-web/saveExcelServlet.do. Reason:
null
Caused by:
java.lang.NumberFormatException: null
If i write it works...
Can anyone help me?
Thanks.
M.
There's a good chance the URL isn't quite built the way you expect. A great poorman's technique for debugging this kind of thing is to assign a variable and pop it up in an alert:
var newLoc = 'saveExcelServlet.do?' + <<GET method attributes>>;
alert(newLoc);
You can see exactly what URL is getting fetched.

struts validation problem in IE

I am using Struts 2.1.8 and facing validation problem in IE. I am getting the following error
An exception occurred: Error. Error message: Invalid argument.
I tried out to figure out the cause and found the following. My generated javascript code is:
field = form.elements['district.name'];
var error = "Enter only alphabets for district";
if (continueValidation && field.value != null && !field.value.match("^[a-zA-Z ]*$")) {
addError(field, error);
errors = true;
}
I tried to mock up by putting the same code in a function and calling it in onclick event. The method addError() throws the exception and the reason is field variable. If I change it to field[0], it works fine. How to fix this error?
Check the generated HTML source. Open the page in webbrowser, rightclick and choose View Source. Is the input field's name really district.name? Isn't it prefixed/suffixed with some other autogenerated key (possibly the ID/name of the <form>) like as many other MVC frameworks do? If so, you'll need to change the JavaScript code accordingly that it uses the right element name as it appears in the HTML DOM tree. You know, JavaScript runs at the client machine and only sees the generated HTML DOM tree, not the "original" server-side code which is responsible for generating the HTML.

Categories