Tôi đang thực hiện một bài đăng https và tôi nhận được một ngoại lệ của ngoại lệ ssl Không phải chứng chỉ máy chủ đáng tin cậy. Nếu tôi làm http bình thường, nó hoạt động hoàn toàn tốt. Tôi có phải chấp nhận chứng chỉ máy chủ bằng cách nào đó không?
Tôi đang thực hiện một bài đăng https và tôi nhận được một ngoại lệ của ngoại lệ ssl Không phải chứng chỉ máy chủ đáng tin cậy. Nếu tôi làm http bình thường, nó hoạt động hoàn toàn tốt. Tôi có phải chấp nhận chứng chỉ máy chủ bằng cách nào đó không?
Câu trả lời:
Tôi đang phỏng đoán, nhưng nếu bạn muốn bắt tay thực sự xảy ra, bạn phải cho android biết về chứng chỉ của mình. Nếu bạn chỉ muốn chấp nhận bất kể điều gì, hãy sử dụng mã giả này để nhận những gì bạn cần với Apache HTTP Client:
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 là một lớp triển khai javax.net.ssl.X509TrustManager, nhưng không có phương thức nào thực sự thực hiện bất kỳ công việc nào, hãy lấy mẫu tại đây .
Chúc may mắn!
FullX509TrustManager
Đây là những gì tôi đang làm. Nó chỉ đơn giản là không kiểm tra chứng chỉ nữa.
// 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();
}
}
và
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
. Tôi cũng đã thử thay thế TLS
bằng SSL
nhưng không giúp được gì. Xin hãy giúp tôi, Cảm ơn
Trong khi cố gắng trả lời câu hỏi này, tôi đã tìm thấy một hướng dẫn tốt hơn. Với nó, bạn không phải ảnh hưởng đến việc kiểm tra chứng chỉ.
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
* Tôi không viết cái này nhưng cảm ơn Bob Lee về công việc
Bạn cũng có thể xem bài viết trên blog của tôi, rất giống với crazybobs.
Giải pháp này cũng không ảnh hưởng đến việc kiểm tra chứng chỉ và giải thích cách thêm chứng chỉ đáng tin cậy vào kho khóa của riêng bạn.
http://blog.antoine.li/index.php/2010/10/android-trusting-ssl-certificates/
http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html
Maduranga lịch sự
Khi phát triển ứng dụng sử dụng https, máy chủ thử nghiệm của bạn không có chứng chỉ SSL hợp lệ. Hoặc đôi khi trang web đang sử dụng chứng chỉ tự ký hoặc trang web đang sử dụng chứng chỉ SSL miễn phí. Vì vậy, nếu bạn cố gắng kết nối với máy chủ bằng Apache HttpClient
, bạn sẽ nhận được một ngoại lệ nói rằng "máy ngang hàng không được xác thực". Mặc dù không phải là một thông lệ tốt để tin tưởng tất cả các chứng chỉ trong một phần mềm sản xuất, bạn có thể phải làm như vậy tùy theo tình huống. Giải pháp này giải quyết trường hợp ngoại lệ do "peer nothenticated".
Nhưng trước khi chúng ta đi đến giải pháp, tôi phải cảnh báo bạn rằng đây không phải là một ý tưởng hay cho một ứng dụng sản xuất. Điều này sẽ vi phạm mục đích của việc sử dụng chứng chỉ bảo mật. Vì vậy, trừ khi bạn có lý do chính đáng hoặc nếu bạn chắc chắn rằng điều này sẽ không gây ra bất kỳ vấn đề gì, thì không nên sử dụng giải pháp này.
Thông thường bạn tạo một cái HttpClient
như thế này.
HttpClient httpclient = new DefaultHttpClient();
Nhưng bạn phải thay đổi cách tạo HttpClient.
Đầu tiên, bạn phải tạo một lớp mở rộng 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();
}
}
Sau đó, tạo một phương thức như thế này.
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();
}
}
Sau đó, bạn có thể tạo HttpClient
.
HttpClient httpclient = getNewHttpClient();
Nếu bạn đang cố gắng gửi một yêu cầu đăng bài đến một trang đăng nhập, phần còn lại của mã sẽ như thế này.
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();
}
Bạn đưa trang html đến InputStream. Sau đó, bạn có thể làm bất cứ điều gì bạn muốn với trang html trả về.
Nhưng ở đây bạn sẽ phải đối mặt với một vấn đề. Nếu bạn muốn quản lý một phiên bằng cookie, bạn sẽ không thể thực hiện bằng phương pháp này. Nếu bạn muốn lấy cookie, bạn sẽ phải thực hiện qua trình duyệt. Sau đó, chỉ bạn sẽ nhận được cookie.
Nếu bạn đang sử dụng chứng chỉ StartSSL hoặc Thawte, chứng chỉ này sẽ không thành công đối với Froyo và các phiên bản cũ hơn. Bạn có thể sử dụng kho lưu trữ CAcert của phiên bản mới hơn thay vì tin tưởng mọi chứng chỉ.
Không có cái nào trong số này hiệu quả với tôi (còn trầm trọng hơn bởi lỗi Thawte ). Cuối cùng tôi đã khắc phục được sự cố với việc chấp nhận SSL tự ký trên Android và xử lý SSL tùy chỉnh ngừng hoạt động trên Android 2.2 FroYo
Bất kỳ câu trả lời nào trong số này không phù hợp với tôi vì vậy đây là mã tin cậy bất kỳ chứng chỉ nào.
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;
}
};
}
Tôi không biết về các chi tiết cụ thể của Android cho chứng chỉ ssl, nhưng sẽ có lý khi Android sẽ không chấp nhận chứng chỉ ssl tự ký. Tôi tìm thấy bài đăng này từ các diễn đàn android có vẻ như đang giải quyết vấn đề tương tự: http://androidforums.com/android-application/950-imap-self-signed-ssl-certificates.html
Đây là sự cố đã biết với Android 2.x. Tôi đã vật lộn với vấn đề này trong một tuần cho đến khi tôi bắt gặp câu hỏi sau, câu hỏi này không chỉ đưa ra nền tảng tốt về vấn đề mà còn cung cấp giải pháp hoạt động và hiệu quả không có bất kỳ lỗ hổng bảo mật nào.
Lỗi 'Không có chứng chỉ ngang hàng' trong Android 2.3 nhưng KHÔNG phải trong 4
Vì một số lý do, giải pháp được đề cập cho httpClient ở trên không hoạt động với tôi. Cuối cùng, tôi đã có thể làm cho nó hoạt động bằng cách ghi đè phương thức một cách chính xác khi triển khai lớp SSLSocketFactory tùy chỉnh.
@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();
}
Đây là cách nó hoạt động hoàn hảo đối với tôi. Bạn có thể xem toàn bộ lớp tùy chỉnh và triển khai trên chuỗi sau: http://blog.syedgakbar.com/2012/07/21/android-https-and-not-trusted-server-certificate-error/
Tôi thực hiện lớp học này và tìm thấy
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());
}
}
trong bạn mã màu trắng này
CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
Các nguồn đã giúp tôi làm việc với chứng chỉ tự ký trên máy chủ AWS Apache của tôi và kết nối với HttpsURLConnection từ thiết bị Android:
SSL trên phiên bản aws - hướng dẫn của amazon về ssl
Android Security với HTTPS và SSL - tạo trình quản lý tin cậy của riêng bạn trên ứng dụng khách để chấp nhận chứng chỉ của bạn
Tạo chứng chỉ tự ký - tập lệnh dễ dàng để tạo chứng chỉ của bạn
Sau đó, tôi đã làm như sau:
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
Đặt các chứng chỉ vào vị trí thích hợp của chúng trên máy chủ (bạn có thể tìm thấy cấu hình trong /etc/httpd/conf.d/ssl.conf). Tất cả những điều này nên được đặt:
SSLCertificateFile
SSLCertificateKeyFile
SSLCertificateChainFile
SSLCACertificateFile
Khởi động lại httpd bằng cách sử dụng sudo service httpd restart
và đảm bảo httpd đã bắt đầu: Đang
dừng httpd: [OK] Đang
khởi động httpd: [OK]
Sao chép my-private-root-ca.cert
vào thư mục nội dung dự án Android của bạn
Tạo người quản lý tin cậy của bạn:
SSLContext SSLContext;
CertificateFactory cf = CertificateFactory.getInstance ("X.509"); InputStream caInput = context.getAssets (). Open ("my-private-root-ca.cert.pem"); Chứng chỉ ca; thử {ca = cf.generateCertificate (caInput); } cuối cùng {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);
Và tạo kết nối bằng HttpsURLConnection:
Kết nối HttpsURLConnection = (HttpsURLConnection) url.openConnection (); connect.setSSLSocketFactory (SSLContext.getSocketFactory ());
Đó là nó, hãy thử kết nối https của bạn.
Chỉ cần sử dụng phương pháp này làm HTTPClient của bạn:
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();
}
}