chấp nhận kết nối HTTPS với chứng chỉ tự ký


153

Tôi đang cố gắng tạo kết nối HTTPS, sử dụng HttpClientlib, nhưng vấn đề là, vì chứng chỉ không được ký bởi Cơ quan cấp chứng chỉ (CA) được công nhận như Verisign , GlobalSIgn , v.v., được liệt kê trên bộ Chứng chỉ tin cậy Android, Tôi tiếp tục nhận được javax.net.ssl.SSLException: Not trusted server certificate.

Tôi đã thấy các giải pháp mà bạn chỉ cần chấp nhận tất cả các chứng chỉ, nhưng nếu tôi muốn hỏi người dùng thì sao?

Tôi muốn nhận được một hộp thoại tương tự như của trình duyệt, cho phép người dùng quyết định tiếp tục hay không. Tốt nhất là tôi muốn sử dụng cùng một chứng chỉ như trình duyệt. Có ý kiến ​​gì không?


Giải pháp được chấp nhận này hoạt động với tôi- stackoverflow.com/questions/2642777/ từ
Venkatesh

Câu trả lời:


171

Điều đầu tiên bạn cần làm là thiết lập mức độ xác minh. Mức độ như vậy không quá nhiều:

  • ALLOW_ALL_HOSTNAME_VERIFIER
  • BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
  • STRICT_HOSTNAME_VERIFIER

Mặc dù phương thức sethostnameVerifier () đã lỗi thời đối với apache thư viện mới, nhưng đối với phiên bản trong SDK Android là bình thường. Và vì vậy chúng tôi lấy ALLOW_ALL_HOSTNAME_VERIFIERvà đặt nó trong nhà máy phương pháp SSLSocketFactory.setHostnameVerifier().

Tiếp theo, Bạn cần đặt nhà máy của chúng tôi cho giao thức thành https. Để làm điều này, chỉ cần gọi SchemeRegistry.register()phương thức.

Sau đó, bạn cần phải tạo một DefaultHttpClientvới SingleClientConnManager. Ngoài ra trong mã bên dưới, bạn có thể thấy rằng theo mặc định cũng sẽ sử dụng cờ của chúng tôi ( ALLOW_ALL_HOSTNAME_VERIFIER) theo phương thứcHttpsURLConnection.setDefaultHostnameVerifier()

Mã dưới đây hoạt động với tôi:

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient client = new DefaultHttpClient();

SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

// Set verifier     
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

// Example send http request
final String url = "https://encrypted.google.com/";
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);

6
Tôi không thể làm cho mã này hoạt động một cách đáng tiếc, tôi vẫn nhận được "Chứng chỉ máy chủ không đáng tin cậy". Có bất kỳ quyền bổ sung nào mà tôi phải đặt để làm cho nó hoạt động không?
Juriy

1
Không phải mã này chỉ chấp nhận tất cả các chứng chỉ? Tôi cần một cửa sổ bật lên để chấp nhận nó.
Morten

3
Tôi đang sử dụng org.apache.http.conn.ssl.SSLSocketFactorytại sao tôi muốn sử dụng javax.net.ssl.HttpsURLConnection??
Ai đó ở đâu đó

9
Bạn có thể giải thích làm thế nào mã này là tốt hơn so với việc vô hiệu hóa hoàn toàn xác minh chứng chỉ? Tôi không quen với API ssl của Android, nhưng trong nháy mắt điều này dường như hoàn toàn không an toàn trước những kẻ tấn công đang hoạt động.
CodeInChaos

3
Tôi sẽ đề xuất sử dụng ThreadSafeClientConnManager thay vì SingleClientConnManager
Farm

124

Các bước chính sau đây được yêu cầu để đạt được kết nối an toàn từ Tổ chức chứng nhận không được coi là đáng tin cậy bởi nền tảng Android.

Theo yêu cầu của nhiều người dùng, tôi đã nhân đôi những phần quan trọng nhất từ bài viết trên blog của tôi ở đây:

  1. Lấy tất cả các chứng chỉ cần thiết (root và bất kỳ CA trung gian nào)
  2. Tạo kho lưu trữ khóa với keytool và nhà cung cấp BouncyCastle và nhập certs
  3. Tải kho khóa trong ứng dụng Android của bạn và sử dụng nó cho các kết nối được bảo mật (Tôi khuyên bạn nên sử dụng ApacheClClient thay vì tiêu chuẩn java.net.ssl.HttpsURLConnection(dễ hiểu hơn, hiệu quả hơn)

Lấy certs

Bạn phải có được tất cả các chứng chỉ xây dựng chuỗi từ chứng chỉ điểm cuối cho đến tận gốc CA. Điều này có nghĩa là, bất kỳ (nếu có) các cer CA trung gian và cả chứng chỉ Root CA. Bạn không cần phải có được chứng chỉ điểm cuối.

Tạo kho khóa

Tải xuống Nhà cung cấp BouncyCastle và lưu trữ nó đến một vị trí đã biết. Cũng đảm bảo rằng bạn có thể gọi lệnh keytool (thường nằm trong thư mục bin của bản cài đặt JRE của bạn).

Bây giờ, nhập các certs thu được (không nhập chứng chỉ điểm cuối) vào kho khóa được định dạng BouncyCastle.

Tôi đã không kiểm tra nó, nhưng tôi nghĩ thứ tự nhập chứng chỉ là quan trọng. Điều này có nghĩa là, nhập chứng chỉ CA trung gian thấp nhất trước tiên và sau đó đến tận chứng chỉ CA gốc.

Với lệnh sau, kho khóa mới (nếu chưa có) với mật khẩu mysecret sẽ được tạo và chứng chỉ CA trung gian sẽ được nhập. Tôi cũng đã xác định nhà cung cấp BouncyCastle, nơi có thể tìm thấy nó trên hệ thống tệp của tôi và định dạng kho khóa. Thực hiện lệnh này cho mỗi chứng chỉ trong chuỗi.

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

Xác minh nếu các chứng chỉ được nhập chính xác vào kho khóa:

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

Nên xuất toàn bộ chuỗi:

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

Bây giờ bạn có thể sao chép kho khóa dưới dạng tài nguyên thô trong ứng dụng Android của mình bên dưới res/raw/

Sử dụng kho khóa trong ứng dụng của bạn

Trước hết, chúng ta phải tạo một ApacheClClient tùy chỉnh sử dụng kho khóa của chúng tôi cho các kết nối HTTPS:

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);
        }
    }
}

Chúng tôi đã tạo ra httpClient tùy chỉnh của mình, bây giờ chúng tôi có thể sử dụng nó cho các kết nối an toàn. Ví dụ: khi chúng tôi thực hiện cuộc gọi GET tới tài nguyên REST:

// 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();

Đó là nó ;)


8
Điều này chỉ hữu ích để có được chứng chỉ trước khi vận chuyển ứng dụng của bạn. Không thực sự giúp người dùng chấp nhận certs của riêng họ. cho ứng dụng của bạn
Fuzzy

Xin chào tất cả mọi người có thể cho tôi biết quy trình xác thực cho kho khóa với Truststore để thực hiện ở trên không ??? cảm ơn trước ..
andriod_testing

Điều này hoạt động tốt..nhưng bây giờ tôi đang gặp phải một vấn đề khi tôi nhập lại chứng chỉ trên máy chủ. Có vẻ kỳ lạ là mỗi khi tôi cập nhật chứng chỉ trên máy chủ của mình, cửa hàng phía khách cũng nên được cập nhật. Phải có một cách tốt hơn: |
bpn

Câu trả lời của Gr8, tôi sẽ đề xuất sử dụng ThreadSafeClientConnManager thay vì SingleClientConnManager
Farm

Tôi đã thêm /res/raw/mykeystore.bks, mặc dù không thể giải quyết tham chiếu đến nó. Làm thế nào để giải quyết điều này?
uniruddh

16

Nếu bạn có chứng chỉ tùy chỉnh / tự ký trên máy chủ không có trên thiết bị, bạn có thể sử dụng lớp bên dưới để tải và sử dụng nó ở phía máy khách trong Android:

Đặt *.crttệp chứng chỉ vào /res/rawđể nó có sẵn từR.raw.*

Sử dụng lớp dưới đây để có được một HTTPClienthoặc HttpsURLConnectionsẽ có một nhà máy ổ cắm sử dụng chứng chỉ đó:

package com.example.customssl;

import android.content.Context;
import org.apache.http.client.HttpClient;
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.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
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.HttpParams;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

public class CustomCAHttpsProvider {

    /**
     * Creates a {@link org.apache.http.client.HttpClient} which is configured to work with a custom authority
     * certificate.
     *
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http Client.
     * @throws Exception If there is an error initializing the client.
     */
    public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {


        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // init ssl socket factory with key store
        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);

        // skip hostname security check if specified
        if (allowAllHosts) {
            sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        // basic http params for client
        HttpParams params = new BasicHttpParams();

        // normal scheme registry with our ssl socket factory for "https"
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

        // create connection manager
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);

        // create http client
        return new DefaultHttpClient(cm, params);
    }

    /**
     * Creates a {@link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
     * certificate.
     *
     * @param urlString     remote url string.
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http url connection.
     * @throws Exception If there is an error initializing the connection.
     */
    public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
                                                           boolean allowAllHosts) throws Exception {

        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // 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);

        // Create a connection from url
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

        // skip hostname security check if specified
        if (allowAllHosts) {
            urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        return urlConnection;
    }

    private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
        // init a default key store
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);

        // read and add certificate authority
        Certificate cert = readCert(context, certRawResId);
        keyStore.setCertificateEntry("ca", cert);

        return keyStore;
    }

    private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {

        // read certificate resource
        InputStream caInput = context.getResources().openRawResource(certResourceId);

        Certificate ca;
        try {
            // generate a certificate
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ca = cf.generateCertificate(caInput);
        } finally {
            caInput.close();
        }

        return ca;
    }

}

Những điểm chính:

  1. Certificatecác đối tượng được tạo ra từ .crtcác tập tin.
  2. Một mặc định KeyStoređược tạo ra.
  3. keyStore.setCertificateEntry("ca", cert)đang thêm chứng chỉ vào kho lưu trữ dưới bí danh "ca". Bạn sửa đổi mã để thêm nhiều chứng chỉ (CA trung gian, v.v.).
  4. Mục tiêu chính là tạo ra một SSLSocketFactorycái mà sau đó có thể được sử dụng bởi HTTPClienthoặc HttpsURLConnection.
  5. SSLSocketFactory có thể được cấu hình thêm, ví dụ để bỏ qua xác minh tên máy chủ, v.v.

Thêm thông tin tại: http://developer.android.com/training/articles/security-ssl.html


Tôi có thể lấy .crttập tin ở đâu? Tải xuống từ máy chủ?
zionpi

@zionpi Tệp chứng chỉ sẽ được sử dụng tương tự bởi máy chủ hỗ trợ TLS mà bạn đang kết nối.
SD

Cảm ơn! Điều này thật dễ dàng!
kapil thadani

@SD Làm cách nào tôi có thể sử dụng tệp .P12 thay vì .crt?
Rakesh R Nair

Tôi có một nghi ngờ tương tự, bạn vui lòng giúp stackoverflow.com/questions/57389622/ cấp
StezPet

8

Tôi đã thất vọng khi cố gắng kết nối Ứng dụng Android của mình với dịch vụ RESTful bằng https. Ngoài ra tôi đã có một chút khó chịu về tất cả các câu trả lời đề nghị vô hiệu hóa kiểm tra chứng chỉ hoàn toàn. Nếu bạn làm như vậy, điểm của https là gì?

Sau khi googled về chủ đề này một thời gian, cuối cùng tôi đã tìm thấy giải pháp này , nơi không cần bình bên ngoài, chỉ cần API Android. Cảm ơn Andrew Smith, người đã đăng nó vào tháng 7 năm 2014

 /**
 * Set up a connection to myservice.domain using HTTPS. An entire function
 * is needed to do this because myservice.domain has a self-signed certificate.
 * 
 * The caller of the function would do something like:
 * HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
 * InputStream in = urlConnection.getInputStream();
 * And read from that "in" as usual in Java
 * 
 * Based on code from:
 * https://developer.android.com/training/articles/security-ssl.html#SelfSigned
 */
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
    try
    {
        // Load CAs from an InputStream
        // (could be from a resource or ByteArrayInputStream or ...)
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        // My CRT file that I put in the assets folder
        // I got this file by following these steps:
        // * Go to https://littlesvr.ca using Firefox
        // * Click the padlock/More/Security/View Certificate/Details/Export
        // * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
        // The MainActivity.context is declared as:
        // public static Context context;
        // And initialized in MainActivity.onCreate() as:
        // MainActivity.context = getApplicationContext();
        InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
        Certificate ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

        // 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 context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        // Tell the URLConnection to use a SocketFactory from our SSLContext
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());

        return urlConnection;
    }
    catch (Exception ex)
    {
        Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
        return null;
    }
}

Nó hoạt động tốt cho ứng dụng mockup của tôi.


X509Certert tôi nên nhập java hoặc javax nào?
Siddharth

Tôi đã nhậpimport java.security.cert.X509Certificate;
Gonzalo Fernández

Cảm ơn vì điều này. Nó thực sự hiệu quả và đơn giản
Anuradhe Dilshan

6

Câu trả lời hàng đầu đã làm việc với tôi. Sau một số điều tra, tôi đã tìm thấy thông tin bắt buộc về "Nhà phát triển Android": https://developer.android.com/training/articles/security-ssl.html#SelfSign

Tạo một triển khai X509TrustManager trống đã thực hiện thủ thuật:

private static class MyTrustManager implements X509TrustManager
{

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
         throws CertificateException
    {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers()
    {
        return null;
    }

}

...

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    TrustManager[] tmlist = {new MyTrustManager()};
    context.init(null, tmlist, null);
    conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
    throw new IOException(e);
} catch (KeyManagementException e)
{
    throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();

Xin lưu ý rằng việc triển khai TustManager trống rỗng này chỉ là một ví dụ và sử dụng nó trong môi trường sản xuất sẽ gây ra mối đe dọa bảo mật nghiêm trọng!


1
chỉ fyi - idk nếu nó là như thế vào thời điểm đó, nhưng họ dường như ngăn cản mạnh mẽ phương pháp này ngay bây giờ (xem ghi chú)
Saik Caskey

6

Google khuyến nghị sử dụng Android Volley cho các kết nối HTTP / HTTPS , vì điều đó HttpClientkhông được chấp nhận. Vì vậy, bạn biết lựa chọn đúng :).

Ngoài ra, KHÔNG BAO GIỜ Chứng nhận SSL NUKE (KHÔNG BAO GIỜ !!!).

Đối với chứng chỉ SSL, hoàn toàn trái với mục đích của SSL, đó là thúc đẩy bảo mật . Không có ý nghĩa sử dụng SSL, nếu bạn dự định đánh bom tất cả các chứng chỉ SSL đi kèm. Một giải pháp tốt hơn sẽ là, không sử dụng SSL hoặc giải pháp tốt hơn, sẽ tạo một tùy chỉnh TrustManagertrên Ứng dụng + của bạn bằng cách sử dụng Android Volley cho các kết nối HTTP / HTTPS.

Đây là một Gist mà tôi đã tạo, với một Ứng dụng cơ bản, thực hiện các kết nối HTTPS, sử dụng Chứng chỉ tự ký ở phía máy chủ, được chấp nhận trên Ứng dụng.

Đây cũng là một Gist khác có thể giúp ích, để tạo Chứng chỉ SSL tự ký để thiết lập trên Máy chủ của bạn và cũng sử dụng chứng chỉ trên Ứng dụng của bạn. Rất quan trọng: bạn phải sao chép tệp .crt được tạo bởi tập lệnh ở trên, vào thư mục "thô" từ dự án Android của bạn.


Xin chào Ivan, tôi chưa bao giờ làm việc với chứng chỉ SSL. Bạn có quan tâm để xây dựng một chút, làm thế nào để tôi có được tệp .crt?
jlively

Chào Jively! Tôi hiểu rồi. Phải, tất nhiên. Nhưng trước tiên, bạn có phiền khi xem Gist thứ hai mà tôi đã đề cập ở trên không? Tôi đã đưa ra hai tệp trên Gist này: một là tệp được sử dụng bởi tập lệnh và tệp kia, là chính tập lệnh, sử dụng tệp nhị phân "openssl" để đọc tệp và sau đó, xây dựng tệp chứa Chứng chỉ SSL ( .crt). Hãy cho tôi biết nếu bạn quản lý để hiểu toàn bộ. Trân trọng :).
ivanleoncz

Hmm vâng, tôi đã xem xét 2 ý chính đó, nhưng tôi thực sự không thể hiểu làm thế nào để tôi sử dụng chúng?
jlively

4

Đây là cách bạn có thể thêm chứng chỉ bổ sung vào KeyStore để tránh sự cố này: Tin tưởng tất cả các chứng chỉ bằng cách sử dụng HttpClient qua HTTPS

Nó sẽ không nhắc người dùng như bạn hỏi, nhưng điều đó sẽ khiến người dùng ít gặp phải lỗi "Chứng chỉ máy chủ không đáng tin cậy".


Chỉ nhằm mục đích thử nghiệm, bạn không thể xuất bản một ứng dụng trong Cửa hàng Play với thủ thuật này vì nó sẽ bị từ chối
ariel

3

Cách đơn giản nhất để tạo chứng chỉ SSL

Mở Firefox (Tôi cho rằng cũng có thể với Chrome, nhưng với FF dễ hơn)

Truy cập trang web phát triển của bạn với chứng chỉ SSL tự ký.

Bấm vào chứng chỉ (bên cạnh tên trang web)

Nhấp vào "Thông tin thêm"

Nhấp vào "Xem chứng chỉ"

Nhấp vào "Chi tiết"

Nhấp vào "Xuất ..."

Chọn "Chuỗi chứng chỉ X.509 (PEM)", chọn thư mục và tên để lưu và nhấp vào "Lưu"

Đi đến dòng lệnh, đến thư mục mà bạn đã tải xuống tệp pem và thực thi "openssl x509 -inform PEM -outform DM -in .pem -out .crt"

Sao chép tệp .crt vào thư mục gốc của thư mục / sdcard bên trong thiết bị Android Bên trong thiết bị Android của bạn, Cài đặt> Bảo mật> Cài đặt từ bộ lưu trữ.

Nó sẽ phát hiện chứng chỉ và cho phép bạn thêm nó vào thiết bị Duyệt đến trang web phát triển của bạn.

Lần đầu tiên nó sẽ yêu cầu bạn xác nhận ngoại lệ bảo mật. Đó là tất cả.

Chứng chỉ sẽ hoạt động với mọi trình duyệt được cài đặt trên Android của bạn (Trình duyệt, Chrome, Opera, Cá heo ...)

Hãy nhớ rằng nếu bạn đang phục vụ các tệp tĩnh của mình từ một tên miền khác (tất cả chúng ta đều là chó cái tốc độ trang), bạn cũng cần thêm chứng chỉ cho tên miền đó.


2

Tôi đã viết thư viện nhỏ ssl-utils-android để tin tưởng chứng chỉ cụ thể trên Android.

Bạn chỉ có thể tải bất kỳ chứng chỉ nào bằng cách cho tên tệp từ thư mục tài sản.

Sử dụng:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());

1

Không có bản sửa lỗi nào hoạt động cho nền tảng phát triển của tôi nhắm mục tiêu SDK 16, Phiên bản 4.1.2, vì vậy tôi đã tìm thấy một cách giải quyết.

Ứng dụng của tôi lưu trữ dữ liệu trên máy chủ bằng cách sử dụng " http://www.example.com/page.php?data=somedata "

Gần đây page.php đã được chuyển đến " https://www.secure-example.com/page.php " và tôi tiếp tục nhận được "javax.net.ssl.SSLException: Không tin cậy chứng chỉ máy chủ".

Thay vì chấp nhận tất cả các chứng chỉ cho một trang duy nhất, bắt đầu với hướng dẫn này, tôi đã giải quyết vấn đề của mình bằng cách viết page.php của riêng tôi được xuất bản trên " http://www.example.com/page.php "

<?php

caronte ("https://www.secure-example.com/page.php");

function caronte($url) {
    // build curl request
    $ch = curl_init();
    foreach ($_POST as $a => $b) {
        $post[htmlentities($a)]=htmlentities($b);
    }
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));

    // receive server response ...
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $server_output = curl_exec ($ch);
    curl_close ($ch);

    echo $server_output;
}

?>

1

Ngày 19 tháng 1 năm 2020 Giấy chứng nhận tự ký ISSUE FIX:

Để phát video, hình ảnh, gọi dịch vụ web cho bất kỳ chứng chỉ tự ký nào hoặc kết nối với bất kỳ url không bảo mật nào, chỉ cần gọi phương thức này trước khi thực hiện bất kỳ hành động nào, nó sẽ khắc phục vấn đề của bạn về vấn đề chứng chỉ:

MÃ KOTLINE

  private fun disableSSLCertificateChecking() {
        val hostnameVerifier = object: HostnameVerifier {
            override fun verify(s:String, sslSession: SSLSession):Boolean {
                return true
            }
        }
        val trustAllCerts = arrayOf<TrustManager>(object: X509TrustManager {
            override fun getAcceptedIssuers(): Array<X509Certificate> {
                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }

            //val acceptedIssuers:Array<X509Certificate> = null
            @Throws(CertificateException::class)
            override fun checkClientTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
            }
            @Throws(CertificateException::class)
            override fun checkServerTrusted(arg0:Array<X509Certificate>, arg1:String) {// Not implemented
            }
        })
        try
        {
            val sc = SSLContext.getInstance("TLS")
            sc.init(null, trustAllCerts, java.security.SecureRandom())
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
            HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier)
        }
        catch (e: KeyManagementException) {
            e.printStackTrace()
        }
        catch (e: NoSuchAlgorithmException) {
            e.printStackTrace()
        }
    }

0

Có lẽ điều này sẽ hữu ích ... nó hoạt động trên các máy khách java sử dụng chứng chỉ tự ký (không có kiểm tra chứng chỉ). Hãy cẩn thận và chỉ sử dụng nó cho các trường hợp phát triển vì điều đó không an toàn chút nào !!

Cách bỏ qua lỗi chứng chỉ SSL trong Apache HttpClient 4.0

Hy vọng nó sẽ hoạt động trên Android chỉ cần thêm thư viện HttpClient ... chúc may mắn !!


1
Không, nó không hoạt động trên Android vì nó phụ thuộc vào các phương thức không dùng nữa mà không có trong biến thể Android :-(
kellyfj

0

Đây là sự cố do thiếu hỗ trợ SNI (Nhận dạng tên máy chủ) trongA, ndroid 2.x. Tôi đã vật lộn với vấn đề này trong một tuần cho đến khi tôi gặp phải câu hỏi sau đây, nó không chỉ đưa ra một nền tảng tốt của vấn đề mà còn cung cấp một giải pháp hiệu quả và hiệu quả mà 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 ở 4

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.