Swift NWConnection에서 TLS/DTLS 없이 민감 정보 전송

Swift NWConnection에서 TLS/DTLS 없이 민감 정보 전송

설명

Apple Network.framework는 TCP, UDP, TLS, DTLS 같은 프로토콜을 직접 구성하는 하위 수준 네트워킹 API입니다. URL Loading System의 App Transport Security(ATS)는 Network.framework 연결에 적용되지 않으므로, 앱이 전송 보호와 피어 인증을 올바르게 구성해야 합니다.

Network.NWParameters.tls는 TLS와 TCP를, Network.NWParameters.dtls는 DTLS와 UDP를 사용합니다. 반면 Network.NWParameters.tcp와 Network.NWParameters.udp는 각각 TLS와 DTLS를 추가하지 않습니다. Network.NWParameters(tls: nil, tcp: ...) 또는 Network.NWParameters(dtls: nil, udp: ...)도 해당 보안 프로토콜을 명시적으로 제외합니다.

민감 데이터를 이 연결로 보내기 전에 실제 프로토콜과 피어 인증을 확인하세요. 전송 호출만으로 연결 성공이나 별도 애플리케이션 계층의 보호 여부까지 알 수는 없습니다.

잠재적 영향

상위 애플리케이션 프로토콜도 인증된 암호화를 제공하지 않는다면 다음 문제가 발생할 수 있습니다.

  • 네트워크 관찰자 또는 중간 장비가 인증 정보와 개인정보를 읽는 기밀성 침해
  • 능동적 공격자가 전송 데이터를 변경하는 무결성 침해
  • 공격자가 서버나 피어를 가장하는 인증 실패
  • 별도의 재전송 방지가 없을 때 캡처된 메시지를 다시 사용하는 공격

해결 방법

  1. TCP 연결에는 Network.NWParameters.tls 또는 nil이 아닌 TLS 옵션을 사용하고, UDP 연결에는 Network.NWParameters.dtls 또는 nil이 아닌 DTLS 옵션을 사용합니다.
  2. 시스템의 기본 서버 신뢰 평가를 유지합니다. 모든 인증서나 피어를 허용하는 검증 콜백을 설치하지 않습니다.
  3. HTTP 및 URL 기반 리소스에는 HTTPS와 URLSession을 사용하고, ATS 예외를 최소화합니다.
  4. 전송하는 민감 정보를 최소화합니다. 위협 모델이 TLS 종단점 너머까지 포함할 때만 독립적인 키 관리, nonce 고유성, 재전송 방지를 갖춘 애플리케이션 계층 인증 암호화를 심층 방어로 추가합니다. 이는 인증된 전송을 대체하지 않습니다.
  5. 릴리스 빌드의 네트워크 트래픽을 런타임에 캡처하여 평문 데이터와 예상하지 못한 프로토콜 경로가 없는지 확인합니다.

예시

변경 전

swift
import Dispatch
import Foundation
import Network

func sendCredential(clientSecret: Data) {
    let connection = Network.NWConnection(
        host: "api.example.com",
        port: 443,
        using: Network.NWParameters.tcp
    )
    let queue = DispatchQueue(label: "cleartext-connection")
    connection.start(queue: queue)
    connection.send(content: clientSecret, completion: .contentProcessed { _ in })
}

변경 후

swift
import Dispatch
import Foundation
import Network

func sendCredential(clientSecret: Data) {
    let connection = Network.NWConnection(
        host: "api.example.com",
        port: 443,
        using: Network.NWParameters.tls
    )
    let queue = DispatchQueue(label: "tls-connection")
    connection.start(queue: queue)
    connection.send(content: clientSecret, completion: .contentProcessed { _ in })
}

설명:

  • 변경 전: 포트 번호가 443이어도 Network.NWParameters.tcp 자체는 TLS를 추가하지 않습니다. 별도의 인증된 상위 프로토콜이 없다면 clientSecret이 보호되지 않습니다.
  • 변경 후: Network.NWParameters.tls가 기본 TLS와 TCP 프로토콜 스택을 구성합니다. 기본 서버 신뢰 평가를 비활성화하지 말고, 실제 애플리케이션에서는 연결 상태와 전송 오류도 처리해야 합니다.

참조