As mentioned is several places on this website and in the app, there are some negative implications of using Android’s WebView to render web pages in Privacy Browser. The purpose of this post is to describe one of these downsides, explain the mitigations that are currently being taken, and lay out thoughts for a more permanent solution down the road.
One of the web tracking technologies that Privacy Browser is designed to mitigate is browser fingerprinting. Any piece of information the browser sends a web server that makes it stick out from the crowd increases the ability of the web server to uniquely fingerprint the browser. Including the app ID in the header, especially as long as Privacy Browser has a small market share, increases the chance that the total information sent to the server is unique.
For the Standard version of Privacy Browser the app ID is “com.stoutner.privacybrowser.standard”; the Free version is “com.stoutner.privacybrowser.standard”. The following is a log from www.stoutner.com that shows what information Privacy Browser <= 1.8 transmits to a web server (note that the User Agent has been changed from the default to “PrivacyBrowser/1.0”).
GET / HTTP/1.1|Host:www.stoutner.com|Connection:keep-alive|Cache-Control:max-age=0|Upgrade-Insecure-Requests:1|User-Agent:PrivacyBrowser/1.0|Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8|Accept-Encoding:gzip, deflate|Accept-Language:en-US|X-Requested-With:com.stoutner.privacybrowser.standard
Google doesn’t want to make it easy to get rid of the “X-Requested-With” header. However, there is a mechanism for replacing header information. This doesn’t allow a program to stop sending the “X-Requested-With” header, but it does allow a program to replace the app ID with a null value. Beginning with Privacy Browser 1.9, the following information will be sent in the headers:
GET / HTTP/1.1|Host:www.stoutner.com|Connection:keep-alive|Upgrade-Insecure-Requests:1|User-Agent:PrivacyBrowser/1.0|x-requested-with:|Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8|Accept-Encoding:gzip, deflate|Accept-Language:en-US
The Problems with the Workaround
The first problem with this workaround is that sending “X-Requested-With:” is not the same as not sending it at all. There are only going to be a few browsers that send “X-Requested-With:” as a header, so for fingerprinting purposes this workaround is only slightly better than including the app ID.
GET /wp-content/themes/twentysixteen/style.css?ver=4.5.3 HTTP/1.1|Host:www.stoutner.com|Connection:keep-alive|Cache-Control:max-age=0|User-Agent:PrivacyBrowser/1.0|Accept:text/css,*/*;q=0.1|Referer:https%3a//www.stoutner.com/|Accept-Encoding:gzip, deflate|Accept-Language:en-US|X-Requested-With:com.stoutner.privacybrowser.standard|If-None-Match:"10d4b-535f10e3fb580-gzip"|If-Modified-Since:Thu, 23 Jun 2016 12%3a18%3a46 GMT
This is a problem for every browser that uses Android’s WebView. For example, Lightning 4.3.3 behaves the same way as Privacy Browser >= 1.9: initial web requests include “X-Requested-With:” and resource requests include “X-Requested-With:acr.browser.lightning”.
The Long-Term Solution
There is a provision in WebView to bypass the default web loading functions by manually acquiring the information using HttpURLConnection and feeding it into WebView. This would allow the complete removal of the “X-Requested-With” header. However, making sure that all possible types of HTTP communication are handled correctly would be complex and the initial implementation would likely result in buggy behavior on some websites.
Another solution is to stop using Android’s WebView and embed a customized WebView in Privacy Browser. This would also allow for the complete removal of the “X-Requested-With” header, but would be a time consuming commitment to maintaining the custom WebView (both from a security and bug perspective).
Long term, it is likely that using a custom WebView will be the best solution for Privacy Browser. The plan is to implement all the privacy functions that are compatible with Android’s WebView (pick the low hanging fruit) and then do a detailed analysis of the best way to move beyond that point.