1.

요즘은 상용 웹 사이트는 HTTPS를 사용하는 것이 대세다.

기업 내 포털 사이트도 대부분 HTTPS를 사용한다. 일부 폐쇄망/내부망 전용 서비스는 제외하고.


Java Spring MVC 기반의 웹 서비스로 만들어진 OTP 솔루션을 납품했던 국내 한 기업에서

내년에 Windows 10으로 전체 직원 PC 업그레이드 계획이 있어 Windows 10 호환성 테스트를 하다 보니

OTP에서 오류가 발생하고 정상 동작하지 않는다는 것이다.


상황을 파악해 봤더니 우리 OTP 솔루션의 오류가 아니라 

OTP가 탑재되어 있는 웹서비스(WAS)가 HTTPS로 호출이 되지 않는 증상이었다.

웹 서버에 응용 프로그램 서비스의 하나로 올라가 있는 우리 OTP 솔루션의 입장에서는

문을 두드려야 "누구세요?"라고 묻지, 문도 두드리지 않았는데 대답을 하지 않았다고 지적받은 셈.

어쨌든,

관련 서비스 담당 개발자 입장에서 우리 솔루션의 문제가 아니니 나몰라라 하고 있을 수만은 없어

문제 파악에 나서 봤다.



2.

먼저, 방화벽의 문제인가 하고 telnet으로 연결을 해 봤다. 

잘 붙었다. 연결은 정상이었다.

실제로 웹 브라우저로 접속을 시도하면 아래 화면과 같이 접속이 안될 뿐.


(희한한 것은, 이렇게 접속이 되지 않아도 HTTP 500 오류가 아닌 200 OK로 결과는 정상으로 반환된다.)


특이한 것은 

Windows 10을 제외한 기존 Windows 7 환경에서는 너무나 정상적으로 접속이 잘 된다는 점!


그렇다면 Windows 10 클라이언트 접속 환경에 문제가 있을 가능성이 높으므로 

해당 Windows 10의 IE 설정 옵션을 조정해 봤다. 어떻게 바꿔봐도 소용이 없었다.


그렇다면 결국은 PC에 설치된 네트워크 제어 및 보안 프로그램이 원인일 것이라고 추측했지만

그 영역은 제어 불가 영역이라 일단 넘어가고 나중에 테스트해 보기로 하고...



3.

도대체 왜 Windows 10에서 접속이 되지 않는 것인지 이해가 되지 않아 

똑같은 조건으로 동일한 테스트 환경을 따로 만들어서 테스트해 봤다.

실제 서버에서 사용하고 있는 JDK가 1.8.0_65-b17 버전이었고, Tomcat은 7.0.82 버전.

문제의 클라이언트 PC는 Windows 10 Pro 1809버전(17763.134)이라고 해서 

똑같은 버전으로 받아서 테스트해 봤다.

결과는... 


너무나도 접속이 잘 되었다.


읭???

이게 대체 무슨 퐝당 시츄에이션?

똑같은 서버 환경에 똑같은 클라이언트 버전으로 테스트했는데, 왜 테스트 환경에서는 잘 될까?

이해하기가 어려운 상황...



4.

그 사이 실제 환경에서 PC 네트워크 제어/보안 프로그램의 문제인지 파악하기 위해

Windows 초기화/재설치 후 서버 네트워크에 직접 연결해서 다시 테스트해 봤다.

헐... 결과는 마찬가지. 클라이언트의 문제는 아니었던 것이다!


문제의 원인이 클라이언트도 아니고 방화벽이나 네트워크도 아니라면 서버에 있다는 얘긴데,

서버에 도대체 어떤 특이점이 있기에 Windows 7에서는 정상 접속되고 Windows 10에서만 안되는 것일까?




5.

먼저 인증서를 의심해 봤다. 인증서 체인이 혹시 신뢰되지 않아서?

아니었다.



6.

다음으로는 WAS인 Tomcat Server.xml에 있는 SSL 설정을 의심해 봤다.

<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
                keystoreFile="/home/user/sslkeystore/keystore" keystorePass="password"
               clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2" />

(이 설정으로는 TLS v1.0 이상을 사용하는 웹 브라우저를 다 지원한다. 최신 브라우저에서만 동작하게 하려면 "TLSv1.2"만 넣어줘도 된다.)


TLS만 허용한 부분에 SSLv3도 넣어보고 TLSv1.2만 넣어보기도 하는 등 별의 별 짓을 다 해봤지만

역시 별 문제될 만한 것이 없었다.

설정을 어떻게 바꿔봐도 Windows 10에서는 요지부동. 

ciphers 속성을 명시적으로 지정하면 해당 지정된 알고리즘들만 동작한다는 얘기가 있어서 

그걸 JDK 7에서 지원하는 형식대로 입력해 넣어봐도 역시 무반응.

<Connector port="443" protocol="org.apache.coyote.http11.Http11Protocol"
               maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
                keystoreFile="/home/user/sslkeystore/keystore" keystorePass="password"
               clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"
               ciphers="TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_DH_DSS_WITH_AES_256_CBCSHA256,
TLS_DH_RSA_WITH_AES_256_CBCSHA256,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
TLS_DH_anon_WITH_AES_256_CBC_SHA256" />

오히려 catalina 로그에 지원되지 않는 알고리즘이라고 경고만 떴다.

12월 19, 2018 8:49:04 오전 org.apache.tomcat.util.net.jsse.JSSESocketFactory getEnableableCiphers
경고: None of the ciphers specified are supported by the SSL engine : TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_DH_DSS_WITH_AES_256_CBCSHA256, TLS_DH_RSA_WITH_AES_256_CBCSHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DH_anon_WITH_AES_256_CBC_SHA256



끄아아아...

대체 뭐가 문제란 말인가!?



7.

혹시나 하여 테스트 환경과 실제 서버 환경을 다시 한번 비교해 봤다.

어라? 설치된 JDK가 약간 달랐다. 같은 버전이긴 했지만 서버에는 리눅스용 Open JDK가 설치되어 있었고 

테스트 환경에는 Windows용 Oracle JDK가 설치되어 있었다.

Java 구동 환경은 어차피 JVM 가상머신이고 동일한 소스를 기반으로 빌드되었으므로 

Open이나 Oracle이나, Windows용이나 리눅스용이나 다 똑같을 것 같았지만

동작 결과가 다른 것으로 보아 뭔가 다른 점이 있는 모양.



8.

그렇다면!!!

마지막으로 Java의 TLS 설정 부분을 살펴 봤다. TLS 설정과 관련된 부분은 딱 두 군데가 있는데,

{jre}/lib/security/java.security:

jdk.tls.disabledAlgorithms=SSLv3, RC4, DH keySize < 768, EC, ECDHE, ECDH

jdk.tls.legacyAlgorithms= \
        K_NULL, C_NULL, M_NULL, \
        DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
        DH_RSA_EXPORT, RSA_EXPORT, \
        DH_anon, ECDH_anon, \
        RC4_128, RC4_40, DES_CBC, DES40_CBC

실제 서버에는 이렇게 되어 있었다.


반면, 테스트 환경의 Java TLS 설정은 아래와 같았다.

{jre}/lib/security/java.security:

jdk.tls.disabledAlgorithms=SSLv3, RC4, DH keySize < 768

jdk.tls.legacyAlgorithms= \
        K_NULL, C_NULL, M_NULL, \
        DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
        DH_RSA_EXPORT, RSA_EXPORT, \
        DH_anon, ECDH_anon, \
        RC4_128, RC4_40, DES_CBC, DES40_CBC


엉?

실제 서버에는 disabledAlgorithms 부분에 EC, ECDHE, ECDH 세 가지가 더 들어있었다.

이게 뭔지는 모르겠고, 설마... 이것 때문에?

테스트 환경에 해당 설정값 세 개를 넣고 테스트해 봤다.


덜컥,

TLS 에러가 나고 접속이 안되는 상황이 정확하게 똑같이 재현되었다!

혹시나 해서 Windows 7에서 해봤더니 정상 접속. Windows Server 2012 R2에서도 정상 접속.

오직 Windows 10에서만 접속이 안되는 상황이 똑같이 재현되었다.

Windows 10 Pro 1709, 1809버전, Windows 10 Enterprise 1803버전 세 종류에서 테스트를 더 해봤는데

모두 접속이 되지 않았다.


실제 서버에는 왜 그런 설정이 추가되어 있었던 것일까?

그래서 해당 설정 부분을 삭제하고 테스트를 해 봤다. 그런데... 그래도 여전히 접속이 안 되었다.

어라? 단순히 설정을 지운다고 동작하는 것은 아니란 얘긴데? 왜 그럴까?


가정을 해 보자면,

Windows 10에서는 TLS 통신에 EC, ECDHE, ECDH 알고리즘만 사용하고 있는데

설마 서버에 설치된 JDK에서는 EC, ECDHE, ECDH 알고리즘 지원이 아예 안된다는 말인가?

그렇기 때문에 위 jdk.tls.disabledAlgorithms 목록에 기본적으로 들어 있었던 걸까?



9.

인터넷을 뒤져 봤다. 비슷한 단어가 있는 모든 페이지를 뒤져 봤지만 이거다 싶은 것이 없었는데

무심코 이것저것 던져보던 검색어에 딱 하나가 눈에 띄었다.


>>참조: https://security.stackexchange.com/questions/117975/how-to-enable-ecdhe-in-openjdk-1-8-0-in-centos-6-7


얘기인 즉슨, 

RedHat에서 EC 암호화 알고리즘을 2013년에 삭제했고 최근에 다시 복구하기 시작했다고.

그리고 그것도 Open JDK 91버전까지는 안 되고, 101버전부터 되는 것 같다는 댓글 증언들...

그렇다! 실제 서버에 설치된 Open JDK가 65버전이었으니 당연히 안되는 것이었다!


결론:

JDK 버전을 101버전 이상(181버전)으로 올려서 해결했다.

허무한 결론...


그런데 ㅎㅎㅎ 여기서 끝은 아니고

TO BE CONTINUED





Posted by 떼르미
,


자바스크립트를 허용해주세요!
Please Enable JavaScript![ Enable JavaScript ]