説明
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で保護されません。
対処方法
- 接続先を
https:にし、サーバーが同じリソースをHTTPSで直接提供することを確認してください。最初のリクエストの保護をリダイレクトに依存しないでください。 - ATSを有効に保ち、
NSAllowsArbitraryLoadsなどの広い例外を削除してください。避けられない例外は必要なホストと機能に限定し、できるだけ早く廃止してください。 - 開発・テスト用の接続先を環境設定で分離し、本番ビルドに含めないでください。プライベートアドレスやループバックも、本質的に安全とは扱わないでください。
- 証明書検証を無効にせず、
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で保護します。