Rumah >Tutorial sistem >LINUX >Analisis prinsip HTTPS dan penggunaannya dalam Android

Analisis prinsip HTTPS dan penggunaannya dalam Android

王林
王林ke hadapan
2024-02-23 08:00:211084semak imbas
1. Kekurangan protokol HTTP

Apabila HTTP1.x menghantar data, semua kandungan yang dihantar adalah dalam teks yang jelas, baik pelanggan mahupun pelayan tidak boleh mengesahkan identiti pihak lain Masalah yang ada adalah seperti berikut:

  • Komunikasi menggunakan teks yang jelas (tidak disulitkan), dan kandungannya mungkin didengari;
  • Jika anda tidak mengesahkan identiti pihak yang berkomunikasi, anda mungkin menghadapi penyamaran;
  • Integriti mesej tidak dapat dibuktikan, jadi ia mungkin telah diusik;

Malah, masalah ini bukan sahaja berlaku dalam HTTP, tetapi juga dalam protokol lain yang tidak disulitkan.

(1) Komunikasi menggunakan teks yang jelas mungkin didengari

Menurut mekanisme kerja suite protokol TCP/IP, terdapat risiko kandungan komunikasi didengari di mana-mana sahaja di Internet. Protokol HTTP itu sendiri tidak mempunyai fungsi penyulitan, dan semua data yang dihantar adalah teks biasa. Walaupun komunikasi telah disulitkan, kandungan komunikasi akan diintip, yang sama seperti komunikasi tidak disulitkan. Ia hanya bermakna bahawa jika komunikasi disulitkan, mungkin mustahil untuk menguraikan maksud maklumat mesej, tetapi mesej yang disulitkan itu sendiri masih dapat dilihat.

(2) Kegagalan untuk mengesahkan identiti pihak yang berkomunikasi boleh menyebabkan penyamaran

Semasa komunikasi protokol HTTP, memandangkan tiada langkah pemprosesan untuk mengesahkan pihak yang berkomunikasi, sesiapa sahaja boleh memulakan permintaan. Di samping itu, selagi pelayan menerima permintaan, ia akan mengembalikan respons tidak kira siapa pihak lain. Oleh itu, jika pihak komunikasi tidak disahkan, terdapat bahaya tersembunyi berikut:

  • Adalah mustahil untuk menentukan sama ada pelayan web yang permintaan dihantar adalah yang mengembalikan respons mengikut niat sebenar. Ia mungkin pelayan web yang menyamar;
  • Tiada cara untuk menentukan sama ada pelanggan yang menerima respons itu adalah yang menerima respons seperti yang dimaksudkan. Ia mungkin pelanggan yang menyamar;
  • Adalah mustahil untuk menentukan sama ada pihak lain yang anda berkomunikasi mempunyai hak akses. Kerana sesetengah pelayan web menyimpan maklumat penting, mereka hanya mahu memberikan kebenaran komunikasi kepada pengguna tertentu;
  • Adalah mustahil untuk menentukan dari mana permintaan itu datang dan siapa yang membuatnya;
  • Malah permintaan yang tidak bermakna akan diterima seperti yang dipesan, tidak dapat menghalang serangan DoS di bawah permintaan besar-besaran;

(3) Keutuhan mesej tidak dapat dibuktikan dan ia mungkin telah diusik

Kesempurnaan yang dipanggil merujuk kepada ketepatan maklumat. Kegagalan untuk menunjukkan kesempurnaannya biasanya bermakna ia tidak boleh dinilai sama ada maklumat itu tepat. Protokol HTTP tidak dapat membuktikan integriti mesej komunikasi Dalam tempoh selepas permintaan atau respons dihantar sehingga pihak lain menerimanya, tidak ada cara untuk mengetahui walaupun kandungan permintaan atau respons telah diganggu.

Sebagai contoh, apabila memuat turun kandungan dari tapak web Web tertentu, adalah mustahil untuk menentukan sama ada fail yang dimuat turun oleh klien dan fail yang disimpan pada pelayan adalah konsisten. Kandungan fail mungkin telah diganggu dengan kandungan lain semasa penghantaran. Walaupun kandungan telah benar-benar berubah, pelanggan sebagai penerima tidak menyedarinya. Seperti ini, serangan di mana permintaan atau tindak balas dipintas oleh penyerang dan diusik dengan kandungan semasa penghantaran dipanggil serangan Man-in-the-Middle (MITM).

分析 HTTPS 原理以及在 Android 中的使用

(4) Beberapa ciri yang perlu ada pada versi HTTP selamat

Disebabkan masalah di atas, teknologi keselamatan HTTP yang boleh menyediakan fungsi berikut diperlukan:

(1) Pengesahan pelayan (pelanggan tahu mereka bercakap dengan pelayan sebenar dan bukan pelayan palsu);

(2) Pengesahan pelanggan (pelayan tahu mereka bercakap dengan pelanggan sebenar dan bukan pelanggan palsu);

(3) Integriti (data pada klien dan pelayan tidak akan diubah suai);

(4) Penyulitan (perbualan antara pelanggan dan pelayan adalah peribadi, tidak perlu risau tentang didengari);

(5) Kecekapan (algoritma yang berjalan cukup pantas untuk digunakan oleh pelanggan dan pelayan kelas bawah);

(6) Kesejagatan (pada asasnya semua pelanggan dan pelayan menyokong protokol ini);

2.Teknologi utama HTTPS

Dalam konteks permintaan sedemikian, teknologi HTTPS dilahirkan. Fungsi utama protokol HTTPS pada asasnya bergantung pada protokol TLS/SSL, yang menyediakan fungsi pengesahan, penyulitan maklumat dan pengesahan integriti, yang boleh menyelesaikan masalah keselamatan HTTP. Bahagian ini akan menumpukan pada beberapa perkara teknikal utama protokol HTTPS.

分析 HTTPS 原理以及在 Android 中的使用

(1) Teknologi Penyulitan

Algoritma penyulitan secara amnya dibahagikan kepada dua jenis:

Penyulitan simetri: Kunci untuk penyulitan dan penyahsulitan adalah sama. Diwakili oleh algoritma DES;

Penyulitan asimetri: Kekunci untuk penyulitan dan penyahsulitan adalah berbeza. Diwakili oleh algoritma RSA;

Penyulitan simetri sangat kuat dan secara amnya tidak boleh dipecahkan Walau bagaimanapun, masalah besar ialah kunci tidak boleh dijana dan disimpan dengan selamat Jika setiap sesi antara pelanggan dan pelayan menggunakan kunci tetap yang sama untuk penyulitan dan penyahsulitan menjadi risiko keselamatan yang besar.

Sebelum kemunculan algoritma pertukaran kunci asimetri, masalah besar dengan penyulitan simetri ialah tidak mengetahui cara menjana dan menyimpan kunci dengan selamat. Proses pertukaran kunci asimetri adalah terutamanya untuk menyelesaikan masalah ini dan menjadikan penjanaan dan penggunaan kunci lebih selamat. Tetapi ia juga merupakan "penyebab" yang mengurangkan prestasi dan kelajuan HTTPS dengan teruk.

HTTPS menggunakan mekanisme penyulitan hibrid yang menggunakan kedua-dua penyulitan simetri dan penyulitan asimetri Ia menggunakan penyulitan asimetri dalam proses pertukaran kunci, dan menggunakan penyulitan simetri dalam peringkat komunikasi dan pertukaran mesej seterusnya.

(2) Pengesahan – Sijil membuktikan ketepatan kunci awam

Salah satu masalah terbesar dengan penyulitan asimetri ialah ia tidak dapat membuktikan bahawa kunci awam itu sendiri ialah kunci awam tulen. Sebagai contoh, semasa bersiap sedia untuk mewujudkan komunikasi dengan pelayan tertentu menggunakan penyulitan kunci awam, bagaimana untuk membuktikan bahawa kunci awam yang diterima ialah kunci awam yang dikeluarkan oleh pelayan yang dijangkakan pada asalnya. Mungkin semasa penghantaran kunci awam, kunci awam sebenar telah digantikan oleh penyerang.

Jika kebolehpercayaan kunci awam tidak disahkan, akan terdapat sekurang-kurangnya dua masalah berikut: serangan man-in-the-middle dan penafian maklumat.

分析 HTTPS 原理以及在 Android 中的使用

Untuk menyelesaikan masalah di atas, anda boleh menggunakan sijil kunci awam yang dikeluarkan oleh pihak berkuasa pensijilan sijil digital (CA, Pihak Berkuasa Sijil) dan agensi berkaitan mereka.

分析 HTTPS 原理以及在 Android 中的使用

Proses khusus untuk menggunakan CA adalah seperti berikut:

(1) Pengendali pelayan memohon kunci awam kepada pihak berkuasa pensijilan sijil digital (CA);

(2) CA mengesahkan kesahihan maklumat yang diberikan oleh pemohon melalui cara dalam talian, luar talian dan lain-lain, seperti sama ada organisasi itu wujud, sama ada perusahaan itu sah, sama ada ia mempunyai pemilikan nama domain, dsb.;

(3) Jika maklumat diluluskan, CA akan menandatangani kunci awam yang digunakan secara digital, kemudian mengedarkan kunci awam yang ditandatangani, memasukkan kunci awam ke dalam sijil kunci awam dan mengikatnya bersama-sama. Sijil mengandungi maklumat berikut: kunci awam pemohon, maklumat organisasi dan maklumat peribadi pemohon, maklumat pihak berkuasa yang mengeluarkan CA, masa sah, nombor siri sijil dan maklumat lain dalam teks biasa, dan juga mengandungi tandatangan; Algoritma penjanaan tandatangan: pertama, gunakan cincang Fungsi lajur mengira ringkasan maklumat maklumat teks biasa awam, dan kemudian menggunakan kunci peribadi CA untuk menyulitkan ringkasan maklumat, dan teks sifir ialah tandatangan;

(4) Pelanggan menghantar permintaan kepada pelayan semasa fasa jabat tangan HTTPS, meminta pelayan memulangkan fail sijil;

(5) Pelanggan membaca maklumat teks biasa yang berkaitan dalam sijil, menggunakan fungsi cincang yang sama untuk mengira ringkasan maklumat, kemudian menggunakan kunci awam CA yang sepadan untuk menyahsulit data tandatangan dan membandingkan ringkasan maklumat sijil. Kalau konsisten boleh Confirm kesahihan sijil iaitu public key tu sah;

(6) Pelanggan kemudiannya mengesahkan maklumat nama domain, masa sah dan maklumat lain yang berkaitan dengan sijil;

(7) Pelanggan akan mempunyai maklumat sijil CA amanah terbina dalam (termasuk kunci awam Jika CA tidak dipercayai, sijil yang sepadan dengan CA tidak akan ditemui dan sijil itu akan dinilai sebagai menyalahi undang-undang).

Beri perhatian kepada beberapa perkara semasa proses ini:

(1) Tidak perlu menyediakan kunci persendirian semasa memohon sijil, memastikan kunci persendirian hanya boleh dikuasai oleh pelayan selama-lamanya;

(2) Kesahihan sijil masih bergantung pada algoritma penyulitan asimetri Sijil terutamanya menambah maklumat pelayan dan tandatangan;

(3) Sijil yang sepadan dengan CA terbina dalam dipanggil sijil akar; pengeluar dan pengguna adalah sama, dan mereka menandatangani untuk diri mereka sendiri, yang dipanggil sijil ditandatangani sendiri;

(4) Sijil = kunci awam + maklumat pemohon dan pengeluar + tandatangan

3.Prinsip protokol HTTPS

(1) Sejarah HTTPS

Pengenalan kepada sejarah protokol HTTPS:

  • (1) Versi pertama protokol SSL telah dibangunkan oleh Netscape, tetapi versi ini tidak pernah dikeluarkan;
  • (2) Versi kedua protokol SSL telah dikeluarkan pada November 1994. Arahan pertama adalah pada pelayar Netscape Navigator 1.1, dikeluarkan pada Mac 1995;
  • (3) SSL 3 telah dikeluarkan pada penghujung tahun 1995. Walaupun namanya sama dengan versi protokol terdahulu, SSL3 ialah protokol yang direka bentuk semula sepenuhnya, dan reka bentuknya masih digunakan sehingga kini.
  • (4) TLS 1.0 keluar pada Januari 1999. Berbanding dengan SSL 3, pengubahsuaian versi tidak besar;
  • (5) Pada April 2006, versi seterusnya TLS 1.1 telah dikeluarkan, yang hanya membetulkan beberapa isu keselamatan utama;
  • (6) Pada Ogos 2008, TLS1.2 telah dikeluarkan. Keluaran ini menambah sokongan untuk penyulitan yang disahkan dan pada asasnya mengalih keluar semua primitif keselamatan berkod keras daripada perihalan protokol, menjadikan protokol berdaya tahan sepenuhnya

(2) Pelaksanaan protokol

Secara makroskopik, TLS dilaksanakan oleh protokol rekod. Protokol rekod bertanggungjawab untuk menukar semua mesej peringkat rendah melalui sambungan pengangkutan dan boleh dikonfigurasikan untuk penyulitan. Setiap rekod TLS bermula dengan pengepala pendek. Pengepala mengandungi jenis (atau subprotokol), versi protokol dan panjang kandungan rekod. Data mesej mengikut pengepala seperti yang ditunjukkan di bawah:

分析 HTTPS 原理以及在 Android 中的使用

Spesifikasi induk TLS mentakrifkan empat sub-protokol teras:

  • protokol jabat tangan;
  • tukar protokol spesifikasi sifir;
  • protokol data aplikasi;
  • Protokol amaran;

(3) Perjanjian Jabat Tangan

Jabatan tangan adalah bahagian paling canggih dalam protokol TLS. Semasa proses ini, pihak yang berkomunikasi merundingkan parameter sambungan dan pengesahan identiti lengkap. Bergantung pada fungsi yang digunakan, keseluruhan proses biasanya memerlukan pertukaran 6 hingga 10 mesej. Mungkin terdapat banyak variasi proses pertukaran bergantung pada konfigurasi dan sambungan protokol yang disokong. Tiga proses berikut selalunya boleh diperhatikan dalam penggunaan:

  • (1) Selesaikan jabat tangan untuk mengesahkan pelayan (pengesahan sehala, yang paling biasa);
  • (2) Jabat tangan yang mengesahkan kedua-dua pelanggan dan pelayan (pengesahan dua hala);
  • (3) Jabat tangan ringkas digunakan untuk memulihkan sesi sebelumnya;

(4) Proses jabat tangan pengesahan sehala

Bahagian ini mengambil proses log masuk peti mel QQ sebagai contoh untuk menganalisis proses jabat tangan pengesahan sehala dengan menangkap paket. Proses jabat tangan yang lengkap untuk pengesahan sehala adalah seperti berikut:

分析 HTTPS 原理以及在 Android 中的使用

Ia terbahagi terutamanya kepada empat langkah:

  • (1) Tukar fungsi yang disokong oleh setiap satu dan bersetuju dengan parameter sambungan yang diperlukan;
  • (2) Sahkan sijil yang dikemukakan, atau gunakan kaedah lain untuk pengesahan;
  • (3) Setuju tentang kunci induk kongsi yang akan digunakan untuk melindungi sesi;
  • (4) Sahkan sama ada mesej jabat tangan telah diubah suai oleh pihak ketiga;

Proses ini dianalisis secara terperinci di bawah.

1.PelangganHello

Dalam proses berjabat tangan, ClientHello ialah mesej pertama. Mesej ini menyampaikan keupayaan dan pilihan pelanggan kepada pelayan. Mengandungi versi SSL yang ditentukan yang disokong oleh klien dan senarai Cipher Suite (algoritma penyulitan digunakan, panjang kunci, dsb.).

分析 HTTPS 原理以及在 Android 中的使用

2.ServerHello

MesejServerHello menghantar parameter sambungan yang dipilih oleh pelayan kembali kepada klien. Struktur mesej ini serupa dengan ClientHello, kecuali setiap medan mengandungi hanya satu pilihan. Kandungan komponen penyulitan pelayan dan kaedah mampatan semuanya ditapis daripada komponen penyulitan klien yang diterima.

分析 HTTPS 原理以及在 Android 中的使用

3.Sijil

Kemudian pelayan menghantar mesej Sijil, yang mengandungi sijil kunci awam Pelayan mesti memastikan sijil yang dihantar adalah konsisten dengan suite algoritma yang dipilih. Walau bagaimanapun, mesej Sijil adalah pilihan kerana tidak semua pakej menggunakan pengesahan, dan bukan semua kaedah pengesahan memerlukan sijil.

分析 HTTPS 原理以及在 Android 中的使用

4.ServerKeyExchange

Tujuan mesej ServerKeyExchange adalah untuk membawa data tambahan untuk pertukaran kunci. Kandungan mesej akan berbeza untuk suite algoritma perundingan yang berbeza. Dalam sesetengah senario, pelayan tidak perlu menghantar apa-apa, dan dalam senario ini tidak perlu menghantar mesej ServerKeyExchange.

分析 HTTPS 原理以及在 Android 中的使用

5.ServerHelloDone

Mesej

ServerHelloDone menunjukkan bahawa pelayan telah selesai menghantar semua mesej jabat tangan yang dijangkakan. Selepas ini, pelayan menunggu untuk pelanggan menghantar mesej.

分析 HTTPS 原理以及在 Android 中的使用

6.ClientKeyExchange

Mesej ClientKeyExchange membawa semua maklumat yang diberikan oleh pelanggan untuk pertukaran kunci. Mesej ini dipengaruhi oleh suite sifir yang dirundingkan dan kandungannya berbeza dengan suite sifir yang dirundingkan yang berbeza.

分析 HTTPS 原理以及在 Android 中的使用

7.ChangeCipherSpec

Mesej

ChangeCipherSpec menunjukkan bahawa pengirim telah memperoleh maklumat yang mencukupi untuk menjana parameter sambungan, telah menghasilkan kunci penyulitan dan akan bertukar kepada mod penyulitan. Kedua-dua pelanggan dan pelayan akan menghantar mesej ini apabila keadaan sudah masak. Nota: ChangeCipherSpec bukan milik mesej jabat tangan Ia adalah protokol lain dengan hanya satu mesej, dilaksanakan sebagai sub-protokolnya.

分析 HTTPS 原理以及在 Android 中的使用

8.Selesai

Mesej selesai bermakna jabat tangan telah selesai. Kandungan mesej akan disulitkan supaya kedua-dua pihak boleh menukar data yang diperlukan dengan selamat untuk mengesahkan integriti keseluruhan jabat tangan. Kedua-dua pelanggan dan pelayan akan menghantar mesej ini apabila keadaan sudah masak.

(5) Proses jabat tangan pengesahan dua hala

Dalam sesetengah senario dengan keperluan keselamatan yang lebih tinggi, keperluan untuk pengesahan dua hala mungkin timbul. Proses pengesahan dua hala yang lengkap adalah seperti berikut:

分析 HTTPS 原理以及在 Android 中的使用

Anda boleh melihat bahawa berbanding dengan proses pengesahan sehala, pengesahan dua hala mempunyai dua lagi mesej berikut: Permintaan Sijil dan Pengesahan Sijil Selebihnya adalah lebih kurang sama.

1.Permintaan Sijil

Permintaan Sijil ialah ciri pilihan yang ditentukan oleh TLS dan digunakan oleh pelayan untuk mengesahkan identiti pelanggan. Dilaksanakan oleh pelayan yang meminta pelanggan menghantar sijil, pelayan harus menghantar mesej CertificateRequest serta-merta selepas ServerKeyExchange.

Struktur mesej adalah seperti berikut:

enum { 
    rsa_sign(1), dss_sign(2), rsa_fixed_dh(3),dss_fixed_dh(4), 
    rsa_ephemeral_dh_RESERVED(5),dss_ephemeral_dh_RESERVED(6), 
    fortezza_dms_RESERVED(20), 
    ecdsa_sign(64), rsa_fixed_ecdh(65), 
    ecdsa_fixed_ecdh(66),  
    (255) 
} ClientCertificateType; 

opaque DistinguishedName<1..2^16-1>;struct { 
    ClientCertificateType certificate_types<1..2^8-1>; 
    SignatureAndHashAlgorithm 
      supported_signature_algorithms<2^16-1>; 
    DistinguishedName certificate_authorities<0..2^16-1>; 
} CertificateRequest;

Anda boleh menghantar senarai pihak berkuasa sijil yang diterima secara pilihan, diwakili oleh nama mereka yang terkenal.

2.SijilSahkan

Apabila pengesahan pelanggan diperlukan, pelanggan menghantar mesej CertificateVerify untuk membuktikan bahawa ia sememangnya memiliki kunci peribadi sijil pelanggan. Mesej ini hanya dihantar jika sijil pelanggan mempunyai keupayaan menandatangani. CertificateVerify mesti segera mengikuti ClientKeyExchange. Struktur mesej adalah seperti berikut:

struct {  
Signature handshake_messages_signature;  
} CertificateVerify;

(6) protokol data aplikasi

Protokol data aplikasi membawa mesej aplikasi Jika kita hanya memikirkannya dari perspektif TLS, ini adalah penimbal data. Merakam pakej lapisan, defragmen dan menyulitkan mesej ini menggunakan parameter keselamatan sambungan semasa. Seperti yang ditunjukkan dalam rajah di bawah, anda dapat melihat bahawa data yang dihantar telah disulitkan.

分析 HTTPS 原理以及在 Android 中的使用

(7) protokol amaran

Tujuan penggera adalah untuk memberitahu rakan sebaya tentang keadaan komunikasi yang tidak normal melalui mekanisme pemberitahuan yang mudah. Ia biasanya membawa pengecualian close_notify, yang digunakan apabila sambungan ditutup untuk melaporkan ralat. Makluman adalah sangat mudah, dengan hanya dua medan:

struct {  
    AlertLevel level;  
    AlertDescription description;  
} Alert;
  • Medan AlertLevel: Menunjukkan keterukan amaran;
  • AlertDescription: secara langsung mewakili kod amaran;
4. Soalan lazim tentang menggunakan HTTPS dalam Android

(1) 服务器证书验证错误

这是最常见的一种问题,通常会抛出如下类型的异常:

分析 HTTPS 原理以及在 Android 中的使用

出现此类错误通常可能由以下的三种原因导致:

  • (1) 颁发服务器证书的CA未知;
  • (2) 服务器证书不是由CA签署的,而是自签署(比较常见);
  • (3) 服务器配置缺少中间 CA;

当服务器的CA不被系统信任时,就会发生 SSLHandshakeException。可能是购买的CA证书比较新,Android系统还未信任,也可能是服务器使用的是自签名证书(这个在测试阶段经常遇到)。

解决此类问题常见的做法是:指定HttpsURLConnection信任特定的CA集合。在本文的第5部分代码实现模块,会详细的讲解如何让Android应用信任自签名证书集合或者跳过证书校验的环节。

(2) 域名验证失败

SSL连接有两个关键环节。首先是验证证书是否来自值得信任的来源,其次确保正在通信的服务器提供正确的证书。如果没有提供,通常会看到类似于下面的错误:

分析 HTTPS 原理以及在 Android 中的使用

出现此类问题的原因通常是由于服务器证书中配置的域名和客户端请求的域名不一致所导致的。

有两种解决方案:

(1) 重新生成服务器的证书,用真实的域名信息;

(2) 自定义HostnameVerifier,在握手期间,如果URL的主机名和服务器的标识主机名不匹配,则验证机制可以回调此接口的实现程序来确定是否应该允许此连接。可以通过自定义HostnameVerifier实现一个白名单的功能。

代码如下:

HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() { 
  @Override 
  public boolean verify(String hostname, SSLSession session) { 
    // 设置接受的域名集合 
    if (hostname.equals(...))  { 
         return true; 
    } 
  } 
}; 

HttpsURLConnection.setDefaultHostnameVerifier(DO_NOT_VERIFY);

(3) 客户端证书验证

SSL支持服务端通过验证客户端的证书来确认客户端的身份。这种技术与TrustManager的特性相似。本文将在第5部分代码实现模块,讲解如何让Android应用支持客户端证书验证的方式。

(4) Android上TLS版本兼容问题

之前在接口联调的过程中,测试那边反馈过一个问题是在Android 4.4以下的系统出现HTTPS请求不成功而在4.4以上的系统上却正常的问题。相应的错误如下:

03-09 09:21:38.427: W/System.err(2496): javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb7fa0620: Failure in SSL library, usually a protocol error 

03-09 09:21:38.427: W/System.err(2496): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:741 0xa90e6990:0x00000000)

按照官方文档的描述,Android系统对SSL协议的版本支持如下:

分析 HTTPS 原理以及在 Android 中的使用

也就是说,按官方的文档显示,在API 16+以上,TLS1.1和TLS1.2是默认开启的。但是实际上在API 20+以上才默认开启,4.4以下的版本是无法使用TLS1.1和TLS 1.2的,这也是Android系统的一个bug。

参照stackoverflow上的一些方式,比较好的一种解决方案如下:

SSLSocketFactory noSSLv3Factory; 
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { 
    noSSLv3Factory = new TLSSocketFactory(mSSLContext.getSSLSocket().getSocketFactory()); 
} else { 
    noSSLv3Factory = mSSLContext.getSSLSocket().getSocketFactory(); 
}

对于4.4以下的系统,使用自定义的TLSSocketFactory,开启对TLS1.1和TLS1.2的支持,核心代码:

public class TLSSocketFactory extends SSLSocketFactory { 

    private SSLSocketFactory internalSSLSocketFactory; 

    public TLSSocketFactory() throws KeyManagementException, NoSuchAlgorithmException { 
        SSLContext context = SSLContext.getInstance("TLS"); 
        context.init(null, null, null); 
        internalSSLSocketFactory = context.getSocketFactory(); 
    } 

    public TLSSocketFactory(SSLSocketFactory delegate) throws KeyManagementException, NoSuchAlgorithmException { 
        internalSSLSocketFactory = delegate; 
    } 

    ...... 

    @Override 
    public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { 
        return enableTLSOnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort)); 
    } 

    // 开启对TLS1.1和TLS1.2的支持 
    private Socket enableTLSOnSocket(Socket socket) { 
        if(socket != null && (socket instanceof SSLSocket)) { 
            ((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.1", "TLSv1.2"}); 
        } 
        return socket; 
    } 
}
5.代码实现

本部分主要基于第四部分提出的Android应用中使用HTTPS遇到的一些常见的问题,给出一个比较系统的解决方案。

(1) 整体结构

不管是使用自签名证书,还是采取客户端身份验证,核心都是创建一个自己的KeyStore,然后使用这个KeyStore创建一个自定义的SSLContext。整体类图如下:

分析 HTTPS 原理以及在 Android 中的使用

类图中的MySSLContext可以应用在HttpURLConnection的方式与服务端连接的过程中:

if (JarConfig.__self_signed_https) { 
    SSLContextByTrustAll mSSLContextByTrustAll = new SSLContextByTrustAll(); 
    MySSLContext mSSLContext = new MySSLContext(mSSLContextByTrustAll); 
   SSLSocketFactory noSSLv3Factory; 
   if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { 
        noSSLv3Factory = new TLSSocketFactory(mSSLContext.getSSLSocket().getSocketFactory()); 
    } else { 
        noSSLv3Factory = mSSLContext.getSSLSocket().getSocketFactory(); 
    } 

    httpsURLConnection.setSSLSocketFactory(noSSLv3Factory); 
    httpsURLConnection.setHostnameVerifier(MY_DOMAIN_VERIFY); 
}else { 
    httpsURLConnection.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault()); 
    httpsURLConnection.setHostnameVerifier(DO_NOT_VERIFY); 
}

核心是通过httpsURLConnection.setSSLSocketFactory使用自定义的校验逻辑。整体设计上使用策略模式决定采用哪种验证机制:

  • makeContextWithCilentAndServer 单向验证方式(自定义信任的证书集合)
  • makeContextWithServer 双向验证方式(自定义信任的证书集合,并使用客户端证书)
  • makeContextToTrustAll (信任所有的CA证书,不安全,仅供测试阶段使用)

(2) 单向验证并自定义信任的证书集合

在App中,把服务端证书放到资源文件下(通常是asset目录下,因为证书对于每一个用户来说都是相同的,并且也不会经常发生改变),但是也可以放在设备的外部存储上。

public class SSLContextWithServer implements GetSSLSocket { 

    // 在这里进行服务器正式的名称的配置 
    private String[] serverCertificateNames = {"serverCertificateNames1" ,"serverCertificateNames2"}; 

    @Override 
    public SSLContext getSSLSocket() { 
        String[] caCertString = new String[serverCertificateNames.length]; 
        for(int i = 0 ; i < serverCertificateNames.length ; i++) { 
            try { 
                caCertString[i] = readCaCert(serverCertificateNames[i]); 
            } catch(Exception e) { 

            } 
        } 
        SSLContext mSSLContext = null; 
        try { 
            mSSLContext = SSLContextFactory.getInstance().makeContextWithServer(caCertString); 
        } catch(Exception e) { 

        } 
        return mSSLContext; 
    }

serverCertificateNames中定义了App所信任的证书名称(这些证书文件必须要放在指定的文件路径下,并其要保证名称相同),而后就可以加载服务端证书链到keystore,通过获取到的可信任并带有服务端证书的keystore,就可以用它来初始化自定义的SSLContext了:

@Override 
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        try { 
            originalX509TrustManager.checkServerTrusted(chain, authType); 
        } catch(CertificateException originalException) { 
            try { 
                X509Certificate[] reorderedChain = reorderCertificateChain(chain); 
                CertPathValidator validator = CertPathValidator.getInstance("PKIX"); 
                CertificateFactory factory = CertificateFactory.getInstance("X509"); 
                CertPath certPath = factory.generateCertPath(Arrays.asList(reorderedChain)); 
                PKIXParameters params = new PKIXParameters(trustStore); 
                params.setRevocationEnabled(false); 
                validator.validate(certPath, params); 
            } catch(Exception ex) { 
                throw originalException; 
            } 
        } 
    }

(3) 跳过证书校验过程

和上面的过程类似,只不过这里提供的TrustManager不需要提供信任的证书集合,默认接受任意客户端证书即可:

public class AcceptAllTrustManager implements X509TrustManager { 

    @Override 
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        //do nothing,接受任意客户端证书 
    } 

    @Override 
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { 
        //do nothing,接受任意服务端证书 
    } 

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

而后构造相应的SSLContext:

public SSLContext makeContextToTrustAll() throws Exception { 
        AcceptAllTrustManager tm = new AcceptAllTrustManager(); 
        SSLContext sslContext = SSLContext.getInstance("TLS"); 
        sslContext.init(null, new TrustManager[] { tm }, null); 

        return sslContext; 
}

Atas ialah kandungan terperinci Analisis prinsip HTTPS dan penggunaannya dalam Android. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:linuxprobe.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam