“인증서 문제라면, https로 호출하던 url을 http로 호출하면 되지 않을까?” 라는 생각이 들어서 로컬 환경에서 테스트해보았다.
물론 좋은 방법은 아니라서 이 방법으로 해결하려고 한 것은 아니고, http로 바꾸면 어떻게 될지 궁금해서 시도해보았다. 하지만 http로 바꿔 호출해도 지도는 로드되지 않았다. API 내부에서도 https로 다른 url들을 호출하고 있어서 제대로 동작하지 않는 것 같았다. 아마 내부적으로 https를 사용하고 있지 않다면, 이 방법으로 로컬에서 간단하게 확인해 볼 수는 있을 것 같다.
앞서 브라우저에서 API 호출 테스트를 했을 때 나오는 오류창은 브라우저에서 SSL 인증서를 신뢰하지 않을 때 발생한다고 한다. 브라우저에 따라 조금씩 다른 말로 표현하긴 하지만, 결국 인증서가 없거나 불안정하다는 의미이다.
이 문제를 이해하기 위해서는 다음 선행 지식들이 필요하다.
브라우저는 왜 인증서를 확인하고 이런 경고를 보낼까?
이전에 https에 대해 공부하면서, https는 SSL 인증서를 사용해서 보안을 강화한다는 사실을 알 수 있었다. (이 과정을 모른다면 여기에서 다루고 있으니 참고 바란다.)
간단하게 다시 정리하자면, SSL 인증서는 요청하는 사이트(서버)가 신뢰할 수 있는지를 확인하는 데 사용된다. 따라서 인증서가 없거나 유효하지 않다면, 해당 사이트를 신뢰할 수 없다는 것을 의미한다. 이런 사이트들은 유해 사이트일 수 있기 때문에, 브라우저는 오류창을 통해 사용자에게 위험성을 미리 알려주는 것이다.
그럼 어떻게 인증서의 유효성을 확인할까?
인증서에는 크게 (1) 해당 기관(서버, 사이트 등)에 대한 정보와 (2) 공개키 그리고 (3) 인증서의 내용을 해시화한 값을 암호화한 값(서명값, Signature)이 들어있다. 암호화에는 CA(Certificate Authority)가 가진 개인 키가 사용된다. 따라서 CA의 공개키를 통해 복호화가 가능하다면, 해당 CA가 발급한 인증서라는 것을 증명할 수 있다. 일반적으로 CA의 공개 키는 컴퓨터에 이미 설치되어 있는 경우가 많다. (Mac OS라면 키체인에 있을 것이고, 웹 브라우저에도 CA의 공개키가 내장되어 있다.)
참고로 인증서의 내용을 해시화하는 이유는 인증서 위변조를 확인할 수 있기 때문이다. 해시는 일반적으로 같은 입력에 대해 같은 출력을 보장한다. 만약 CA의 공개키로 복호화해서 얻어낸 인증서의 해시 값과 원래 인증서의 내용을 해시화한 값이 다른 경우 인증서의 내용이 변조되었음을 의미한다.
인증서는 계층 구조로 되어있다. (보통 3계층 구조로 되어 있다고 한다.)
이러한 계층 구조는 “상위 계층의 인증서가 신뢰할 수 있는 기관이라면, 해당 인증서의 비밀 키로 암호화된 하위 인증서 또한 신뢰할 수 있다.”는 사실을 이용해 강력한 인증 체계를 구축한다. 이를 Chain of Trust 라고 한다.
특히 지금과 같이 중간 인증 기관이 있는 구조에서는 더욱 강력한 인증 체계를 구축할 수 있다.
Quora6 및 Stack Overflow의 답변에 의하면, 인증을 수행하는 기관의 인증서가 손상되거나 비밀키가 유출될 경우 이를 철회 (revoke) 할 수 있도록 ICA라는 중간 단계를 두었다고 한다. Root 인증서가 직접 개인 인증서에 서명하는 것에 비해 한 단계 인증 Layer가 더 존재하게 되므로, 더욱 강력한 보안 체계를 구축할 수 있게 된다.
이제 다시 원래 문제로 돌아와보자.
문제는 API가 가지고 있는 인증서를 브라우저에서 신뢰하지 못한다는 것이고, 이는 인증서 계층 구조에 따라 루트 인증서를 신뢰하지 못한다는 뜻으로 해석할 수 있다. 다양한 이유(인증서 기간 만료, 인증서 위변조, 인증서 발급 기관을 신뢰할 수 없음 등)가 있지만, 결과적으로 이 루트 인증서를 신뢰할 수 있도록 만들어주면 문제는 해결될 수 있다.
루트 인증서 기간이 만료된 것이라면, 자동 업데이트 기능이 꺼져 있을 수 있으니 여기를 확인해서 인증서 업데이트를 받아주면 된다. 인증서가 위조 혹은 변조되었다면, 그 사이트는 신뢰할 수 없는 사이트이니 접속하지 않는 편이 좋겠다.
하지만 내 경우는 기존에도 계속 사용하고 있었고, 사무실 이사한 후에 내부망 설정 문제라고 생각해서 우선 내 폰에서라도 확인할 수 있도록 조치가 필요했다.
클라이언트(개인 기기나 브라우저)에서는 루트 인증서를 설치/활성화하여 인증서를 신뢰하도록 설정할 수 있다.
대신 설치한 클라이언트에서만 신뢰할 수 있어서, 확인하고자 하는 모든 클라이언트에 설치를 해야 한다.
위의 방법으로 전부 해결되면 좋겠지만, 내부망을 잡고 개발앱을 확인하는 사람마다 이 인증서를 설치 해야 하는 번거로움이 있다. 그래서 결과적으로는 인증서에 포함되어 있는 URL(도메인)에 대한 접근만 제한적으로 허용하도록 내부망 설정을 변경하는 작업이 필요하다. 이거는 내가 할 수 있는 부분은 아니고 보안팀을 통해서 진행해야 하기 때문에 따로 요청해서 처리했다.
내부망을 잡고 네이버(www.naver.com)의 인증서를 확인하면, 실제 네이버의 인증서와는 다른 경로를 보인다. 아마 허용된 몇몇 사이트 외에는 내부적으로 인증서를 바꿔서 전달하는 것 같다.
마지막으로 하나 의문점은 “왜 노트북에서는 문제가 없었는가?” 이다.
나중에 알고 보니 노트북에는 처음에 세팅할 때 사설 인증서를 적용해주는 프로그램을 설치해서 가능했던 것이다. (자동으로 필수 소프트웨어가 깔려서 미처 알지 못했다.) 모바일은 이런 프로그램이 없어서 직접 인증서를 설치해야 문제가 없었다.
원인을 파악하기 조금 까다로웠지만, 그래도 알고 나서는 해결이 어렵지 않아서 다행이었다.
혹시 웹뷰에서 비슷한 현상이 있다면, 인증서 문제가 있는 것은 없는지 확인해보는 것이 좋을 것 같다.
사실 https를 공부하면서 인증서는 “핸드쉐이킹에 필요한 정보들을 가지고 있는 문서” 정도로만 추상적으로 이해했었는데, 직접 눈으로 보니 https에 대한 이해도 더 잘되는 것 같다. 새로운 내용을 알 수 있는 좋은 기회였다!