[iOS] SSL 핸드쉐이크 실패 디버깅
It looks like only the source citation was provided. Could you please share the full text you’d like translated? Once I have the content, I’ll translate it into Korean while preserving the original formatting and markdown.
문제: 예상치 못한 구성 충돌
최근 모니터링 대시보드에 간헐적인 네트워크 오류 로그가 표시되기 시작했습니다. 일반적인 404나 500 오류가 아니라, SSL Handshake Failures라는 특정 원인으로 지목되는 파편화된 저수준 오류였습니다.
이는 우리 ATS(App Transport Security) 설정이 완전히 관대하게 보였기 때문에 예상 밖이었습니다. Info.plist에서 NSAllowsArbitraryLoads를 true로 명시적으로 설정했습니다.
NSAppTransportSecurity
NSAllowsArbitraryLoads
이 설정은 이론적으로 ATS 검사를 우회하여 자체 서명 인증서나 오래된 TLS 버전을 사용하는 서버와의 연결을 허용하도록 되어 있습니다. 그러나 이 구성을 적용했음에도 불구하고 지속적인 TLS/SSL 네트워크 오류가 계속 발생했습니다.
문서를 파헤쳐 보니, Apple의 구성 규칙에 숨겨진 오버라이드가 있다는 것을 발견했습니다.
발견: InWebContent 오버라이드
근본 원인은 WebView에 대해 활성화한 또 다른 키인 **NSAllowsArbitraryLoadsInWebContent**에 있었습니다.
우리는 인‑앱 브라우저에서 혼합 콘텐츠를 허용하기 위해 이를 활성화했습니다. 그러나 Apple 문서에 중요한 내용이 명시되어 있습니다:
“
NSAllowsArbitraryLoadsInWebContent가 존재하면,NSAllowsArbitraryLoads의 값은 NO로 재정의됩니다.”
iOS 10+을 타깃으로 하고 있기 때문에, InWebContent 키가 존재하는 것만으로도 전역 “모두 허용” 설정이 조용히 무시되었습니다.
- WebView 내부: 임의 로드가 허용되었습니다.
- 네이티브 네트워킹 (API 호출, 이미지 로드): 전역 플래그가 무시되어 ATS가 기본값인 엄격 모드로 돌아갔습니다.
이는 우리가 임의 로드를 허용하려는 의도와는 달리, 모든 API 호출에 대해 엄격한 ATS 정책(TLS 1.2+, Forward Secrecy 필요)이 적용된다는 의미였습니다.
Why TLS Settings Were the Suspect
Once it became clear that strict ATS was active, the “SSL Handshake Failure” logs made perfect sense.
- The App (Client): Enforcing TLS 1.2 or higher (ATS default).
- The Server: A legacy server capable of speaking only TLS 1.0.
Result: Negotiation failed. Connection dropped.
We were inadvertently blocking our own legacy servers because the app’s security standards were silently defaulted to maximum.
오해: “보안 없음” ≠ “구식 프로토콜”
이 문제를 해결하기 위한 일반적인 방법은 문제 도메인에 대해 NSExceptionAllowsInsecureHTTPLoads 를 활성화하는 것입니다. “보안이 없는 로드”를 허용하면 TLS 버전 요구 사항을 포함한 모든 검사가 비활성화된다고 종종 생각합니다.
이는 잘못된 이해입니다.
NSExceptionAllowsInsecureHTTPLoads 은 지정된 도메인에 대해 HTTP(암호화되지 않은) 연결을 허용하지만, 다음을 하지 않습니다:
- TLS 버전 요구 사항을 낮추지 않음(HTTPS는 여전히 TLS 1.2가 필요합니다).
- 인증서 검증을 우회하지 않음(자체 서명되었거나 만료된 인증서는 여전히 실패합니다).
서버가 TLS 1.0만 지원한다면, 이 설정과 관계없이 핸드셰이크는 여전히 실패합니다.
해결책: 정밀 구성
전역 “Allow All”을 강제로 적용하려는 시도(일반적으로 좋지 않은 관행)를 피하고, 정밀한 수정을 적용했습니다.
목표는 다음과 같습니다:
- 보안을 높게 유지: 인증서 검증은 계속 활성화되어야 합니다.
- 호환성 장벽 완화: 특정 레거시 도메인에 대해 오래된 프로토콜을 명시적으로 허용합니다.
다음은 최종 Info.plist 구성입니다:
NSExceptionDomains
legacy-api.example.com
NSExceptionMinimumTLSVersion
TLSv1.0
NSExceptionRequiresForwardSecrecy
NSIncludesSubdomains
이 구성은 앱이 인증서를 엄격히 확인하도록 지시하면서도, TLS 1.0 프로토콜을 사용하는 연결을 허용하도록 합니다.
Deploy & Next Steps
업데이트된 구성이 배포되었습니다. 가설이 맞다면 해당 레거시 도메인에 대한 SSL/TLS 오류가 사라져야 합니다. 오류가 계속된다면 문제에 또 다른 층이 있을 수 있습니다—예를 들어 암호 스위트 불일치나 중간 인증서 문제일 수 있습니다.
결과와 함께 이 글을 업데이트하겠습니다. 이 이야기가 끝이 되길 바랍니다! 🤞
Summary
- 오버라이드 주의:
NSAllowsArbitraryLoadsInWebContent는NSAllowsArbitraryLoads를 조용히 비활성화합니다. - 키를 알아두세요:
NSExceptionAllowsInsecureHTTPLoads는 HTTP 연결을 허용하지만 TLS 버전 문제에는 **NSExceptionMinimumTLSVersion**이 필요합니다. - 구체적으로 설정하세요: 보안을 전역적으로 비활성화하지 마세요. 실제로 필요한 도메인에만 예외를 구성하십시오.