https簡介
現(xiàn)在網(wǎng)絡(luò)安全越來越受到重視,https作為更加安全的通信協(xié)議應(yīng)用也越來越廣泛。https相對與http有以下優(yōu)勢:
- 認(rèn)證用戶和服務(wù)器,確保數(shù)據(jù)發(fā)送到正確的客戶機(jī)和服務(wù)器;(驗(yàn)證證書)
- 加密數(shù)據(jù)以防止數(shù)據(jù)中途被竊??;(加密)
- 維護(hù)數(shù)據(jù)的完整性,確保數(shù)據(jù)在傳輸過程中不被改變。(摘要算法)
對于一個(gè)android開發(fā)來說,目前的網(wǎng)絡(luò)請求框架大部分都是使用okhttp進(jìn)行網(wǎng)絡(luò)請求的,okhttputils,或者retrofit, 所以了解okhttp是如何加載https請求的對于我們平時(shí)開發(fā)有很大的幫助。
訪問自簽名的網(wǎng)站
首先我們將.cer證書文件放到assets文件夾下,其實(shí)你可以隨便放哪,反正能讀取到就行。
然后在我們的OkHttpClientManager里面添加如下的方法:
public void setCertificates(InputStream... certificates) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
int index = 0;
for (InputStream certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
try {
if (certificate != null)
certificate.close();
} catch (IOException e) {
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init
(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
//.setSslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
為了代碼可讀性,我把異常捕獲的部分簡化了,可以看到我們提供了一個(gè)方法傳入InputStream流,InputStream就對應(yīng)于我們證書的輸入流。
代碼內(nèi)部,我們:
- 構(gòu)造
CertificateFactory對象,通過它的generateCertificate(is)方法得到Certificate。 - 然后講得到的
Certificate放入到keyStore中。 - 接下來利用keyStore去初始化我們的
TrustManagerFactory - 由
trustManagerFactory.getTrustManagers獲得TrustManager[]初始化我們的SSLContext - 最后,設(shè)置我們
mOkHttpClient.setSslSocketFactory即可。
這樣就完成了我們代碼的編寫,其實(shí)挺短的,當(dāng)客戶端進(jìn)行SSL連接時(shí),就可以根據(jù)我們設(shè)置的證書去決定是否新人服務(wù)端的證書。
記得在Application中進(jìn)行初始化:
public class MyApplication extends Application
{
@Override
public void onCreate()
{
super.onCreate();
try
{
OkHttpClientManager.getInstance()
.setCertificates(getAssets().open("srca.cer"));
} catch (IOException e)
{
e.printStackTrace();
}
}
然后我們就可以嘗試訪問自簽名的htpps服務(wù)器接口了。
使用字符串替代證書
下面繼續(xù),有些人可能覺得把證書copy到assets下還是覺得不舒服,其實(shí)我們還可以將證書中的內(nèi)容提取出來,寫成字符串常量,這樣就不需要證書根據(jù)著app去打包了。

使用keytool命令,以rfc樣式輸出。keytool命令是JDK里面自帶的。
有了這個(gè)字符串以后,我們就不需要srca.cer這個(gè)文件了,直接編寫以下代碼:
public class MyApplication extends Application
{
private String CER_12306 = "-----BEGIN CERTIFICATE-----\n" +
"MIICmjCCAgOgAwIBAgIIbyZr5/jKH6QwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ04xKTAn\n" +
"BgNVBAoTIFNpbm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMB4X\n" +
"DTA5MDUyNTA2NTYwMFoXDTI5MDUyMDA2NTYwMFowRzELMAkGA1UEBhMCQ04xKTAnBgNVBAoTIFNp\n" +
"bm9yYWlsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRTUkNBMIGfMA0GCSqGSIb3\n" +
"DQEBAQUAA4GNADCBiQKBgQDMpbNeb34p0GvLkZ6t72/OOba4mX2K/eZRWFfnuk8e5jKDH+9BgCb2\n" +
"9bSotqPqTbxXWPxIOz8EjyUO3bfR5pQ8ovNTOlks2rS5BdMhoi4sUjCKi5ELiqtyww/XgY5iFqv6\n" +
"D4Pw9QvOUcdRVSbPWo1DwMmH75It6pk/rARIFHEjWwIDAQABo4GOMIGLMB8GA1UdIwQYMBaAFHle\n" +
"tne34lKDQ+3HUYhMY4UsAENYMAwGA1UdEwQFMAMBAf8wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDov\n" +
"LzE5Mi4xNjguOS4xNDkvY3JsMS5jcmwwCwYDVR0PBAQDAgH+MB0GA1UdDgQWBBR5XrZ3t+JSg0Pt\n" +
"x1GITGOFLABDWDANBgkqhkiG9w0BAQUFAAOBgQDGrAm2U/of1LbOnG2bnnQtgcVaBXiVJF8LKPaV\n" +
"23XQ96HU8xfgSZMJS6U00WHAI7zp0q208RSUft9wDq9ee///VOhzR6Tebg9QfyPSohkBrhXQenvQ\n" +
"og555S+C3eJAAVeNCTeMS3N/M5hzBRJAoffn3qoYdAO1Q8bTguOi+2849A==\n" +
"-----END CERTIFICATE-----";
@Override
public void onCreate()
{
super.onCreate();
OkHttpClientManager.getInstance()
.setCertificates(new Buffer()
.writeUtf8(CER_12306)
.inputStream());
}
注意Buffer是okio包下的,okhttp依賴okio。
ok,這樣就省去將cer文件一起打包進(jìn)入apk了。
參考
- http://blog.csdn.net/hfeng101/article/details/10163627
- http://www.ibm.com/developerworks/cn/java/j-lo-socketkeytool/index.html?ca=drs
- http://sourceforge.net/projects/portecle/files/
- http://blog.sina.com.cn/s/blog_7035c6ac01017hrx.html
- http://blog.csdn.net/cuker919/article/details/7599969
- http://www.cnblogs.com/devinzhang/archive/2012/02/28/2371631.html