TokenScript

Intercepting HTTP requests in web view

#1

As part of TokenScript implementation, it is important that we can intercept and potentially block HTTP requests against a whitelist.

I couldn't find a way to intercept HTTP requests natively on iOS. There is a way that apparently works. But I'm not sure if it's good. It is to swap out the system function prototype (XMLHttpRequest.send()) that supports the HTTP call, hold a reference to it and delegate to it if the URL is in the whitelist. It feels hackish and we don't know if it's secure enough. I'll sleep on it a bit and maybe get a hint of how to do it better in my dreams.

Feel free to think about it or comment please or recommend a better way.

From https://forums.xamarin.com/discussion/140084/is-it-possible-to-intercept-post-requests-from-wkwebview-and-get-request-body:

var s_ajaxListener = new Object();
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
  // this.method :the ajax method used
  // this.url    :the url of the requested script (including query string, if any) (urlencoded) 
  // this.data   :the data sent, if any ex: foo=bar&a=b (urlencoded)
  console.log(`url: ${this.url}`)
}

XMLHttpRequest.prototype.open = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempOpen.apply(this, arguments);
  s_ajaxListener.method = a;  
  s_ajaxListener.url = b;
  if (a.toLowerCase() == 'get') {
    s_ajaxListener.data = b.split('?');
    s_ajaxListener.data = s_ajaxListener.data[1];
  }
}

XMLHttpRequest.prototype.send = function(a,b) {
  if (!a) var a='';
  if (!b) var b='';
  s_ajaxListener.tempSend.apply(this, arguments);
  if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;
  s_ajaxListener.callback();
}
#2

Either way, this needs some more testing. A few more things:

  • We'll need to patch fetch() similarly too.
  • The example code above might not handle multiple concurrent request correctly.
#3

Another way is to use declarative content blocking rules which are specified in JSON for each webview. Again the devil is in the details.

#4

Ok, we can use content blocking rules on iOS for this instead of the JavaScript hack described above. It's not programmatic, but fully declarative, so there would be limitations. But It'll help to accomplish 2 goals by blocking everything by default and allow a list of URL patterns to go through:

  1. Prevent loading of remote images/scripts
  2. Whitelist a list of APIs that are accessible (same thing for scripts, if we want to support that)
#5

What's the lowest version of iOS it supports and what's the lowest hardware that can run that iOS versoin?

#6

Update from the horses mouth [1]:

  • 83% of all devices introduced in the last 4 years are using iOS 12
  • 80% of all devices are using iOS 12

It'll require iOS 11, we are currently supporting iOS >= 10.

The current version is iOS 12, and by ~Oct of this year, iOS 13 will be available.

According to MixPanel [2], iOS 12 adoption is 88.57% and iOS 11 is 8.1%. We'll address >96% by making iOS 11 our minimum version.

iOS 11 requires iPhone 5S and above, the original iPad Air, the Mini 2 or newer. These are all devices released in 2013, which will be 5 years old by end of this year.

iOS 10 would support iPhones a year older. iPads seems the same for iOS 10 and iOS 11.

iPhone 5S is the first iOS device with Touch ID.

I presume MixPanel, which is an in-app/site analytics service, can only get their data from apps that are using their SDK.

[1] https://developer.apple.com/support/app-store/

[2] https://mixpanel.com/trends/#report/ios_12/from_date:-29,report_unit:day,to_date:0