ハイライト
Apple は iOS 17 と macOS Sonoma に新しい Network Relay API を提供しました。開発者は MASQUE と Oblivious HTTP プロトコルを使って App のネットワークトラフィックにプライバシー保護レイヤーを追加でき、企業管理者は従来の VPN に代わる軽量な方法として、社内リソースへの安全なアクセスにリレーを利用できます。
主要内容
問題:VPN がすべてのシナリオに最適ではない理由
ネットワークトラフィックを保護したい開発者にとって、従来の選択肢は限られています。何もせずユーザーの IP アドレスをサーバーに晒すか、VPN を使うかの二択ですが、VPN には固有の問題があります。
- スコープが広すぎる:VPN は通常デバイス全体のトラフィックを引き受け、App は自分が関心のあるリクエストだけに保護を適用できません。
- ユーザー体験が悪い:VPN 接続は遅く、ネットワーク切り替え時に再接続が必要で、ユーザーが手動でオン/オフする必要があります。
- 信頼モデルが理想的でない:VPN プロバイダーはユーザーの実 IP とアクセス先を見えるため、プライバシーを中間者に委ねることになります。
企業シナリオでも、VPN の設定と配布は IT チームの負担です。従業員は VPN クライアントのインストール、設定入力、切断時の再接続対応が必要です。
Apple のアプローチ:ネットワークリレー
Apple は iOS 17 / macOS Sonoma で Network Relay サポートを導入しました。リレーは IETF 標準化された2つのプロトコルに基づく特殊なプロキシサーバーです。
- MASQUE:任意の TCP と UDP 接続をプロキシでき、バックエンドサーバーの変更は不要です。
- Oblivious HTTP:HTTP トラフィック専用に設計され、REST API シナリオに適しています。
リレーの中核的な利点はチェーン(chain)できることです。2つのリレーサーバーを設定できます。1つ目はユーザーの IP を知るがコンテンツは暗号化されているため内容を知らない。2つ目はアクセス内容を知るがユーザー IP を知らない。どの単一の主体も両方を同時に得られません。これが iCloud Private Relay の裏側技術です。
開発者にとっては、デバイス上の他のトラフィックに影響せず、自分の App だけにリレーを設定できます。企業にとっては、VPN より軽量で、接続が速く、指定ドメインのトラフィックだけをプロキシし、既存の ID プロバイダーと統合できます。
詳細
App 内で単一リレーを設定する
リレーの設定は数行のコードで済みます。Network framework で ProxyConfiguration オブジェクトを作成します(04:52):
import Network
let relayEndpoint = NWEndpoint.url(URL(string: "https://relay.example.com")!)
let relayServer = ProxyConfiguration.RelayHop(http3RelayEndpoint: relayEndpoint)
let relayConfig = ProxyConfiguration(relayHops: [relayServer])
キーポイント:
NWEndpoint.urlはリレーサーバーの URL を受け取り、プロトコルは HTTPS である必要がありますRelayHopはリレーチェーンの1ホップを表し、http3RelayEndpointはリレーとの通信に HTTP/3 を指定しますProxyConfigurationのrelayHopsは配列で、シングルホップまたはマルチホップ(chain)をサポートします- 上記コードは設定オブジェクトを作成するだけで、まだ接続には適用されていません
3つの利用方法:Network framework、URLSession、WebKit
リレー設定は Apple の3つの主要ネットワーク API に注入できます。
方法1:Network framework(05:40)
import Network
let relayEndpoint = NWEndpoint.url(URL(string: "https://relay.example.com")!)
let relayServer = ProxyConfiguration.RelayHop(http3RelayEndpoint: relayEndpoint)
let relayConfig = ProxyConfiguration(relayHops: [relayServer])
var context = NWParameters.PrivacyContext(description: "my relay")
context.proxyConfigurations = [relayConfig]
let parameters = NWParameters.tls
parameters.setPrivacyContext(context)
let connection = NWConnection(host: "www.example.com", port: 443, using: parameters)
connection.start(queue: .main)
キーポイント:
NWParameters.PrivacyContextは iOS 17 / macOS Sonoma で追加された型で、プライバシー設定をカプセル化しますproxyConfigurationsはProxyConfigurationの配列を受け取りますsetPrivacyContextでプライバシーコンテキストを接続パラメーターにバインドします- カスタムプロトコルや非 HTTP トラフィックなど、低レベル制御が必要なシナリオに適しています
方法2:URLSession(06:07)
import Network
let relayEndpoint = NWEndpoint.url(URL(string: "https://relay.example.com")!)
let relayServer = ProxyConfiguration.RelayHop(http3RelayEndpoint: relayEndpoint)
let relayConfig = ProxyConfiguration(relayHops: [relayServer])
let config = URLSessionConfiguration.default
config.proxyConfigurations = [relayConfig]
let mySession = URLSession(configuration: config)
let url = URL(string: "https://www.example.com/api/v1/employees")!
let (data, response) = try await mySession.data(from: url)
キーポイント:
URLSessionConfigurationにproxyConfigurationsプロパティが追加されました- 設定後、その
URLSessionのすべてのリクエストがリレー経由でルーティングされます - Swift concurrency の
async/awaitAPI でデータを取得します - サーバーはリレーの IP アドレスしか見えず、ユーザーの実 IP は取得できません
方法3:WebKit(06:30)
import Network
let relayEndpoint = NWEndpoint.url(URL(string: "https://relay.example.com")!)
let relayServer = ProxyConfiguration.RelayHop(http3RelayEndpoint: relayEndpoint)
let relayConfig = ProxyConfiguration(relayHops: [relayServer])
let webkitConfig = WKWebViewConfiguration()
webkitConfig.websiteDataStore = WKWebsiteDataStore.nonPersistent()
webkitConfig.websiteDataStore.proxyConfigurations = [relayConfig]
let webView = WKWebView(frame: .zero, configuration: webkitConfig)
let url = URL(string: "https://www.example.com/api/v1/employees")!
webView.load(URLRequest(url: url))
キーポイント:
WKWebsiteDataStoreにproxyConfigurationsプロパティが追加されましたnonPersistent()データストアを使用するため、cookie やキャッシュを保持せず、プライバシーが向上します- WebView 内のすべてのネットワークリクエストがリレー経由になります
- OAuth ログインフローなど、内蔵ブラウザーシナリオに適しています
企業シナリオ:構成プロファイルでリレーをデプロイ
企業は従業員に手動設定をさせる必要はありません。管理者は MDM(モバイルデバイス管理)で構成プロファイルを配布できます(09:15):
<dict>
<key>PayloadType</key>
<string>com.apple.relay.managed</string>
<key>Relays</key>
<array>
<dict>
<key>HTTP3RelayURL</key>
<string>https://relay.example.com</string>
<key>PayloadCertificateUUID</key>
<string>5AB702EC-32F3-48A9-94FE-8EA1C67ACF46</string>
</dict>
</array>
<key>MatchDomains</key>
<array>
<string>internal.example.com</string>
</array>
</dict>
キーポイント:
PayloadTypeはcom.apple.relay.managedで、新しい構成プロファイルタイプですHTTP3RelayURLでリレーサーバーアドレスを指定しますPayloadCertificateUUIDは同一プロファイル内の証明書を参照し、TLS 検証に使いますMatchDomainsでリレーがプロキシするドメインを限定し、他のトラフィックには影響しません- VPN からの大きな改善:必要なトラフィックだけをプロキシし、全体ではありません
企業シナリオ:NetworkExtension でプログラム的に設定
企業独自の管理 App がある場合、NetworkExtension フレームワークでプログラム的にリレーを設定できます(09:42):
import NetworkExtension
let newRelay = NERelay()
let relayURL = URL(string: "https://relay.example.com:443/")
newRelay.http3RelayURL = relayURL
newRelay.http2RelayURL = relayURL
newRelay.additionalHTTPHeaderFields = ["Authorization" : "PrivateToken=123"]
let manager = NERelayManager.shared()
manager.relays = [newRelay]
manager.matchDomains = ["internal.example.com"]
manager.isEnabled = true
do {
try await manager.saveToPreferences()
} catch let saveError {
// Handle error
}
キーポイント:
NERelayは NetworkExtension フレームワークの新しいクラスで、リレー設定を表します- HTTP/3 と HTTP/2 の両方をサポートし、フォールバックとして使えます
additionalHTTPHeaderFieldsでカスタム HTTP ヘッダーを追加し、認証(Authorizationtoken など)に使えますNERelayManager.shared()はシングルトンで、システム全体のリレー設定を管理しますmatchDomainsでリレーの適用範囲を指定ドメインに限定しますsaveToPreferences()で設定をシステムに永続化し、ユーザー承認が必要です
重要ポイント
-
ヘルスケア/金融系 App にネットワークプライバシー保護を追加:機密データ(健康記録、財務情報、位置データ)を扱う App では、
URLSessionConfiguration.proxyConfigurationsでリレーを設定し、サーバーがユーザーの実 IP を取得できないようにします。価値がある理由:プライバシー規制(GDPR、CCPA)はデータ収集・処理に厳格な要件を課し、IP を隠すことはコンプライアンスリスク低減に有効です。始め方:MASQUE 対応のリレープロバイダーを選び、URLSessionConfigurationでproxyConfigurationsを設定し、サーバーログにリレー IP しか見えないことを確認します。 -
社内 API アクセスで企業 VPN をリレーに置き換え:企業 App が社内リソースにアクセスする際、従業員に VPN クライアントをインストールさせる必要はありません。MDM で
com.apple.relay.managed構成プロファイルを配布し、リレーはMatchDomainsのドメインだけをプロキシします。価値がある理由:VPN は接続が遅く、切断時に手動再接続が必要で、非企業トラフィックを妨げます。リレーはこれらの課題を回避します。始め方:MASQUE 対応リレーサーバーを構築し、構成プロファイルを作成、MDM でプッシュし、NERelayManagerまたは URLSession で利用します。 -
two-hop リレーアーキテクチャでより強いプライバシー保護:
relayHops配列に2つのRelayHopを設定します。1つ目はユーザー IP を知るがコンテンツは見えない、2つ目はコンテンツを見るがユーザー IP を知りません。価値がある理由:シングルリレーではプロバイダーが「誰か」と「何にアクセスしているか」の両方を知ります。two-hop では単一主体が両方を関連付けられません。始め方:2つの異なるリレープロバイダーを選び、2つのRelayHopをProxyConfiguration(relayHops: [hop1, hop2])に渡します。 -
WebView コンテンツにネットワーク分離を追加:App 内に WebView でサードパーティーコンテンツを表示する場合、
WKWebsiteDataStore.nonPersistent()とproxyConfigurationsを組み合わせ、WebView のリクエストをリレー経由にし、ローカルデータを保持しません。価値がある理由:内蔵ブラウザーはプライバシー漏洩の温床です。始め方:WKWebViewConfigurationを作成し、websiteDataStoreをnonPersistent()に設定してproxyConfigurationsを構成します。 -
カスタム HTTP ヘッダーでパスワードレス認証:
NERelay.additionalHTTPHeaderFieldsでAuthorizationヘッダーを追加し、リレーサーバーがパスワードなしでリクエスト元を検証できます。価値がある理由:従来の VPN は追加のユーザー名/パスワード認証が必要です。カスタム HTTP ヘッダーは SSO と統合し、無感知認証を実現できます。始め方:企業 IdP で API token を生成し、additionalHTTPHeaderFieldsで渡し、リレーサーバー側で token を検証します。
関連セッション
- Reduce network delays with L4S — L4S はネットワーク遅延を下げる新技術。リレーと組み合わせてプライバシーと性能を同時に改善できます
- Build robust and resumable file transfers — URLSession の大容量ファイル転送機能。リレー設定はこれらの転送に直接適用できます
- What’s new in managing Apple devices — デバイス管理の新機能。リレー構成プロファイルの MDM 配布を含みます
- Explore advances in declarative device management — 宣言型デバイス管理の更新。企業がリレーをデプロイする基盤です
コメント
GitHub Issues · utterances