출시 프로젝트에서 공공데이터포털의 투어 API를 사용했다.
HTTPS를 지원하는 API 서비스였기 때문에 출시 과정에서 문제없이 ATS를 사용할 수 있을 거라고 생각했지만
결국 보안 관련 이슈를 겪게됐고 문제의 원인과 해결 방법을 작성한 글이다.
1. 이슈를 겪게된 과정
나는 공공데이터포털에서 제공하는 오픈 API 서비스를 출시 앱에 사용하기 위해서
Alamofire를 통해 제공되는 URL로 네트워크 요청을 시도했는데 아래 콘솔 메시지가 출력됐다.
Result : FAIL
Error : Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."
요약하면 SSL
오류가 발생해서 서버로 보안 연결을 할 수 없다는 뜻이다.
같은 URL을 크롬 브라우저로 요청했을 때 정상적으로 응답이 왔었고 HTTPS 통신 역시
아무 문제가 없었는데 xcode나 다른 클라이언트로 요청하면 SSL
오류가 발생했다.
대표적으로 Insomnia에서 HTTPS 요청 시 아래 메시지가 출력된다.
Error: SSL peer certificate or SSH remote key was not OK
SSL(Secure Sockets Layer)
은 TLS가 표준화 되기 전 이름인데
TLS는 HTTPS 통신 시 서버와 클라이언트가 안전하게 데이터를 주고받게 해주는 역할이다.
두 사례에서 발견된 공통 문제는 "보안"이므로 여기에 초점을 맞춰 해결 방법을 찾았다.
2. 문제의 원인과 해결 방법
결론적으로 문제가 되는 것은 "보안"이므로 프로젝트에서 ATS 설정을 해제하고
HTTP 통신을 사용하면 쉽게 문제를 해결할 수 있지만 정확한 원인을 알고 싶었다.
그래서 ATS 사용 조건 중 어느 부분이 문제가 있는지 진단하기 위해서
터미널에 공공데이터포털의 도메인과 명령어를 입력했다.
$ nscurl -- ats-diagnostics --verbose https://apis.data.go.kr
이 명령어를 입력하면 자동으로 ATS 예외 조건들을 변경해가면서 해당 URL로 네트워크 요청한 결과를 알려준다.
내가 확인한 공공데이터포털 도메인의 경우 NSExceptionRequiresForwardSecrecy
의 값이false
일 때 요청 결과가 항상 성공임을 알 수 있었다.
그렇다면 ForwardSecrecy
가 뭘까?
이 개념을 이해하기 위해선 HTTPS 통신 과정(SSL Handshake
)을 조금 이해할 필요가 있다.
https 통신에서 서버와 클라이언트는 데이터를 암호화하기 위한 키를 주고 받는데,
대표적으로 RSA 알고리즘
을 사용한 키 교환 방식은 다음과 같다.
- 서버는 SSL 인증서를 통해 클라이언트에게 공개키를 전달한다.
- 클라이언트는 실제 데이터 암호화에 사용할 비밀키(대칭키)를
서버에게 받은 공개키를 사용해 암호화 한 뒤 서버에게 전달한다. - 서버는 가지고 있던 개인키로 비밀키(대칭키)를 해독해 클라이언트와 같은 비밀키를 가진다.
그런데 만약 누군가가 서버의 개인키를 탈취했고 암호화된 데이터를 가지고 있다면
탈취한 개인키로 암호화된 비밀키를 해독하여 암호화된 데이터를 복호화할 수 있게된다.
이런 단점을 보완한 키 교환 방식이DH 알고리즘
인데,
비밀키(대칭키) 자체를 교환하는게 아니라 비밀키(대칭키)를 만들기 위한 재료를 교환한다.
이 재료는 공개적으로 노출되어도 상관없고 키 교환 과정이 매우 간편하기 때문에
새로운 키를 만들기에 매우 용이하다.
따라서 이런 알고리즘의 특징을 이용해 일시적으로 사용하는 비밀키를 만들어서 그 키로 암호화하는 것을
FS(Forward Secrecy)
또는 PFS(Perfect Forward Secrecy)
라고 한다.
일회성 키를 생성할 수 있는 DH 알고리즘을 DHE라고 부른다. E는 Ephermeral 의 약자
꽤나 멀리 돌아왔지만 다시 한번 짚고 넘어가보자.
HTTPS 통신 과정 중에 서버와 클라이언트 사이에서 데이터 암호화를 위한 키 교환이 일어나고
어떻게 키를 교환하느냐에 따라 보안성이 달라진다는 것을 길게 설명했다.
그러니까 서버에서 HTTPS를 지원하더라도 ATS 사용을 위해서는 기본적으로 PFS
를 지원해야하며
그렇지 않은 경우 예외처리를 해야 오류가 발생하지 않는다.
그래서 정말로 서버 도메인이 PFS
를 지원하지 않는지 확인해봤다.
HTTPS 통신 시 FS
와 추가적으로 서버의 certificate chain
에도 문제가 있는 것을 발견했다.
Insomnia에서 발생한 오류는 아마도 이것 때문인 것 같다. (명확한 SSL 인증서 오류였기 때문)
그리고 크롬 브라우저에서는 이것을 내부적으로 처리해주기 때문에 정상적으로 통신이 가능했던 것 같다.
여담이지만 Handshake 시뮬레이션 결과 iOS는 다른 클라이언트와 다르게 대놓고 안된다고 뜬다...
결론적으로 프로젝트의 info.plist에서 해당 도메인에 대한 ATS 예외 설정을 통해 HTTPS 통신을 할 수 있었다.
물론 앞서 얘기했던 것 처럼 그냥 AllowsArbitraryLoads
키를 true
로 설정해도 출시에 걸림돌이 되진 않는다.
3. 참고 문서
https://developer.apple.com/forums/thread/128414
https://velog.io/@lhj26/ATSApp-Transport-Security
'IOS' 카테고리의 다른 글
[IOS] UIGestureRecognizer 사용해서 지도 조작하기 (0) | 2022.10.19 |
---|---|
[IOS] Realm 사용해서 데이터 저장하기 (0) | 2022.10.05 |
[IOS] NaverMap SDK 사용 중 알게된 Git LFS에 대하여 (0) | 2022.10.03 |
[IOS] CocoaPod의 pod install 오류에 대하여 (0) | 2022.09.09 |
[IOS] UIView의 tintColor 프로퍼티에 대하여 (0) | 2022.07.27 |