目次
Session概要
アプリ内でWebにアクセスする場合は、そのプライバシーが非常に重要になります。Appleのプラットフォーム全体で暗号化DNSを活用することによってその情報を守り、アプリ内でプライベートかつ安全な接続性を提供しましょう。システムのDNS設定を使用して暗号化サーバに接続する、または標準的なネットワークAPIを使用してアプリ内で暗号化DNSを有効化する方法について https://developer.apple.com/videos/play/wwdc2020/10047/
DNSとプライバシーの重要性
- DNS(Domain Name System)とは
- SafariなどのWebページのアドレスを IPアドレスに変換するシステム
- SafariなどのWebページのアドレスを IPアドレスに変換するシステム

DNSとプライバシーの関係性
- 通常 DNSのリクエストとレスポンスは 未暗号化のUDPで送受信されるので、検索ページがネットワーク上の外部デバイスに知られる可能性がある
- UDP(User Datagram Protocol)
- 通信プロトコルの一つで、転送速度は高いが信頼性が低い
- UDP(User Datagram Protocol)
- 偽装も可能で、ローカルネットワークのDNSリゾルバーの信頼性が低いことも問題で公共のWi-Fiにアクセスした場合、追跡やブロックされる可能性がある

DNSの暗号化

- 暗号を使用してDNSのリクエストとレスポンス保護する
- AppleはDNS暗号化のサポートを開始
- 保護用のプロトコルは2つ
- DoTと呼ばれるDNS over TLS
- DoHと呼ばれるDNS over HTTPS
- 両方ともTLSを使用し、DNSメッセージを暗号化する
- DoHはHTTPを使用し、パフォーマンスを改善します
- DNSの暗号化2つの方法
- デフォルトのリゾルバーとしてすべてのアプリに 1つのDNSサーバーを選択する
- そうすることで、パブリックDNSサーバーの提供のため、システムを設定するNetworkExtensionアプリを作成可能
- もし MDM(モバイルデバイス管理)を使ってデバイス上の エンタープライズ設定を行うのであれば、プロファイルをプッシュダウンしネットワークに対し暗号化を設定可能
- アプリから直接オプトインする
- アプリに対してだけでも暗号化を望むなら、特定のサーバーを選択し選んだアプリの接続に使用可能
- アプリに対してだけでも暗号化を望むなら、特定のサーバーを選択し選んだアプリの接続に使用可能
- デフォルトのリゾルバーとしてすべてのアプリに 1つのDNSサーバーを選択する



システム全体のDNS設定

- 2つの設定方法
- NEDNSSettingsManagerを使用するNetworkExtensionアプリで設定
- DNSSettingsペイロードを含むMDMプロファイルで設定
- どちらも同じ内容を指定可能で、
- サーバーとプロトコルを特定するDNSサーバー設定
- 設定のタイミングをカスタマイズするネットワークルールのセット
- NetworkExtensionで サーバーコンフィグレーションを指定する
- NEDNSSettingsManagerオブジェクトで 既存のコンフィグレーションでロードする
- そうすれば、DoHかDoTサーバーのいずれかの設定を定義することができる
NetworkExtensionでのサーバーコンフィグレーション指定
// Create a DNS configuration
import NetworkExtension
// NEDNSSettingsManagerオブジェクトで 既存のコンフィグレーションでロード
NEDNSSettingsManager.shared().loadFromPreferences { loadError in
if let loadError = loadError {
// ...handle error...
return
}
let dohSettings = NEDNSOverHTTPSSettings(servers: [ "2001:db8::2" ])
dohSettings.serverURL = URL(string: "https://dnsserver.example.net/dns-query")
NEDNSSettingsManager.shared().dnsSettings = dohSettings
// これでユーザーはDNSサーバーを設定アプリ内で有効にできる
NEDNSSettingsManager.shared().saveToPreferences { saveError in
if let saveError = saveError {
// ...handle error...
return
}
}
}
コンフィグレーションの ネットワークルール
- ネットワークルールの指定により、別のネットワークとの互換性を保証する
- パブリックDNSサーバはローカルネットワーク上 だけのプライベートネームを解決しない
- 例えば、エンタープライズWi-Fiネットワーク上のDNSサーバーのみが従業員がアクセスするプライベートネームを解決する
- 互換性の中には、自動的に処理されるものもあり、ネットワークルールを指定する必要はな
- カフェなどのキャプティブネットワーク(ユーザ登録や通信料の支払いが必要な公共の Wi-Fi ネットワークのこと)は自動的に例外として検出される
- 同様にVPNがアクティブだとVPNトンネル内での解決にVPNのDNS設定が使用され、システム全体の設定ではありません
- ただし、エンタープライズWi-Fiネットワーク上の プライベートネームを処理するにはネットワークルールの設定が必要
- ネットワークルールは Wi-Fiやセルラー特定のWi-Fi SSIDのような ネットワークタイプの挙動を定義する
- 適合済みのネットワークでは、DNS設定を完全に無効にするか、特定のプライベートドメインに対してのみ例外を与えられる
- すなわち、アプリ内でネットワークルールを設定する方法でユーザーはこれらのルール設定が可能となる
- すなわち、アプリ内でネットワークルールを設定する方法でユーザーはこれらのルール設定が可能となる

// Apply network rules
// 社内ネットワークの例外作成のため、特定SSIDでWi-Fiのルールを定義
let workWiFi = NEOnDemandRuleEvaluateConnection()
workWiFi.interfaceTypeMatch = .wiFi
workWiFi.ssidMatch = ["MyWorkWiFi"]
workWiFi.connectionRules =
[ NEEvaluateConnectionRule(matchDomains: ["enterprise.example.net"],
andAction: .neverConnect) ]
// Disconnectルールでネットワークのカテゴリー全体で設定を無効
let disableOnCell = NEOnDemandRuleDisconnect()
disableOnCell.interfaceTypeMatch = .cellular
let enableByDefault = NEOnDemandRuleConnect()
NEDNSSettingsManager.shared().onDemandRules = [
workWiFi,
disableOnCell,
enableByDefault
]
XcodeでのDNS設定機能
- プロジェクト設定のSigning and Capabilitiesをクリック
- DNS設定機能は NetworkExtension機能の1つであるため、システムがサポートするプロトコルを設定する

DNS Blocking
- ネットワークによっては、ポリシーで暗号化サーバーをブロックするものもあり、クエリを見て トラフィックをフィルタリングする可能性がある
- これが発生するとWi-Fiネットワークにプライバシー警告が付く
- プライバシー侵害の前にアプリの接続が失敗となる
- プライバシー侵害の前にアプリの接続が失敗となる

アプリ単位でのDNS暗号化
- アプリからオプトインする場合、Networkフレームワークで PrivacyContexts を選ぶ

// Use encrypted DNS with NWConnection
import Network
let privacyContext = NWParameters.PrivacyContext(description: "EncryptedDNS")
if let url = URL(string: "https://dnsserver.example.net/dns-query") {
let address = NWEndpoint.hostPort(host: "2001:db8::2", port: 443)
privacyContext.requireEncryptedNameResolution(true,
fallbackResolver: .https(url, serverAddresses: [ address ]))
}
let tlsParams = NWParameters.tls
tlsParams.setPrivacyContext(privacyContext)
let conn = NWConnection(host: "www.example.com", port: 443, using: tlsParams)
conn.start(queue: .main)
// Validate which DNS protocol was used
import Network
conn.requestEstablishmentReport(queue: .main) { report in
if let report = report {
for resolution in report.resolutions {
// 使用したプロトコルの確認
switch resolution.dnsProtocol {
case .https, .tls:
print("Used encrypted DNS!”)
case .udp, .tcp:
print("Used unencrypted DNS")
default:
// Ignore unknown protocols
}
}
}
// Use encrypted DNS for other APIs
import Network
if let url = URL(string: "https://dnsserver.example.net/dns-query") {
let address = NWEndpoint.hostPort(host: "2001:db8::2", port: 443)
NWParameters.PrivacyContext.default.requireEncryptedNameResolution(true,
fallbackResolver: .https(url, serverAddresses: [ address ]))
}
let task = URLSession.shared.dataTask(with: ...)
task.resume()
getaddrinfo(...)