Encrypt DNS in iOS 14 applications

iOS 14 introduces support for both DNS over HTTPS and DNS over TLS standards. This article explains the benefits of using these standards and how to utilize them through NSURLSession.

Stavros Schizas

3 minute read

In iOS 14, Apple introduced support for passing the DNS queries over HTTPS (DoH) or TLS (DoT). So why bother encrypting DNS queries when HTTPS is widely in use? Because if someone (ISPs, on-path routers, law enforcement agency, etc.) is eavesdropping on your application’s unencrypted DNS queries, they will be able to map which API / services your application uses and potentially “map” your service.

You can read more about DoH and DoT here

Unencrypted DNS

To better understand how easy it is for someone to eavesdrop on unencrypted DNS queries, let’s run the following sample code:

import UIKit
import Network
import PlaygroundSupport

let url = URL(string: "https://stackoverflow.com/questions/24058336/how-do-i-run-asynchronous-callbacks-in-playground")!
let config = URLSessionConfiguration.default
config.requestCachePolicy = .reloadIgnoringLocalCacheData
config.urlCache = nil

let session = URLSession.init(configuration: config)
URLSession.shared.dataTask(with: url) { data, response, error in
    guard let data = data, error == nil else {
        print(error ?? "Unknown error")
        return
    }

    let contents = String(data: data, encoding: .utf8)
    print(contents!)
    PlaygroundPage.current.finishExecution()
}.resume()

PlaygroundPage.current.needsIndefiniteExecution = true

To eavesdrop on the DNS queries, we will use Wireshark, a well-known network protocol analyzer.

As you can see in the figure below, Wireshark mapped the service and its IP addresses used in the sample code easily.

Wireshark: DNS query and response

Moreover, since the DNS messages are unprotected, other attacks are possible:

  • Queries could be directed to a resolver that performs DNS hijacking.
  • Firewalls can easily intercept, block or modify any unencrypted DNS traffic based on the port number alone.

Encrypted DNS using DoH/DoT

Encrypted DNS (DoH or DoT) mitigates the privacy issue illustrated above. To decide which one is better to use, you can read multiple articles on the web that compare DoH to DoT, but it all boils down to these points:

  • DNS over TLS may seem faster as it’s one level lower, but based on benchmarks, that’s not the case.
  • It’s harder for mediators to monitor and censor DNS queries if it’s DNS over HTTPS. It looks like regular HTTPS traffic, while DNS over TLS requires separate port usage, namely: 853.
  • Even with encrypted DNS, TLS connections contain unencrypted domain names (SNI). TLS 1.3 mitigates it.

Based on the above, DoH is a definite winner. 🤖

On iOS 14, to make use of DoH, we need to configure the NWParameters.PrivacyContext with a DNS (which supports DoH) resolver’s central host HTTPS and its backup hosts IPs.

import UIKit
import Network
import PlaygroundSupport

enum DoHConfigurarion: Hashable {
    case cloudflare

    var httpsURL: URL {
        switch self {
        case .cloudflare:
            return URL(string: "https://cloudflare-dns.com/dns-query")!
        }
    }

    var serverAddresses: [NWEndpoint] {
        switch self {
        case .cloudflare:
            return [
                NWEndpoint.hostPort(host: "1.1.1.1", port: 443),
                NWEndpoint.hostPort(host: "1.0.0.1", port: 443),
                NWEndpoint.hostPort(host: "2606:4700:4700::1111", port: 443),
                NWEndpoint.hostPort(host: "2606:4700:4700::1001", port: 443)
            ]
        }
    }
}

let url = URL(string: "https://stackoverflow.com/questions/24058336/how-do-i-run-asynchronous-callbacks-in-playground")!
let secureDNS = DoHConfigurarion.cloudflare
NWParameters.PrivacyContext.default.requireEncryptedNameResolution(
    true,
    fallbackResolver: .https(secureDNS.httpsURL, serverAddresses: secureDNS.serverAddresses)
)

URLSession.shared.dataTask(with: url) { data, response, error in
    guard let data = data, error == nil else {
        print(error ?? "Unknown error")
        return
    }

    let contents = String(data: data, encoding: .utf8)
    print(contents!)
    PlaygroundPage.current.finishExecution()
}.resume()

PlaygroundPage.current.needsIndefiniteExecution = true

Running the sample code using DoH configuration resulted in Wireshark failing to pick up any of the DNS queries made.

🎉 🎊🎉 🎊🎉 🎊🎉 🎊🎉 🎊🎉 🎊

For applying encrypted DNS using the Network framework, you can take a look at Apple’s WWDC 2020 session: Enable encrypted DNS.

Many DNS resolvers, such as Google, Cloudflare, Alibaba, etc., support encrypted DNS. Therefore, we have created an enum that implements NWParameters.PrivacyContext configuration for each provider, for your convenience.

In summary, iOS14 added support for encrypted DNS and, in particular, DoH, which enhances privacy significantly. We strongly recommend using it in your applications, and if you still have concerns, Apple teamed up with Cloudflare and Fastly to further improve DoH by introducing Oblivious DoH.

The End.

comments powered by Disqus