며칠 삽질의 기억을.. 잊지 않기 위해 남긴다. 미래의 나에게 알리기 위해..
수정: 인증서 인증기관(CA)의 인증서를 google에서 다운로드 받는 부분 정정 |
문제의 발단..
배포 중인 앱을 사용하는 고객사 중 https를 사용하는 고객사들이 늘어나고 있다.
SSL 관련 에러 runtime 에러 중 handshake 관련 에러, CertPathValidation 관련 에러..
구글링해보면 가장 많이 나오는 내용이다. 하나같이 보안이 취약해짐을 경고한다.
/**
* Trust every server - don't check for any certificate
*/
private void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
}};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");//TLS
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
}
catch (Exception e) {
e.printStackTrace();
}
}
그런데, 웹페이지에서 첨부 파일을 다운로드 하려고 하면, 에러 없이 해당 코드 다 지나가는데 정작 다운로드가 안된다.
2022-02-18 09:36:43.932 5444-18175/? E/CONSCRYPT: ------------------Untrusted chain: ----------------------
2022-02-18 09:36:43.932 5444-18175/? E/CONSCRYPT: == Chain0 ==
Version: 3
2022-02-18 09:36:43.932 5444-18175/? E/CONSCRYPT: AuthorityKeyIdentifier: 41830168014f5cdd53c0850f96a4f3ab797da5683e669d268f7
2022-02-18 09:36:43.934 5444-18175/? E/CONSCRYPT: SubjectKeyIdentifier: 41604144ddfc81a25282145b8a8d443e77730654eaf2141
2022-02-18 09:36:43.934 5444-18175/? E/CONSCRYPT: Serial Number: 57a4fb9c8db5886950fea7c6
2022-02-18 09:36:43.934 5444-18175/? E/CONSCRYPT: SubjectDN: CN=work.synopex.com
2022-02-18 09:36:43.935 5444-18175/? E/CONSCRYPT: IssuerDN: CN=AlphaSSL CA - SHA256 - G2, O=GlobalSign nv-sa, C=BE
2022-02-18 09:36:43.935 5444-18175/? E/CONSCRYPT: Get not before: Tue Dec 07 13:34:04 GMT+09:00 2021
2022-02-18 09:36:43.936 5444-18175/? E/CONSCRYPT: Get not after: Sun Jan 08 13:34:04 GMT+09:00 2023
2022-02-18 09:36:43.936 5444-18175/? E/CONSCRYPT: Sig ALG name: SHA256withRSA
2022-02-18 09:36:43.936 5444-18175/? E/CONSCRYPT: Signature: 3f5733ba696f079777d75c5689643ea51dd77397a52783e0929ce8e059c8a54368a05fbebc4930ad2348eaf390165aaacfaa430240643cd1581faf58335f20deff423905fe9b5caa1b9e80cafbdfe738079d8db973b3d993019fece0106f2b58bac3dfd72870d2a669d27f5a93e3ff53ff609b287a7135e5c2afbc35cec764af022479eee2c4e6703fded4cd1464d1fc6497bb9717ea37fd1ab66e970588df32c30f13e4d790a3fa90be2f3b997694bcea3868575d065f58c4606beb5d66cf3c21cb03d1126aeeefd63523b38b5c5949be2a04adbcf263d7822cf7519641c9b0b61ccf032363a1e351a12af8d71c35dc42f440902066bc9662af5c93bc491df7
2022-02-18 09:36:43.981 5444-18175/? E/CONSCRYPT: Public key:
30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03
82 01 0f 00 30 82 01 0a 02 82 01 01 00 bb 53 2d 60 f9 db ce
17 45 aa 55 20 b9 92 ed 67 aa 31 1a 74 14 16 14 5f a3 43 fb
f5 72 0f f9 fc 2d d7 75 51 04 58 a5 9d d7 23 6c 60 fa 43 40
53 45 a8 00 61 e4 80 5c 08 a7 42 d7 74 bc 1e af ee cd 2b aa
ce 3d 73 4a c1 78 c7 d9 f1 9f fd 13 e8 18 6f f5 33 f6 23 48
46 cd 0c eb 14 c5 99 7d ff a3 93 9e 02 bc ea 72 41 c0 d1 58
b5 e9 e3 3e 79 79 b1 9f 25 ed 3b e0 85 49 a0 bd 45 04 6d fc
86 fc 6e e9 0a bc be e1 23 f0 8f 8d 64 1d 3d 72 9b a7 01 c8
b0 1e b6 60 ef 8a 08 6f a7 52 e3 9e 0e 3a de 73 56 30 03 a1
62 93 78 59 6d 6f cd 07 e0 a3 a8 00 90 94 cb b6 1e 9b a3 8e
c3 d9 a5 88 38 0b a0 6d 63 6e 7e c0 8a 3c 8e 17 39 ce ea 17
29 65 c8 25 01 bd 67 01 88 f2 d1 c7 63 b4 db 67 32 a3 9e 5f
0a ab fa 4f a2 3a 95 37 1d 18 b2 38 b4 df 9f b7 e5 8d 01 00
ec 9d 37 af 08 18 76 27 77 02 03 01 00 01
2022-02-18 09:36:43.990 5444-18175/? W/DownloadManager: [402] Stop requested with status HTTP_DATA_ERROR: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
2022-02-18 09:36:44.041 4159-4159/? W/NotificationEntryMgr: removeNotification for unknown key: 0|com.android.providers.downloads|0|1:com.goom.goom|10050
2022-02-18 09:36:47.264 3312-3615/? E/BufferQueueProducer: [Toast[16744]#0] disconnect: not connected (req=1)
2022-02-18 09:36:47.265 16744-17078/com.goom. W/libEGL: EGLNativeWindowType 0x7f08928010 disconnect failed
Trust anchor for certification path not found..
Trust anchor?
https://ko.theastrologypage.com/trust-anchor
'뭐지? 앱이 문젠가? 서버 문젠가?
처음엔 서버 쪽을 의심했다.
에러도 없고 , 무엇보다 같은 앱에서 정상동작 하는, https 사용 고객사가 있었기 때문.. (안되려면 다 안되야지.. 그게 더 수상해..)
nginx 문제 인가 해서 , 바로 tomcat으로 연결해보고.. setHeader("Pragma","no-cache") 도 해보고..
그냥 구글링해서 조금이라도 관련된 내용이면 이것도 해보고 다 해보면서 멘붕 중에..
Logcat 에서 No Filter로 보니...
2022-02-17 16:56:18.289 6795-5125/? E/CONSCRYPT: Public key:
30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03
82 01 0f 00 30 82 01 0a 02 82 01 01 00 bb 53 2d 60 f9 db ce
17 45 aa 55 20 b9 92 ed 67 aa 31 1a 74 14 16 14 5f a3 43 fb
f5 72 0f f9 fc 2d d7 75 51 04 58 a5 9d d7 23 6c 60 fa 43 40
53 45 a8 00 61 e4 80 5c 08 a7 42 d7 74 bc 1e af ee cd 2b aa
ce 3d 73 4a c1 78 c7 d9 f1 9f fd 13 e8 18 6f f5 33 f6 23 48
46 cd 0c eb 14 c5 99 7d ff a3 93 9e 02 bc ea 72 41 c0 d1 58
b5 e9 e3 3e 79 79 b1 9f 25 ed 3b e0 85 49 a0 bd 45 04 6d fc
86 fc 6e e9 0a bc be e1 23 f0 8f 8d 64 1d 3d 72 9b a7 01 c8
b0 1e b6 60 ef 8a 08 6f a7 52 e3 9e 0e 3a de 73 56 30 03 a1
62 93 78 59 6d 6f cd 07 e0 a3 a8 00 90 94 cb b6 1e 9b a3 8e
c3 d9 a5 88 38 0b a0 6d 63 6e 7e c0 8a 3c 8e 17 39 ce ea 17
29 65 c8 25 01 bd 67 01 88 f2 d1 c7 63 b4 db 67 32 a3 9e 5f
0a ab fa 4f a2 3a 95 37 1d 18 b2 38 b4 df 9f b7 e5 8d 01 00
ec 9d 37 af 08 18 76 27 77 02 03 01 00 01
2022-02-17 16:56:18.295 6795-5125/? W/DownloadManager: [393] Stop requested with status HTTP_DATA_ERROR: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
2022-02-17 16:56:18.296 3837-3848/? D/ConnectivityService: filterNetworkStateForUid() uid: 10362, pid: 6795
DownloadManager 가 Stop 됐다고? 또 그 놈의 Trust anchor 때문에?
답답한 마음에 Android Developer 사이트를 둘러보던 중..
예전에도 많이 , 자주 봤던.. HTTPS 관련 페이지를 천천히 정독하기 시작..
https://developer.android.com/training/articles/security-ssl
HTTPS 및 SSL을 사용한 보안 | Android 개발자 | Android Developers
HTTPS 및 SSL을 사용한 보안 현재 기술적으로 전송 계층 보안(TLS)이라고 알려진 보안 소켓 레이어(SSL)는 클라이언트와 서버 간의 암호화된 통신을 위한 공통 기본 토대입니다. 애플리케이션이 SSL을
developer.android.com
https://developer.android.com/training/articles/security-config
네트워크 보안 구성 | Android 개발자 | Android Developers
앱 개발자가 안전한 구성 파일에서 네트워크 보안 설정을 사용자설정할 수 있는 기능입니다.
developer.android.com
그러다 눈에 들어온 부분..
인증서 전달 받을 때, 보통 .key 및 (인증서).crt, (체인).crt, (루트).crt 받기도 하고, .key 제외한 인증서만 받는 경우도 있는데
여기서 사용할 파일은 (인증서).crt
일단, AndroidManifest.xml 파일에서 아래 부분 추가 안되어 있으면 추가!
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config" //추가
... >
...
</application>
</manifest>
res>xml>network_security_config.xml 수정
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">(도메인 정보 ex)naver.com</domain>
<trust-anchors>
<certificates src="@raw/sectigo_org_ca"/>
</trust-anchors>
</domain-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">(도메인 정보 ex)google.com</domain>
<trust-anchors>
<certificates src="@raw/(인증서 파일 이름)"/>
</trust-anchors>
</domain-config>
</network-security-config>
참고로, cleartextTrafficPermitted 옵션은 간단하게 말해 HTTP 연결을 허용할지 여부이다.
자세한 내용은 아래 링크 참고
NetworkSecurityPolicy | Android Developers
developer.android.com
public HttpsURLConnection postHttps(Context context,String url){
HttpsURLConnection urlConnection = null;
try{
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
//인증서 경로 저장
InputStream is = context.getResources().openRawResource(R.raw.sectigo_org_ca);
InputStream caInput = new BufferedInputStream(is);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL toUrl = new URL(url);
urlConnection =
(HttpsURLConnection)toUrl.openConnection();
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
urlConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
return hv.verify("server_domain",session);
}
});
//urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());
//InputStream in = urlConnection.getInputStream();
/*InputStream in = urlConnection.getInputStream();
IOUtils.copy(in, System.out);*/
}catch (Exception e){
e.printStackTrace();
}
return urlConnection;
}
와! 이제 그 Trust anchor 도 안뜨고.. 첨부파일 다운로드도 정상적으로 되고..
역시.. 귀찮다고 시도도 안해보고 일찌감치 포기하면.. 더 많은 시간, 체력을 뺏긴다는걸 이번 경험으로 또 알게됨.
그 외 참고 사이트
SSL문제 해결기:
https://modelmaker.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-SSL-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%EA%B8%B0
인증서 정보 찾기 : https://info-lab.tistory.com/265
더 확인할 문제 |
특정 인증기관의 인증서(ex. setigo) 는 인증서 파일을 등록하지 않아도 접속 및 실행에 문제 없는데, 어떤 CA의 인증서는 꼭 등록해야만 앱이 실행되는 이유.. |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
(삭제)
먼저, 추가하고자 하는 사이트의 인증서 정보를 알아보자.
openssl s_client -connect (사이트 도메인):443 | openssl x509 -noout -subject -issuer
-- ex)openssl s_client -connect google.com:443 | openssl x509 -noout -subject -issuer

어디서 다운 받지? 그대로 구글에 치면 됨 이렇게..
AlphaSSL CA - SHA256 - G2 Download


다른 인증서 다운로드 사이트도 유사하다 파일 다운로드/ Base64 보기..
거의 다왔다.. (정리하면서 보니.. 얼마 안되네..)
왜인지 몰라도.. android에 .cer 형식으로 하면 인식이 안되서.. .crt 형식으로 변환
openssl x509 -inform PEM -in (.cer파일 경로) -out (.crt 파일 경로)
ex) openssl x509 -inform PEM -in gsalphasha2g2r1.cer -out gsalphasha2g2r1.crt
이제 res>raw> 경로에 넣어주기

androidManifes.xml 파일에 추가
'android' 카테고리의 다른 글
Android Target API Level 34로 변경 후 빌드 안됨. (3) | 2024.10.31 |
---|---|
[FCM] OAuth 2.0 Playground로 message 보내기 (1) | 2024.10.18 |
[cordova] exitApp 플러그인 추가 안됨 (0) | 2024.07.22 |
Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent. (0) | 2023.01.09 |
android 12(sdk version 31) Task :app:processDebugMainManifest FAILED 에러 (0) | 2023.01.06 |