https 게시물을 작성하고 있는데 SSL 예외가 아닌 신뢰할 수없는 서버 인증서 예외가 발생합니다. 내가 정상적인 http를하면 완벽하게 잘 작동합니다. 어떻게 든 서버 인증서를 수락해야합니까?
https 게시물을 작성하고 있는데 SSL 예외가 아닌 신뢰할 수없는 서버 인증서 예외가 발생합니다. 내가 정상적인 http를하면 완벽하게 잘 작동합니다. 어떻게 든 서버 인증서를 수락해야합니까?
답변:
추측하고 있지만 실제 핸드 셰이크가 발생하려면 Android에 인증서를 알려야합니다. 무엇이든 받아들이고 싶다면 다음 의사 코드를 사용하여 Apache HTTP 클라이언트에서 필요한 것을 얻으십시오.
SchemeRegistry schemeRegistry = new SchemeRegistry ();
schemeRegistry.register (new Scheme ("http",
PlainSocketFactory.getSocketFactory (), 80));
schemeRegistry.register (new Scheme ("https",
new CustomSSLSocketFactory (), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager (
params, schemeRegistry);
return new DefaultHttpClient (cm, params);
CustomSSLSocketFactory :
public class CustomSSLSocketFactory extends org.apache.http.conn.ssl.SSLSocketFactory
{
private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory ();
public CustomSSLSocketFactory ()
{
super(null);
try
{
SSLContext context = SSLContext.getInstance ("TLS");
TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () };
context.init (null, tm, new SecureRandom ());
FACTORY = context.getSocketFactory ();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public Socket createSocket() throws IOException
{
return FACTORY.createSocket();
}
// TODO: add other methods like createSocket() and getDefaultCipherSuites().
// Hint: they all just make a call to member FACTORY
}
FullX509TrustManager는 javax.net.ssl.X509TrustManager를 구현하는 클래스이지만 실제로 작업을 수행하는 메소드는 없습니다 . 여기 에서 샘플을 얻으 십시오 .
행운을 빕니다!
FullX509TrustManager
이것이 내가하는 일입니다. 더 이상 인증서를 확인하지 않습니다.
// always verify the host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
/**
* Trust every server - dont check for any certificate
*/
private static void trustAllHosts() {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new java.security.cert.X509Certificate[] {};
}
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
}
} };
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
과
HttpURLConnection http = null;
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
https.setHostnameVerifier(DO_NOT_VERIFY);
http = https;
} else {
http = (HttpURLConnection) url.openConnection();
}
javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
. 나는 또한 교체 TLS
를 시도했지만 SSL
도움이되지 않았습니다. 제발 도와주세요, 감사합니다
이 질문에 답하는 동안 더 나은 튜토리얼을 찾았습니다. 그것으로 당신은 인증서 검사를 손상시킬 필요가 없습니다.
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
* 저는이 글을 쓰지 않았지만 작업을 해주신 Bob Lee에게 감사드립니다.
crazybobs와 매우 유사한 내 블로그 기사를 볼 수도 있습니다.
이 솔루션은 또한 인증서 검사를 손상시키지 않으며 자체 키 저장소에 신뢰할 수있는 인증서를 추가하는 방법을 설명합니다.
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
의례 Maduranga
https를 사용하는 애플리케이션을 개발할 때 테스트 서버에 유효한 SSL 인증서가 없습니다. 또는 웹 사이트에서 자체 서명 된 인증서를 사용하거나 웹 사이트에서 무료 SSL 인증서를 사용하는 경우가 있습니다. 따라서 Apache를 사용하여 서버에 연결하려고 HttpClient
하면 "peer not authenticated"라는 예외가 발생합니다. 프로덕션 소프트웨어의 모든 인증서를 신뢰하는 것은 좋지 않지만 상황에 따라 그렇게해야 할 수도 있습니다. 이 솔루션은 "피어가 인증되지 않음"으로 인한 예외를 해결합니다.
그러나 솔루션으로 이동하기 전에 이것은 프로덕션 응용 프로그램에 좋은 아이디어가 아니라는 점을 경고해야합니다. 이는 보안 인증서 사용 목적에 위배됩니다. 따라서 정당한 이유가 있거나 이것이 문제를 일으키지 않는다고 확신하는 경우가 아니면이 솔루션을 사용하지 마십시오.
일반적으로 다음 HttpClient
과 같이 만듭니다 .
HttpClient httpclient = new DefaultHttpClient();
그러나 HttpClient를 만드는 방법을 변경해야합니다.
먼저 org.apache.http.conn.ssl.SSLSocketFactory
.
import org.apache.http.conn.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}
그런 다음 이와 같은 방법을 만듭니다.
public HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}
그런 다음 HttpClient
.
HttpClient httpclient = getNewHttpClient();
로그인 페이지에 게시 요청을 보내려는 경우 나머지 코드는 다음과 같습니다.
private URI url = new URI("url of the action of the form");
HttpPost httppost = new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", "user"));
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
InputStream에 html 페이지를 가져옵니다. 그런 다음 반환 된 html 페이지로 원하는 것을 할 수 있습니다.
그러나 여기서 문제에 직면하게 될 것입니다. 쿠키를 사용하여 세션을 관리하려는 경우이 방법으로는 수행 할 수 없습니다. 쿠키를 얻으려면 브라우저를 통해해야합니다. 그러면 귀하 만 쿠키를 받게됩니다.
StartSSL 또는 Thawte 인증서를 사용하는 경우 Froyo 및 이전 버전에서는 실패합니다. 모든 인증서를 신뢰하는 대신 최신 버전의 CAcert 저장소 를 사용할 수 있습니다 .
이것들 중 어느 것도 나를 위해 일하지 않았습니다 ( Thawte 버그 로 인해 악화되었습니다 ). 결국 나는 그것이 고정있어 안드로이드에 대한 자체 서명 된 SSL 수용 및 사용자 정의 SSL 처리는 안드로이드 2.2 프로 요에 작동이 중지
이 답변 중 어느 것도 나를 위해 작동하지 않았으므로 여기에 인증서를 신뢰하는 코드가 있습니다.
import java.io.IOException;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
public class HttpsClientBuilder {
public static DefaultHttpClient getBelieverHttpsClient() {
DefaultHttpClient client = null;
SchemeRegistry Current_Scheme = new SchemeRegistry();
Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
try {
Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443));
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HttpParams Current_Params = new BasicHttpParams();
int timeoutConnection = 8000;
HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection);
int timeoutSocket = 10000;
HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket);
ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme);
client = new DefaultHttpClient(Current_Manager, Current_Params);
//HttpPost httpPost = new HttpPost(url);
//client.execute(httpPost);
return client;
}
public static class Naive_SSLSocketFactory extends SSLSocketFactory
{
protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS");
public Naive_SSLSocketFactory ()
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException
{
super(null, null, null, null, null, (X509HostnameVerifier)null);
Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null);
}
@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException
{
return Cur_SSL_Context.getSocketFactory().createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException
{
return Cur_SSL_Context.getSocketFactory().createSocket();
}
}
private static class X509_Trust_Manager implements X509TrustManager
{
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
};
}
SSL 인증서에 대한 Android 사양에 대해서는 모르지만 Android가 자체 서명 된 SSL 인증서를 즉시 수락하지 않는 것이 합리적입니다. 동일한 문제를 해결하는 것으로 보이는 Android 포럼에서이 게시물을 찾았습니다. http://androidforums.com/android-applications/950-imap-self-signed-ssl-certificates.html
이것은 Android 2.x의 알려진 문제입니다. 나는 문제에 대한 좋은 배경을 제공 할뿐만 아니라 어떤 보안 허점도없이 작동하고 효과적인 해결책을 제공하는 다음 질문을 발견 할 때까지 일주일 동안이 문제로 고심하고있었습니다.
Android 2.3에서는 'No peer certificate'오류가 발생하지만 4에서는 그렇지 않습니다.
어떤 이유로 위의 httpClient에 대해 언급 한 솔루션이 저에게 효과적이지 않았습니다. 결국 사용자 지정 SSLSocketFactory 클래스를 구현할 때 메서드를 올바르게 재정 의하여 작동하도록 만들 수있었습니다.
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
throws IOException, UnknownHostException
{
return sslFactory.createSocket(socket, host, port, autoClose);
}
@Override
public Socket createSocket() throws IOException {
return sslFactory.createSocket();
}
이것이 나를 위해 완벽하게 작동하는 방법입니다. 다음 스레드에서 전체 사용자 정의 클래스와 구현을 볼 수 있습니다. http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
나는이 수업을 만들고
package com.example.fakessl;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import android.util.Log;
public class CertificadoAceptar {
private static TrustManager[] trustManagers;
public static class _FakeX509TrustManager implements
javax.net.ssl.X509TrustManager {
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
throws CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return (true);
}
public boolean isServerTrusted(X509Certificate[] chain) {
return (true);
}
public X509Certificate[] getAcceptedIssuers() {
return (_AcceptedIssuers);
}
}
public static void allowAllSSL() {
javax.net.ssl.HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
javax.net.ssl.SSLContext context = null;
if (trustManagers == null) {
trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
}
try {
context = javax.net.ssl.SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
Log.e("allowAllSSL", e.toString());
} catch (KeyManagementException e) {
Log.e("allowAllSSL", e.toString());
}
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
}
}
이 코드 화이트
CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
AWS Apache 서버에서 자체 서명 된 인증서로 작업하고 Android 디바이스에서 HttpsURLConnection에 연결하는 데 도움이 된 소스 : AWS
인스턴스의
SSL - HTTPS 및 SSL을 사용 하는 SSL Android 보안 에 대한 Amazon 자습서 -수락을 위해 클라이언트에서 자체 신뢰 관리자 생성
자체 서명 된 인증서 생성 - 인증서 생성을 위한 쉬운 스크립트
그런 다음 다음을 수행했습니다.
create_my_certs.sh
.#!/bin/bash FQDN=$1 # make directories to work from mkdir -p server/ client/ all/ # Create your very own Root Certificate Authority openssl genrsa \ -out all/my-private-root-ca.privkey.pem \ 2048 # Self-sign your Root Certificate Authority # Since this is private, the details can be as bogus as you like openssl req \ -x509 \ -new \ -nodes \ -key all/my-private-root-ca.privkey.pem \ -days 1024 \ -out all/my-private-root-ca.cert.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com" # Create a Device Certificate for each domain, # such as example.com, *.example.com, awesome.example.com # NOTE: You MUST match CN to the domain name or ip address you want to use openssl genrsa \ -out all/privkey.pem \ 2048 # Create a request from your Device, which your Root CA will sign openssl req -new \ -key all/privkey.pem \ -out all/csr.pem \ -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}" # Sign the request from Device with your Root CA openssl x509 \ -req -in all/csr.pem \ -CA all/my-private-root-ca.cert.pem \ -CAkey all/my-private-root-ca.privkey.pem \ -CAcreateserial \ -out all/cert.pem \ -days 500 # Put things in their proper place rsync -a all/{privkey,cert}.pem server/ cat all/cert.pem > server/fullchain.pem # we have no intermediates in this case rsync -a all/my-private-root-ca.cert.pem server/ rsync -a all/my-private-root-ca.cert.pem client/
bash create_my_certs.sh yourdomain.com
서버의 적절한 위치에 인증서를 배치합니다 (/etc/httpd/conf.d/ssl.conf에서 구성을 찾을 수 있음). 다음을 모두 설정해야합니다.
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
다음을 사용하여 httpd를 다시 시작 sudo service httpd restart
하고 httpd가 시작되었는지 확인합니다. httpd
중지 : [확인]
httpd 시작 : [확인]
복사 my-private-root-ca.cert
안드로이드 프로젝트 자산 폴더에
신뢰 관리자를 작성하십시오.
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance ( "X.509"); InputStream caInput = context.getAssets (). open ( "my-private-root-ca.cert.pem"); 인증서 ca; 시도 {ca = cf.generateCertificate (caInput); } 마지막으로 {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.getInstance("TLS");
SSSLContext.init(null, tmf.getTrustManagers(), null);
그리고 HttpsURLConnection을 사용하여 연결합니다.
HttpsURLConnection 연결 = (HttpsURLConnection) url.openConnection (); connection.setSSLSocketFactory (SSLContext.getSocketFactory ());
그게 다야, https 연결을 시도하십시오.
이 방법을 HTTPClient로 사용하십시오.
public static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}