Square OkHTTP와 Android SSLContext 문제
Square에서 만든 OkHttp는 안드로이드를 위해 만들어진 HTTP 클라이언트로 SDK가 제공하는 Apache HttpClient에 비해 사용이 간편하고 효과적이며 (Connection Pooling, Response Caching, Transparent GZIP Supports, etc.) 구글이 개발한 개방형 네트워크 프로토콜인 SPDY를 지원하는 것이 특징입니다. 최근 들어 OkHttp를 사용하는 프로젝트가 많아지고 있는 추세이며 저또한 최근의 프로젝트에서 OkHttp를 사용하였습니다.
OkHttp는 HttpClient와는 비교할 수 없을만큼 편리한 사용성과 만족할만한 수준의 성능으로 저를 즐겁게 해주었습니다. 그런데 프로젝트 막바지에 Google Analytics (GA)를 적용하던 중 문제가 생겼습니다.
libssl: singal 11 (SIGSEV)
전혀 예상치 못한 에러와 함께 종료되는 어플리케이션을 보며 조금 이해가 안되더군요. 왜 잘 작동하던 libssl이 문제인거지? 이때까지만 해도 OkHttp에 문제가 있을거라고 생각조차 못했습니다.
조금 조사를 해보니 해당 문제는 square/okhttp 이슈트래커에서 8개월전에 논의가 되었던 이슈였습니다. 컨트리뷰터인 Jesse Wilson이 남긴 글에 보면 이렇게 나와있습니다.
So the problem is that Java and Android programs default to using a single global SSL context, accessible to our HTTP clients as the SSLSocketFactory. When OkHttp enables NPN for its own SPDY-related stuff, it ends up turning on NPN for the singleton shared SSL socket factory. Later when HttpURLConnection attempts to do SSL, it freaks out and crashes because NPN is enabled when it isn't expected to be.
결론부터 말하자면 문제의 원인은 안드로이드 어플리케이션의 기본 룰이 SSL 컨텍스트를 싱글튼으로 공유하는데 있었습니다. 저의 경우 libssl이 문제를 일으킨 직접적인 원인이 GA를 앱에 붙였기 때문인거죠.
SPDY를 지원하는 OkHttp는 SSLContext의 NPN(Next Protocol Negotiation)을 활성화하여 보안통신에서 어떤 통신 프로토콜이 사용되어야 할지 결정하게끔 합니다. 이 경우 OkHttp를 사용한 통신은 NPN 활성화 사실을 인지하고 이것을 문제삼지 않습니다.
하지만 GA의 경우 OkHttp 클라이언트가 아닌 HttpUrlConnection을 사용하기 때문에 문제가 됩니다. 앞에서 말한것같이 OkHttp도 HttpUrlConnection도 같은 SSLContext를 공유하는데 HttpUrlConnection이 SSL 통신을 하려고 보니 (HttpUrlConnection이 생각하기에) 활성화 되어있으면 안되는 NPN이 활성화 되어 있으니 바로 에러를 뱉고 죽는거죠.
문제를 파악했으니 해결을 해야죠. 가장 간단한 해결법은 OkHttp가 기본 SSLContext를 사용하지 않는겁니다. 다음 코드를 보면 OkHttp 클라이언트에 새로운 SSLContext를 설정하는 것을 확인할 수 있습니다.
OkHttpClient okHttpClient = new OkHttpClient(); SSLContext sslContext; try { sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, null, null); } catch (GeneralSecurityException e) { throw new AssertionError(); // 시스템이 TLS를 지원하지 않습니다 } okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
이렇게 하면 okHttpClient는 독립적인 SSLContext를 사용하게 되어 다른 코드 혹은 라이브러리에서 HttpUrlConnection(또는 다른 HTTP 클라이언트 라이브러리)으로 보안통신을 시도해도 문제를 일으키지 않습니다.













