🔥 패키지 컬렉션 보호하기

288자
4분

Swift Package Manager는 패키지 컬렉션의 보안을 강화하기 위해 서명 기능을 제공하고 있어요. 하지만 서명만으로는 다음과 같은 공격 벡터를 완벽히 방어할 수 없답니다:

  • 서명 제거: 공격자가 서명된 컬렉션에서 서명을 제거하면 unsigned collection으로 다운로드되어 서명 검사를 우회할 수 있어요.
  • 서명 교체: 공격자가 컬렉션을 수정한 후 다른 인증서로 다시 서명하면 서명이 유효한 한 SwiftPM이 이를 받아들일 수 있죠.

이러한 공격에 대비하기 위해 SwiftPM은 컬렉션 제작자가 다음과 같은 작업을 할 수 있도록 인증서 고정(certificate-pinning) 설정을 제공합니다:

  • 컬렉션에 대한 서명 검사 필수화 — "서명 제거" 공격 방어
  • 서명에 사용할 수 있는 인증서 제한 — "서명 교체" 공격 방어

컬렉션 제작자가 인증서 고정 설정을 정의하는 과정은 다음과 같아요:

  1. PackageCollectionSourceCertificatePolicy 파일을 수정하여 defaultSourceCertPolicies 딕셔너리에 새 항목을 추가하세요:
private static let defaultSourceCertPolicies: [String: CertificatePolicyConfig] = [
    // 패키지 컬렉션 URL의 "host" 부분을 키로 사용합니다.
    // 이 도메인에 호스팅된 모든 패키지 컬렉션에 서명이 필요합니다.
    "www.example.com": CertificatePolicyConfig(
        // 서명 인증서는 반드시 이 subject user ID를 가져야 합니다.
        certPolicyKey: CertificatePolicyKey.default(subjectUserID: "exampleUserID"),
        /*
         인증서의 base64 인코딩 문자열을 계산하려면:
         let certificateURL = URL(fileURLWithPath: <DER로 인코딩된 루트 인증서 파일 경로>)
         let certificateData = try Data(contentsOf: certificateURL)
         let base64EncoodedCertificate = certificateData.base64EncodedString()
         */
        base64EncodedRootCerts: ["<base64로 인코딩된 루트 인증서>"]
    )
]
swift
  1. Pull Request를 열어 검토를 요청하세요. 요청자는 자신의 신원과 도메인 소유권을 증명할 수 있어야 해요:
    • 요청자는 실제 인증서 파일(DER로 인코딩됨)을 제공해야 해요. SwiftPM 팀은 인증서 체인이 유효하고 PR에 제공된 값이 올바른지 확인할 거예요.
    • 요청자는 Pull Request를 참조하는 TXT 레코드를 추가해야 해요. SwiftPM 팀은 dig -t txt <DOMAIN> 명령을 실행하여 이를 확인할 거예요. 이는 도메인 소유권 증명 역할을 하죠.
  2. 변경 사항이 승인되면 다음 SwiftPM 릴리스에 반영될 거예요.

인증서 고정 설정은 웹 도메인과 연결되므로, 웹에 호스팅된(즉, URL이 https://로 시작하는) 서명된 컬렉션에만 적용할 수 있어요. 로컬 파일 시스템에서 발견된(즉, URL이 file://로 시작하는) 컬렉션에는 적용되지 않습니다.