github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/MobileLibrary/iOS/SampleApps/TunneledWebView/README.md (about)

     1  # iOS Library Sample App: TunneledWebView
     2  
     3  ## Tunneling UIWebView
     4  
     5  *Note: this approach does not work with WKWebView (see [http://www.openradar.me/17190141](http://www.openradar.me/17190141)).*
     6  
     7  This app tunnels UIWebView traffic by proxying requests through the local Psiphon proxies created by [PsiphonTunnel](https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/MobileLibrary/iOS/PsiphonTunnel).
     8  The listening Psiphon proxy ports can be obtained via TunneledAppDelegate delegate callbacks (see `onListeningSocksProxyPort` and `onListeningHttpProxyPort` in `AppDelegate.swift`).
     9  
    10  This is accomplished by registering `NSURLProtocol` subclass `JAHPAuthenticatingHTTPProtocol` with `NSURLProtocol`.
    11  `JAHPAuthenticatingHTTPProtocol` is then configured to use the local Psiphon proxies.
    12  This is done by setting the [connectionProxyDictionary](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration/1411499-connectionproxydictionary?language=objc) of [NSURLSessionConfiguration](https://developer.apple.com/documentation/foundation/nsurlsessionconfiguration).
    13  See [`+ (JAHPQNSURLSessionDemux *)sharedDemux`](https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/c9c4834fba5e7a8b675c3ae493ac17b5975ab0fb/MobileLibrary/iOS/SampleApps/TunneledWebView/External/JiveAuthenticatingHTTPProtocol/JAHPAuthenticatingHTTPProtocol.m#L157) in `JAHPAuthenticatingHTTPProtocol.m`.
    14  
    15  We use a slightly modified version of JiveAuthenticatingProtocol (https://github.com/jivesoftware/JiveAuthenticatingHTTPProtocol), which in turn is largely based on [Apple's CustomHTTPProtocol example](https://developer.apple.com/library/content/samplecode/CustomHTTPProtocol/Introduction/Intro.html). 
    16  
    17  ## *\*\* Caveats \*\*\*
    18  
    19  ### i18n API Leaks Timezone
    20  
    21  The Internationalization API (i18n) provides websites, though a JavaScript API, with access to the timezone used by
    22  the user's browser (in this case UIWebView). This does not reveal the precise location of the user, but can be accurate
    23  enough to identify the city in which the user is located.
    24  
    25  Like the "Untunneled WebRTC" issue mentioned below, the i18n API cannot be disabled without disabling JavaScript.         
    26  
    27  ### NSURLProtocol Challenges
    28  
    29  ***NSURLProtocol is only partially supported by UIWebView (https://bugs.webkit.org/show_bug.cgi?id=138169) and iOS,
    30  meaning that some network requests are made out of process and are consequently untunneled.***
    31  
    32  Below we address the exceptions we have encountered, but there may be more.
    33  
    34  ### Untunneled Media
    35  
    36  ***In some versions of iOS audio and video are fetched out of process in mediaserverd and therefore are not intercepted 
    37  by NSURLProtocol.***
    38  
    39  *In our limited testing iOS 9/10 leak and iOS 11 does not leak.*
    40  
    41  #### Workarounds
    42  
    43  ***It is worth noting that this fix is inexact and may not always work. If one has control over the HTML being rendered and resources being fetched with XHR it is preferable to alter 
    44  the media source URLs directly beforehand instead of relying on the javascript injection trick.***
    45  
    46  ***This is a description of a workaround used in the [Psiphon Browser iOS app](https://github.com/Psiphon-Inc/endless) and not of what is implemented in TunneledWebView.
    47  TunneledWebView *does NOT* attempt to tunnel all audio/video content in UIWebView. This is only a hack which allows tunneling
    48  audio and video in UIWebView on versions of iOS which fetch audio/video out of process.***
    49  
    50  #### Background
    51  In [PsiphonBrowser](https://github.com/Psiphon-Inc/endless) we have implemented a workaround for audio and video being 
    52  fetched out of process.
    53  
    54  [PsiphonTunnel's](https://github.com/Psiphon-Labs/psiphon-tunnel-core/tree/master/MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel)
    55  HTTP Proxy also offers a ["URL proxy (reverse proxy)"](https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/631099d086c7c554a590b0cb76766be6dce94ef9/psiphon/httpProxy.go#L45-L70) 
    56  mode that relays requests for HTTP or HTTPS or URLs specified in the proxy request path. 
    57   
    58  This reverse proxy can be used by constructing a URL such as `http://127.0.0.1:<proxy-port>/tunneled-rewrite/<origin media URL>?m3u8=true`.
    59  
    60  When the retrieved resource is detected to be a [M3U8](https://en.wikipedia.org/wiki/M3U#M3U8) playlist a rewriting rule is applied to ensure all the URL entries
    61  are rewritten to use the same reverse proxy. Otherwise it will be returned unmodified.
    62  
    63  #### Fix
    64  
    65  * Media element URLs are rewritten to use the URL proxy (reverse proxy).
    66  * This is done by [injecting javascript](https://github.com/Psiphon-Inc/endless/blob/b0c33b4bbd917467a849ad8c51a225c2d4dab260/Endless/Resources/injected.js#L379-L408) 
    67  into the HTML [as it is being loaded](https://github.com/Psiphon-Inc/endless/blob/b0c33b4bbd917467a849ad8c51a225c2d4dab260/External/JiveAuthenticatingHTTPProtocol/JAHPAuthenticatingHTTPProtocol.m#L1274-L1280) 
    68  which [rewrites media URLs to use the URL proxy (reverse proxy)](https://github.com/Psiphon-Inc/endless/blob/b0c33b4bbd917467a849ad8c51a225c2d4dab260/Endless/Resources/injected.js#L319-L377).
    69  * If a [CSP](https://en.wikipedia.org/wiki/Content_Security_Policy) 
    70  is found in the header of the response, we need to modify it to allow our injected javascript to run.
    71    * This is done by [modifying the
    72  CSP](https://github.com/Psiphon-Inc/endless/blob/b0c33b4bbd917467a849ad8c51a225c2d4dab260/External/JiveAuthenticatingHTTPProtocol/JAHPAuthenticatingHTTPProtocol.m#L1184-L1228) 
    73  to include a nonce generated for our injected javascript, which is [included in the script tag](https://github.com/Psiphon-Inc/endless/blob/b0c33b4bbd917467a849ad8c51a225c2d4dab260/External/JiveAuthenticatingHTTPProtocol/JAHPAuthenticatingHTTPProtocol.m#L1276).
    74  
    75  *Requests to localhost (`127.0.0.1`) should be [excluded from being proxied](https://github.com/Psiphon-Labs/psiphon-tunnel-core/blob/master/MobileLibrary/iOS/SampleApps/TunneledWebView/External/JiveAuthenticatingHTTPProtocol/JAHPAuthenticatingHTTPProtocol.m#L283-L287) so the system does not attempt to proxy loading the rewritten URLs. They will be correctly proxied through PsiphonTunnel's reverse proxy.*
    76  
    77  ### Untunneled OCSP Requests
    78  
    79  See "Online Certificate Status Protocol (OCSP) Leaks" in [../../USAGE.md](../../USAGE.md).
    80  
    81  ### Untunneled WebRTC
    82  
    83  WebRTC in UIWebView does not follow NSURLProtocol and cannot be disabled without disabling JavaScript. If not disabled, 
    84  WebRTC will leak the untunneled client IP address and the WebRTC connection may be performed entirely outside of the
    85  tunnel.
    86  
    87  One solution would be to use a WebRTC library which allows setting a proxy; or allows all requests to be intercepted, and
    88  subsequently proxied, through NSURLProtocol.
    89  
    90  More details can be found in this issue: https://github.com/OnionBrowser/OnionBrowser/issues/117.
    91  
    92  ## Configuring, Building, Running
    93  
    94  The sample app requires some extra files and configuration before building.
    95  
    96  ### Get the framework.
    97  
    98  1. Run `pod install`
    99  
   100  ### Get the configuration.
   101  
   102  1. Contact Psiphon Inc. to obtain configuration values to use in your app. 
   103     (This is requried to use the Psiphon network.)
   104  2. Make a copy of `TunneledWebView/psiphon-config.json.stub`, 
   105     removing the `.stub` extension.
   106  3. Edit `psiphon-config.json`. Remove the comments and fill in the values with 
   107     those received from Psiphon Inc. The `"ClientVersion"` value is up to you.
   108  
   109  ### Ready!
   110  
   111  TunneledWebView should now compile and run.
   112  
   113  ### Loading different URLs
   114  
   115  Just update `urlString = "https://freegeoip.net"` in `onConnected` to load a different URL into `UIWebView` with TunneledWebView.
   116  
   117  ## License
   118  
   119  See the [LICENSE](../LICENSE) file.