Accessing JS code from an android Native app - android

This might seem to be a weird problem, but I am curious to know if it would work. I am working on a POC, and hence have to either prove or disprove that this works or not.
The UI in the Android app would be native (Java + XML layouts) + some other device features access like (Camera/File system etc).
There is a JS library that I have built, that has a few functions which do Ajax post and get requests.
In the app, I have an invisible Webview, where I load a blank HTML (referencing this JS library). And into that WebView, I have injected a JavascripInterface. So, essentially, the UI would be native, and you would never see the Webview. That's just a host which provides access to my JS library to the native code.
Now, on some action on my UI, I call the JS functions on the Webview, which in turn tries to make an ajax call (loadUrl calls ex. javascipt:functionName()). But, those calls fail, without any visible errors.
Note: This same HTML file works, if I load it up on my desktop browser. The AJAX calls succeed.
But, when I initiate Ajax calls through the JavascriptInterface(or webview.loadUrl() calls), they fail, with a reponse status 0.
Things apart from AJAX, like simple function calls, alerts, and callbacks through javascript interface work fine though.
Q: I know this is a weird and an unpractical way to do things. But, would it/should it work?
Update: Even after setting the setBlockNetworkLoads(false), it still doesn't work.
I tried logging the JS calls and errors, and got this error.
Request header field X-Requested-With is not allowed by
Access-Control-Allow-Headers.
Any idea how to solve this?

It seems that your are trying to do a cross domain ajax request.
Cross domain requests are not allowed by same origin policy and so the requests will be blocked. If you are loading a local file in webView and then sending ajax requests from it to other domains, this will be the case.
You if that is the case and it is the same origin policy causing you trouble then you might want to look at Cross-origin Resource Sharing (CORS) or JSONP to workaround it.
Given the error you get it seems that your problem is similar to one discussed here:
Cross-Domain AJAX doesn't send X-Requested-With header
You might want to change server settings to allow X-Requested-With header.
Also it seems that from API level 16, webSettings added a method setAllowFileAccessFromFileURLs(). Setting this to true for the webView might solve the problem as well.

I had a similar issue where I was loading a "web-app" locally into a WebView, just doing Ajax remotely. I observed a similar problem where Javascript alerts etc worked fine, but AJAX calls didn't. It turned out that by default the WebView blocks "network loads".
Make sure you do this:
webView.getSettings().setBlockNetworkLoads(false);
That did it for me. Just to clarify, I wasn't using a Javascriptinterface - just loading a web-app as-is using webView.loadDataWithBaseUrl() - the baseUrl parameter passed to this method was where I perform all my AJAX calls (since this method respects the same origin policy)

Related

Remediation for JavaScript Interface Injection Vulnerability

I received a warning from Google Play Console that refers me to this page because I used JavaScript Interface in my app and suggest two options to solve the problem .
Option 1 tells :
Ensure that there are no objects added to the JavaScript interface of
any WebView that loads untrusted web content. You can do this in two
ways:
Ensure that no objects are ever added to the JavaScript interface
via calls to addJavascriptInterface.
Remove objects from the JavaScript interface in shouldInterceptRequest
via removeJavascriptInterface before untrusted content is loaded by
the WebView.
but I can't understand what google exactly says specially on :
Remove objects from the JavaScript interface in shouldInterceptRequest
via removeJavascriptInterface before untrusted content is loaded by
the WebView
can someone tell me more explanation ?
You can resolve this issue in following ways:
If your website supports HTTPS, use "https://" prefix in loadUrl method.
You can set android:usesCleartextTraffic to false in your Manifest or set a Network Security Config that disallows HTTP traffic. It also means that your website should run on HTTPS.
Now, coming to your question about "Remove objects from the JavaScript interface in shouldInterceptRequest via removeJavascriptInterface before untrusted content is loaded by the WebView" : It mean that your app should remove (or disable) JavaScriptInterface whenever there is any non HTTPS URL is loaded within the WebView.
After doing any of these, you need to update APK on Play Console.
Conclusion is that if you want to use JavaScriptInterface, better use HTTPS on your website. If you use HTTP, JavaScriptInterface won't be allowed by Google Play.
I faced the same problem, and have not been able to figure this out, either. What worked for me, documented in How to address "Remediation for JavaScript Interface Injection Vulnerability"?, was to use WebView.evaluateJavascript. Alas, that is not a full replacement for all use cases of JavascriptInterface, but maybe it's sufficient for your purposes.
I just release an update without doing something special and warning disappeared BUT not sure it will came back again or not

Ajax call not working in Chrome for Android web app

net::ERR_ADDRESS_UNREACHABLE
Is the error I get.
It's just a standard Ajax call:
$.ajax({
url: postLink,
type: 'POST',
data: JSON.stringify(postData),
...
I suspect there's nothing wrong with the call itself.
Here's why - if I run the page in Chrome for Android it runs fine. No problems at all.
If I add that page to the homescreen, then Android treats the page as a web app (which is fine too, because it is). But I think there's something about the way Android/Chrome treats web apps that is stopping the Ajax call from going through. In this instance, the error above occurs.
Anyone heard of this issue before, perhaps know of a workaround?

oAuth support in a WebView

So I've created a simple WebView application that wraps an already existing mobile friendly site and displays it on the device. I've enabled javascript, supported screen orientation changes, etc...
I've run into an issue with the oAuth support though. Accessing the site from the chrome browser on the device, everything runs fine.
If I try to access the site from the app/WebView, it will push me over to the oAuth screen, let me input credentials and everything, but the moment it tries to push me back to the website and log me in, I get this:
Failed to recognize URL query:
https://exittix.com/frontend/login/redirect.html#access_token=******************************&expires_in=********&state=****client_id=******************network*****facebook*****display***popup****callback****_hellojs_agj27sx5****state****oauth_proxy***https***auth-server.herokuapp.com%2Fproxy***scope***basic_profile***email***basic***oauth***version***auth***https***facebook.com%2Foauth***
The * is used to protect data.
So, any ideas why oAuth isn't working inside a JS enabled webview but works fine in the mobile chrome browser for android?
Thanks in advance for your help!
EDIT:
Ok, so I've tracked the error I'm getting back to redirect.html.
This page calls some javascript. If the javascript fails to redirect, then it displays that error I have above instead.
The javascript being called to handle the oAuth is Andrew Dodson's hello.js script.
You can see it HERE.
I've concluded that the second half of the error's url is indeed the unhandled JSON.
Here's what the returned data looks like after I've decoded it from the URL encoded characters:
{"client_id":"************.apps.googleusercontent.com","network":"google","display":"popup","callback":"_hellojs_********","state":"","oauth_proxy":"https://auth-server.herokuapp.com/proxy","scope":["https://www.googleapis.com/auth/userinfo.profile","https://www.googleapis.com/auth/userinfo.email","basic"],"oauth":{"version":2,"auth":"https://accounts.google.com/o/oauth2/auth"}}&access_token=***.*.*****_*********************************************************&token_type=Bearer&expires_in=3600
Any ideas why this isn't getting handled properly in the WebView?

Phonegap / Cordova include external src without http / https

So here it is, I'm starting a Phonegap app and would like to use a given library. In the library code it tries to reach some URL with this form :
//img.site.com/given_img.png
without http or https at the beginning so it will adapt nicely. But when launching the app on my phone I see it tries to reach :
file://img.site.com/given_img.png
Not http or https... But file protocol. Obviously it fails to load...
Anyone knows how to deal with this ?
Thanks ahead !
As far as I can tell, after researching this for some time... Currently there is no solution out of the box. You have to check the code with JS and force add the wanted protocol into it before execution. I simply changed the way I wanted to do things and avoided that kind of situation.
The idea behind having src="//domain.com/some/pic" is so that the browser will request those assets with the protocol matching your website, meaning, if your website is running on http - it will request the picture over http, vs if your website is running on https it will request the image with https://.
#Jeremy is right, there's no option at the moment.
But you can take the protocol matching your website with var protocol = window.location.protocol and use that in your src={{ protocol + image }}
This is to prevent from writing hard-coded http / https and mix secure with non-secure content in your website which causes errors to jump like "This Page Contains Both Secure and Non-Secure Items"

Sencha Touch 2.1 native (android) app not getting json from remote (it works on PC)

I created my first Sencha touch 2 app by watching this video (http://youtu.be/5F7Gx0-W-M4) and it has a store page structured like this:
Ext.define('FirstApp.store.Places',{
extend:'Ext.data.Store',
config:{
autoLoad:true,
model:'FirstApp.model.Place',
proxy:{
type:'ajax',
url:'https://maps.googleapis.com/maps/api/place/search/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=AIzaSyCFWZSKDslql5GZR0OJlVcgoQJP1UKgZ5U',
reader:{
type:'json',
rootProperty:'results'
}
}
}
})
The after-build (after running "sencha app build native") package work very well on my MAC (all browsers) but the generated app (i am running it on my nexus phone) works but doesn't collect any data from the google maps json.
Any help would be appreciated
The example you are referring is using google map's place search API. You can not use this API when you build the app for mobile phone with proxy set to ajax . Basically, you can not use any resource that is outside your domain. Like if your site is at yourdomain.com and there is someotherdomain.com, then you can't make ajax request to this someotherdomain.com from yourdomain.com unless that domain allows you to. In this case, your mobile app is not having any domain. You are just loading a page inside webview.
The reason is, ajax will not be able to load cross-origin resources. App build works on browsers because I believe you're using chrome with --disable-web-security flag. To work with CORS you need to use JsonP proxy. It's the only way if you're packaging for mobile app. If in a case, you own the server ( not in this context though ) then you can allow CORS by setting appropriate headers like
Access-Control-Allow-Origin: *
or
Access-Control-Allow-Origin: http://yourdomain.com/resource
Try setting proxy to JsonP .

Categories

Resources