Unveiling the Power of Proxies for Mobile Clients
Tags: ios, networking, architecture
Published: 2023-02-26 21:17:21

It's pretty common for mobile applications to participate in client-server communication. As a mobile developer, you may build apps that communicate with your own trusted server. However, there might be cases when you need to communicate with third-party servers. In such situations, you may not want to expose the IP address of your mobile client. To solve this issue, using a proxy server appears to be an obvious choice. So in this article, I'm going to show you one way you can use a proxy in your systems to improve privacy. And, based on my experience, there are a few things that mobile engineers might find helpful to navigate this topic further.


## Proxy 101

Proxy servers are quite helpful for a variety of reasons, such as content filtering or caching, but their main purpose is to provide privacy and security. While SSL and TLS already do a great job of securing communication, a proxy server can add an extra layer of protection.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6c381rqjty6dyip96to6.png" alt="Alt Text">
  <figcaption>Client-server with a proxy</figcaption>
</figure>

In a typical HTTPS connection between a client and a server without a proxy in the middle, the traffic is secured with the Transport Layer Security (TLS) protocol. When a client sends a request to the server, the TLS protocol ensures that the data is encrypted before it is transmitted over the network. Once the server receives the encrypted data, it decrypts it using a private key that only the server has access to.

However, even though the traffic is encrypted, the server can still see the IP address of the client, which may reveal sensitive information about the client's location or network configuration. This is where a proxy server or other techniques come into play to provide additional privacy and security.


## Proxy or VPN?

When you want to keep your IP address hidden, you have two popular options: a proxy server and a virtual private network (VPN). Here's how they work:

- A proxy server acts as an intermediary between the client and the server. This means that it forwards requests from the client to the server and then returns the server's response back to the client. The server sees the IP address of the proxy server instead of the client's, which provides an additional layer of privacy.
- A VPN creates a secure, encrypted connection between the client and a remote server. All traffic is routed through the remote server, which masks the client's IP address and provides an added layer of security. However, setting up a VPN can be more complex than using a proxy server. It may also conflict with the VPN proxy, block traffic that is not routed through the VPN tunnel, and require additional resources.

> To set up a VPN proxy with the [Network Extensions](https://developer.apple.com/documentation/networkextension) framework, you'll need to create a new Network Extension target in your Xcode project and implement a few delegate methods. You will also need to configure the tunnel provider with the details of your proxy server, such as its hostname and port number.



## The Many Shades of Proxies

Proxy servers have a long history. There are actually a bunch of different protocols you can use with them, like SMTP, SOCKS, and FTP. But for now, let's focus on HTTP(s).

The main thing to know about HTTP vs HTTPS proxies is that HTTPS uses SSL/TLS encryption to keep your data safe. That means when you use an HTTPS proxy, your data is encrypted from the moment it leaves your device until it reaches the server, which makes it a lot more secure.

On the other hand, HTTP proxies don't encrypt your data, so it's visible to anyone who might be snooping around. While they can be helpful for caching and filtering web traffic, they're not great for sending sensitive information. So if you're doing something like online shopping or sending private messages, it's definitely a good idea to use an HTTPS proxy.

It's worth mentioning that proxies come in all shapes and sizes, not just protocols. Did you know that even http(s) can have different types? The most common ones are forward and reverse proxies. A forward proxy acts as a middleman between a client and a server, while a reverse proxy acts as a middleman between a server and the internet.

#### Forward proxy
<table>  
  <tr>
    <td><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/guuko3a9fygaki1w50c4.png" alt="Alt Text" style="max-width: 100%; height: auto;"></td>
    <td>
      <ul>
        <li><small>Acts as an intermediary between a client and a server</small></li>
        <li><small>Client initiates the request</small></li>
        <li><small>Used to provide anonymity or bypass firewalls</small></li>
        <li><small>Commonly used for content caching and filtering</small></li>
        <li><small>Usually deployed in client networks</small></li>
      </ul>
    </td>
  </tr>
</table>

#### Reverse proxy
<table>
  <tr>
    <td><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/je8bewlzb2ss7hyptag8.png" alt="Alt Text" style="max-width: 100%; height: auto;"></td>
    <td>
      <ul>
        <li><small>Acts as an intermediary between a server and the internet</small></li>
        <li><small>Server initiates the request</small></li>
        <li><small>Used for load balancing, content caching, and enhancing security</small></li>
        <li><small>Commonly used to distribute traffic across multiple servers</small></li>
        <li><small>Usually deployed in server networks</small></li>
      </ul>
    </td>
  </tr>
</table>


Ensuring a well-distributed infrastructure and protecting client anonymity are crucial. To maintain anonymity, a significant number of clients should be hidden behind the proxy address. In practice, a combination of reverse-proxy and forward-proxy is often used. For simplicity, the examples below will only use one forward proxy.


## HTTP: Connecting ~~people~~ packets

Okay, so proxy servers are pretty popular these days. In fact, the HTTP protocol has a whole method just for them called [HTTP CONNECT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT). This method helps you create a safe tunnel through an unsafe network, like the internet. When you're using HTTP Connect to connect to a server, you send an HTTP CONNECT request to the proxy server, and you just need to let the proxy server know the hostname and port number of the server you want to reach.

The proxy server then establishes a two-way communication channel with the destination server and passes data between the client and server, allowing the client to communicate with the server securely. This method is commonly used to establish SSL/TLS encrypted connections between a client and server. It can be used for a variety of purposes, such as bypassing firewalls, establishing secure communication channels, and enabling remote access to internal networks.


<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jwu53jwx62mo36wzgzsi.png" alt="Alt Text">
  <figcaption>HTTP CONNECT setup</figcaption>
</figure>

If you're a mobile developer, you probably use methods like GET, POST, and PUT all the time. But have you ever used CONNECT? Let’s explore how to get [URLSession](https://developer.apple.com/documentation/foundation/nsurlsession) to use it, or whether you should go with a more hardcore library.

So check it, the first thing - you can totally set up a proxy address in the session configuration. No big deal, just wanted to give you the heads up.

```javascript
// Create a session configuration object
let config = URLSessionConfiguration.default

// Create a proxy object with your desired host and port
let proxy = [kCFNetworkProxiesHTTPSEnable: true,
             kCFNetworkProxiesHTTPSProxy: "your.https.proxy.host",
             kCFNetworkProxiesHTTPSPort: 8080] as [String: Any]

// Set the proxy on the session configuration
config.connectionProxyDictionary = proxy

// Create an NSURLSession with the configuration
let session = URLSession(configuration: config)
```

One way to understand what's happening under the hood is by intercepting the traffic using Wireshark or any other tool you prefer. Alrighty, just fire off a GET request to your fave endpoint with this session and we're good to roll. 

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l6f945ta48ys26m0580l.png" alt="Alt Text">
  <figcaption>Tcp dump from the wireshark</figcaption>
</figure>

So get this, tcp dump shows that the client is actually sending a CONNECT for us behind the scenes. Pretty good!

Setting up Android is just as easy and you'll still get the same results.

```javascript
// Create a URL object for the destination server
val url = URL("https://www.example.com")

// Create a Proxy object with your desired host and port
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("your.https.proxy.host", 8080))

// Open a connection to the URL with the proxy
val connection = url.openConnection(proxy) as HttpURLConnection
```


## Houston, We Have a Problem (Again)

Alright, so is the case all wrapped up? Or is there still more to it? Actually, on top of the VPN, iOS/Android has a nifty feature that lets you use a system-level proxy setting for a specific Wi-Fi network. This is mainly used by big-shot companies that have their own devices to manage. But this led us to a new issue with changing the system proxy configuration: when you set a new proxy config through session configuration, it overwrites the user's current settings for any requests handled by those sessions.

> Note that by overriding, we only mean session-level requests (i.e., requests served during your app session) rather than app or device-level requests, which will not be affected.


You might decide to override the default settings, but this could have the following consequences:

- No connectivity, as the ISP/network can require all traffic to go through the proxy.
- Loss of privacy for the user, as they may be using the proxy for additional privacy.
- Malfunction of some features (e.g. payment due to geo-blocking).

Okay, so let's say we want to keep both proxies, right? No worries, because the cool thing about network protocols is that you can layer them on top of one another, which makes them really powerful. One way to do this is by nesting one tunnel inside another. For example, you can open one connect tunnel through the system proxy and then nest it inside a second tunnel that goes through a forward proxy.

The diagram from before will be updated in the following manner

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oij1p463znxvswwvh608.png" alt="Alt Text">
  <figcaption>Double HTTP CONNECT setup</figcaption>
</figure>

So, the diagram might seem a bit more complicated, but it's actually just duplicating the same mechanism for two proxies. The only issue is that the default iOS/Android libraries don't support this out of the box, so we'll need to put in some extra work. To get around this, we can go one level down and use [Network.framework](https://developer.apple.com/documentation/network) on iOS, subclass NWConnection, and handle it manually.


## So Much to Proxy, So Little Time

Alright, let's wrap up this article so it doesn't drag on. We've gone over how using proxies on mobile clients can improve  security and privacy for our users. We also talked about the differences between VPNs and proxy servers, and delved into the two most common types of proxies: forward and reverse proxies. Lastly, we checked out client libraries and how they can help with proxies, as well as their limitations.

Keep an eye on the next article where we'll try to mix and match proxies. We'll be using NWConnection and might even do some byte juggling. Stay tuned!