We have an android application that's iframe-ing our website into their application. However to prevent click jacking we have the following directive in our proxy configs.
Header append X-FRAME-OPTIONS "SAMEORIGIN"
This is a very common Cross-Origin Resource Sharing strategy.
Unfortunately the Webview in an android browser has the origin as file:// which is different than the domain we use. This leads to the error refused to display x-frame-options set to sameorigin.
What strategies (either on the proxy or the client side) Can I employ to allow the android application to interact with our site (without COMPLETELY removing sameorigin)?
Don’t think you can do that. Since Chromium doesn’t see Allow-From as feature[1] and Android relies heavily on Chromium’s frameworks for WebViews.
I’m guessing your requirements are to block browser based click jackings?
Since you can’t use Allow-From. You may want to think about an approach similar to that outlined in this BlackHat talk[2], UI Redressing Attacks on Android Devices. I’d recommend reading the entire pdf really interesting stuff.
Check out Chapter 5 MITIGATION TECHNIQUES, Section 1 Browser-Based UI Redressing.
<styleid=”antiClickjack”>
body{display:none!important;}
</style>
<scripttype=”text/javascript”>
if(self===top){
varantiClickjack=document.
getElementById(”antiClickjack”);
antiClickjack.parentNode.removeChild(antiClickjack);
}else{
top.location=self.location;
}
</script>
[1] https://code.google.com/p/chromium/issues/detail?id=129139#c20
[2] https://media.blackhat.com/ad-12/Niemietz/bh-ad-12-androidmarcus_niemietz-WP.pdf
The WebView has a loadDataWithBaseURL() method. You could read in your file, and pass that through with whatever origin you need as the base url.
public void loadDataWithBaseURL(String baseUrl,
String data,
String mimeType,
String encoding,
String historyUrl)
Loads the given data into this WebView, using baseUrl as the base URL for the content. The base URL is used both to resolve relative URLs and when applying JavaScript's same origin policy.
Related
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
Google has asked me to address https://support.google.com/faqs/answer/9095419 in my Android app, which basically means not to use the JavaScript injection mechanism for a web page loaded via HTTP.
Not using this mechanism (option 1) doesn't work for me. Setting android:usesCleartextTraffic to false also doesn't work, as the app uses non-HTTPS traffic elsewhere. So that leaves me with "you can ensure that any affected WebViews do not load any URLs with HTTP schemes via loadUrl" - which I'm happy to do, as my app only uses file:/// URLs to load content into the WebView, which should be fine security-wise. But how do I need to code the shouldOverrideUrlLoading method so that Google's checker recognizes that I'm using only file:/// URLs?
Note that the question is different from both Remediation for JavaScript Interface Injection Vulnerability (because I'm clear what is being asked) and In Android, JavaScript Interface Injection Vulnerability (because I'm not using HTTP, but file:/// URLs).
Edit: Adding my shouldOverrideUrlLoading method. (This isn't the entire method, but the salient part of it.)
#Override
public boolean shouldOverrideUrlLoading (WebView browser, String url) {
if (url.startsWith("file:///")) {
// This is my web site, so do not override; let my WebView load the page
browser.loadUrl(url);
return true;
}
// Otherwise, the link is not for a page on my site, or is an entirely different kind of URI
// (like tel:, geo: or mailto:), so launch another Activity that handles URLs
act.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
return true;
}
I have not found a way to use file:// URLs with assets in a way that satisfies Google code checker. While this would solve the issue, I'm still not clear how one might need to code it.
What I ended up doing -which solves my immediate problem- is to call a JavaScript method via the WebView.evaluateJavascript method. When called from within WebViewClient.onPageFinished the page has finished loading, so all elements are accessible. While not important for my case, this method can also return a value to the Java code. So while it's not a general replacement for a JavascriptInterface, it addresses some of its uses cases.
I have developed a simple REST api using NODE and EXPRESS. And I already have a web-app(browser) and a native mobile application.
Now I need to check if the incoming request is from web-browser or from native application.
I have successfully detected the device for incoming request coming from browser via USER-AGENT.
I will suggest using the Host header.
For example:
If your web application is hosted at example.com then all requests will have Host header set to example.com.
In your mobile application, you can manually set all request headers to have a different Host header like Host:app.example.com.
A good practice to have limited set of hostnames that accepted by the server.
Make sure you do not tight any security logic to that header. Every HTTP client can fake/override that value.
window.navigator.standalone for iOS, and window.matchMedia('(display-mode: standalone)').matches for Android to detect this:
isInWebAppiOS = (window.navigator.standalone == true);
isInWebAppChrome = (window.matchMedia('(display-mode: standalone)').matches);
Set a cookie for each to pass to the server.
References
Optimized Presentation of XML Content | Introduction
Android 8.0 Compatibility Definition | Android Open Source Project
Issues - chromium - An open-source project to help move the web forward. - Monorail
143578 – Chrome: XMLHttpRequest executed in UIWebView encodes valid query string characters
Browser Shredders: iOS UIWebView baseURL
iOS - Best Practices for Opening a Web Page Within an App - Outbrain Developer Center
CWE - CWE-749: Exposed Dangerous Method or Function (2.11)
Attack Surface Extended by URL Schemes (pdf)
Implementing XSLT into our iOS Apps | The Distance, York
How to transform xml with xslt and display it in Android webview
XSLT in a UIWebView using iOS SDK 4.2
detect ipad/iphone webview via javascript
is-webview
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"
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)