Foundationで作成するハードコードされたHTTP URL

Foundationで作成するハードコードされたHTTP URL

説明

Foundation.URL(string:) などで作った http:// アドレスを通信に使うと、TLSのない接続になる場合があります。URLオブジェクトの生成自体はネットワークリクエストではないため、実際の送信と保護設定を合わせて確認してください。

AppleのURL Loading Systemは、App Transport Security(ATS)によって平文HTTPを既定で遮断します。そのため、例外のない URLSession リクエストは通常失敗します。ただし、NSAllowsArbitraryLoads や NSExceptionAllowsInsecureHTTPLoads などの例外があるとHTTPが許可される場合があり、NetworkやCFNetworkなどの低レベルAPIにはATSが適用されないことがあります。URLの使用経路、Info.plist のATS設定、実行時の通信を合わせて確認してください。

想定される影響

有効な通信保護なしで接続できる場合、次の問題が起こるおそれがあります。

  • ネットワーク上の第三者によるリクエストや応答の読み取り
  • 通信内容や応答の改ざん
  • サーバーへのなりすましや意図しない接続先への誘導
  • 広範なATS例外による平文通信の許可範囲の拡大

HTTPからHTTPSへリダイレクトしても、最初のHTTPリクエストはTLSで保護されません。

対処方法

  1. 接続先を https: にし、サーバーが同じリソースをHTTPSで直接提供することを確認してください。最初のリクエストの保護をリダイレクトに依存しないでください。
  2. ATSを有効に保ち、NSAllowsArbitraryLoads などの広い例外を削除してください。避けられない例外は必要なホストと機能に限定し、できるだけ早く廃止してください。
  3. 開発・テスト用の接続先を環境設定で分離し、本番ビルドに含めないでください。プライベートアドレスやループバックも、本質的に安全とは扱わないでください。
  4. 証明書検証を無効にせず、Info.plist と実際の通信から、HTTP接続に成功する経路が残っていないか確認してください。

例

変更前

swift
import Foundation

func loadProfile() {
    guard let url = Foundation.URL(string: "http://api.example.com/profile") else {
        return
    }

    URLSession.shared.dataTask(with: url) { _, _, _ in }.resume()
}

変更後

swift
import Foundation

func loadProfile() {
    guard let url = Foundation.URL(string: "https://api.example.com/profile") else {
        return
    }

    URLSession.shared.dataTask(with: url) { _, _, _ in }.resume()
}

解説:

  • 変更前: HTTPの接続先がコードに固定されています。ATSが遮断する場合もあるため、例外設定と実際の通信の成否を確認してください。
  • 変更後: 直接利用できるHTTPS接続先を使い、リクエストの開始からTLSで保護します。

参考資料