java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. 에러는 일반적으로 안드로이드 앱이 SSL/TLS 연결을 설정하려고 할 때 발생합니다. 이 에러의 주요 원인은 앱이 서버의 SSL/TLS 인증서를 신뢰할 수 없거나 인증서 체인을 검증할 수 없을 때입니다.
저는 서버에서 사설 인증서를 사용했을 때 발생했습니다.
해결 방법은 서버에서 공인 인증서를 사용하도록 수정하는 것이 완벽한 해결책인데요.
가끔씩은 서버쪽 개발 리소스가 부족해서 그 상태가 며칠간 유지되는 경우가 있을 수 있습니다.
이럴때 해결방법은 앱이 사설 인증서도 사용할 수 있게끔 임시로 수정해 주는 것입니다.
여기서 그 방법을 알아 보겠습니다.
앱 수전의 build.gradle 에 아래와 같이 라이브러리를 추가합니다.
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.5'
그리고 Utile 패키지에 아래와 같은 유틸 클래스를 만듭니다.
import okhttp3.OkHttpClient
import java.security.SecureRandom
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
object UnsafeOkHttpClient {
val unsafeOkHttpClient: OkHttpClient.Builder
get() = try {
// Create a trust manager that does not validate certificate chains
val trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager {
@Throws(CertificateException::class)
override fun checkClientTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
@Throws(CertificateException::class)
override fun checkServerTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
)
// Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory: SSLSocketFactory = sslContext.socketFactory
val builder = OkHttpClient.Builder()
builder.sslSocketFactory(
sslSocketFactory,
(trustAllCerts[0] as X509TrustManager)
)
builder.hostnameVerifier { hostname, session -> true }
builder
} catch (e: Exception) {
throw RuntimeException(e)
}
}
위 유틸 클래스는 실제로 다음과 같이 사용될 수 있습니다.
1. Network Moduel 에서 사용하는 방법
@Singleton
@Provides
fun provideOkHttpClient(
addHeaderInterceptor: Interceptor,
httpLoggingInterceptor: HttpLoggingInterceptor
): OkHttpClient {
/*
// Original Code
return OkHttpClient.Builder()
.addInterceptor(addHeaderInterceptor)
.addInterceptor(httpLoggingInterceptor)
.build()
*/
return unsafeOkHttpClient
.addInterceptor(addHeaderInterceptor)
.addInterceptor(httpLoggingInterceptor)
.build()
}
2. Glide 라이브러리에서 사용하는 방법
- registerComponents 함수를 오버라이딩 해줍니다.
@GlideModule
class FDGlideApp : AppGlideModule() {
override fun applyOptions(context: Context, builder: GlideBuilder) {
super.applyOptions(context, builder)
builder.apply {
RequestOptions().diskCacheStrategy(DiskCacheStrategy.ALL).signature(
ObjectKey("NCAA_" + System.currentTimeMillis().toShort())
)
}
}
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
val okHttpClient = unsafeOkHttpClient.build()//getUnsafeOkHttpClient()
registry.replace<GlideUrl, InputStream>(
GlideUrl::class.java,
InputStream::class.java, OkHttpUrlLoader.Factory(okHttpClient)
)
}
}
위 방법으로 서버에서 공인 인증서로 교체하기 전까지 개발을 계속할 수 있습니다.
'Android > Features' 카테고리의 다른 글
[Android] BroadcastReceiver 사용하기 (0) | 2023.11.22 |
---|---|
[Android] 백그라운드 스레드에서 메인 스레드로 데이타 전달하는 방법 (0) | 2023.11.22 |
[Android] 스레드(Thread)와 핸들러(Handler) (1) | 2023.11.22 |
[Android] StartIntentSenderForResult 를 사용하여 외부 앱과 상호작용하기 (0) | 2023.10.14 |
[Android] registerForActivityResult (0) | 2023.10.14 |