안드로이드와 HTTP 통신
HTTP는 클라이언트와 웹서버가 서로 통신하기 위해 사용하는 프로토콜임.
HTTP는 평문으로 데이터를 주고받기 때문에 네트워크 보안 상 취약하다.
이런 점으로 인해 안드로이드는 Pie(9) 버전부터 기본적으로 HTTP 통신을 허용하지 않음.
그래서 안드로이드에서 HTTP 서버와 통신을 하려면AndroidManifest.xml
에 평문트래픽을 허용하도록 설정해줘야 함.
// AndroidManifest.xml
<application
...
// application 레벨에서 평문트래픽 허용 설정 추가 (http 통신 설정)
android:usesCleartextTraffic="true"
...
>
</application>
안드로이드와 HTTPS 통신
1. HTTPS 프로토콜과 TSL(SSL) 핸드쉐이크
평문으로 데이터를 주고받는 HTTP를 보완하고자
SSL/TLS 프로토콜 기반으로 데이터를 암호화 한, HTTPS 프로토콜
이 만들어졌음.
HTTPS는 비대칭키 알고리즘으로 데이터를 암복호화함.
데이터가 비대칭키로 암복호화되기 때문에
클라이언트와 서버는 통신하기 전에 서로의 암호화키를 주고받는 단계가 필요함.
근데 여기서 발생할수 있는 취약점이 있음.
공격자가 서버와 클라이언트가 암호화키를 주고받는 동안에 패킷을 탈취해서
서버의 암호화키로 데이터를 복호화하고 클라이언트에게는 자신의 암호화키를 제공하는 수법으로 데이터를 해킹할수 있다.
이걸 중간자공격(MITM)이라고 함.
그래서 HTTPS 서버는 클라이언트에게
나 공격자 아님. 너가 통신하려는 그 서버 맞음. 그니까 내가 주는 공개키 믿고 나랑 통신해도 됨.
라는걸 보장해주는 인증서를 제공함.
이걸 TLS인증서(SSL 인증서)
라고 함.
브라우저 앱에서 바로 확인 할 수 있음. (아래는 크롬 브라우저에서 TLS/SSL 인증서 확인하는 방법)
암튼 그리하여 서버와 클라이언트는 HTTPS 통신을 하기전에
- 서버가 클라이언트에게 자신이 신뢰할수 있는 서버라는 걸 알랴줌 (TLS/SSL 인증서)
- 서버와 클라이언트가 서로의 암호화 키를 전달 (데이터 암호화)
하는 과정을 거치며,
이 단계를 TLS(SSL) 핸드쉐이크라고 한다.
2. TSL(SSL) 인증서와 Root CA
아까 말했듯, TLS/SSL 인증서는 클라이언트에게 자신이 신뢰할수 있는 서버라는 걸 보장해주는 인증서임.
인증서가 신뢰를 받으려면 인증서가 발급되는 곳 또한 신뢰할 수 있어야 함.
서버의 인증서가 신뢰받을 수 있도록 검증하고 발급해주는 기관,
이것을 CA(Certificate Authority)
혹은 Root CA
라고 함.
안드로이드 시스템에는 공인된 Root CA의 인증서들이 미리 내장되어 있다.
안드로이드 문서 상으론 100개 이상의 Root CA 인증서가 내장되어있다고 함. (안드로이드 8.0 이상 기준)
궁금해서 adb 명령어로 직접 확인해봤는데 오 진짜 되게 많다. (130개 정도 되는거 가틈)
adb shell cat /system/etc/security/cacerts/* | grep Issuer:
넘 많아서 대중적으로 사용하는 인증기관 몇개만 추려봤음.
- AddTrust External CA Root
- Comodo RSA Certification Authority
- DigiCert Global Root CA
- GeoTrust Global CA
- GlobalSign Root CA
- GoDaddy Root Certificate Authority - G2
- Sectigo (formerly Comodo CA)
- Thawte Primary Root CA
- VeriSign Class 3 Public Primary Certification Authority - G5
암튼 그래서 HTTPS 통신하려는 서버가
공인된 Root CA에서 서명한 인증서를 쓰고 있다면
별도의 설정 없이 HTTP 통신 라이브러리를 통해 HTTPS 통신을 할 수 있다.
근데 아니라면?
안드로이드에서 통신하는 서버가 공인된 Root CA에서 서명한 인증서를 쓰고 있지 않다면?
이런 Exception이 쾅 떠버린다.
javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
근본적인 이 문제의 해결법은
통신하는 서버가 공인된 Root CA에서 서명한 인증서를 사용하면 됨.
근데 상황상 서버 인증서를 구입하고 적용하는데 시간이 좀 걸릴수 있고 (혹은 안될수도 있고,,)
서버에서 분명 RootCA 인증서를 사용하고 있는데도 인증서 구성에 따라 안드로이드에서 통신이 안될수 있음.
다음 글에선 다양한 상황 별로
안드로이드 https 통신 문제(SSLHandshakeException)에 대처할수 있는 방법에 대해 알아볼거임.
출처 및 참고 목록
https://yozm.wishket.com/magazine/detail/1852/
https://brunch.co.kr/@sangjinkang/47
https://opentutorials.org/course/228/4894
https://developer.android.com/privacy-and-security/security-ssl?hl=ko#HttpsExample
https://developer.android.com/privacy-and-security/security-config?hl=ko#TrustingAdditionalCas
'개발 > 안드로이드' 카테고리의 다른 글
안드로이드 백그라운드 정리 (thread와 handler) (0) | 2023.06.08 |
---|