안드로이드 플랫폼에서 신뢰할 수없는 것으로 간주되는 인증 기관으로부터 안전하게 연결하려면 다음과 같은 주요 단계가 필요합니다.
많은 사용자의 요청에 따라 블로그 기사 에서 가장 중요한 부분을 여기에 반영했습니다.
- 필요한 모든 인증서 (루트 및 중간 CA)를 가져옵니다.
- keytool 및 BouncyCastle 제공자를 사용하여 키 저장소를 작성 하고 인증서를 가져 오십시오.
- 안드로이드 앱에 키 저장소를로드하고 보안 연결에 사용하십시오 ( 표준 대신 Apache HttpClient 를 사용하는 것이 좋습니다
java.net.ssl.HttpsURLConnection
(더 이해하기 쉽고 성능이 좋습니다 )
인증서를 잡아
엔드 포인트 인증서에서 루트 CA까지 체인을 구축하는 모든 인증서를 가져와야합니다. 즉, 중간 CA 인증서 (있는 경우)와 루트 CA 인증서도 있습니다. 엔드 포인트 인증서를 얻을 필요가 없습니다.
키 스토어 작성
BouncyCastle Provider를 다운로드하여 알려진 위치에 저장하십시오. 또한 keytool 명령 (보통 JRE 설치의 bin 폴더 아래에 있음)을 호출 할 수 있는지 확인하십시오.
이제 획득 한 인증서를 엔드 포인트 인증서를 가져 오지 말고 BouncyCastle 형식의 키 저장소로 가져 오십시오.
테스트하지는 않았지만 인증서 가져 오기 순서가 중요하다고 생각합니다. 즉, 가장 낮은 중간 CA 인증서를 먼저 가져온 다음 루트 CA 인증서까지 가져옵니다.
다음 명령을 사용하면 비밀번호가 mysecret 인 새 키 저장소 (아직없는 경우) 가 작성되고 중간 CA 인증서가 가져옵니다. 또한 내 파일 시스템과 키 저장소 형식에서 찾을 수있는 BouncyCastle 공급자를 정의했습니다. 체인의 각 인증서에 대해이 명령을 실행하십시오.
keytool -importcert -v -trustcacerts -file "path_to_cert/interm_ca.cer" -alias IntermediateCA -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
인증서를 키 저장소로 올바르게 가져 왔는지 확인하십시오.
keytool -list -keystore "res/raw/mykeystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-145.jar" -storetype BKS -storepass mysecret
전체 체인을 출력해야합니다.
RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43
이제 당신은 아래의 안드로이드 앱에서 키 저장소를 원시 리소스로 복사 할 수 있습니다 res/raw/
앱에서 키 저장소를 사용하십시오.
우선 HTTPS 연결에 키 저장소를 사용하는 사용자 정의 Apache HttpClient를 작성해야합니다.
import org.apache.http.*
public class MyHttpClient extends DefaultHttpClient {
final Context context;
public MyHttpClient(Context context) {
this.context = context;
}
@Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "mysecret".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
우리는 커스텀 HttpClient를 만들었습니다. 이제 안전한 연결을 위해 사용할 수 있습니다. 예를 들어 REST 리소스에 대해 GET 호출을하는 경우 :
// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();
그게 다야;)