簡單說一下 http 和https 的區(qū)別 http是應(yīng)用層協(xié)議 而https是http 的升級版 是網(wǎng)絡(luò)安全大趨勢之下的產(chǎn)物 在現(xiàn)有條件下 常規(guī)的http已經(jīng)無法保證數(shù)據(jù)和平臺的安全,所以https 已成大勢 目前的http 通過一些工具是可以抓取到數(shù)據(jù)的 例如Fiddler 毁涉,charles 就能輕易抓取http的請求數(shù)據(jù) 而https 則可以輕松避免這種抓取數(shù)據(jù)的方式
http 請求是通過 http + tcp 進行的應(yīng)用傳輸?shù)? 而https 則是在http 和 tcp 之間加了一層安全驗證也就是 SSL/TLS的驗證 數(shù)據(jù)證書驗證是使用CA證書(數(shù)據(jù)證書頒發(fā)機構(gòu)辦法的證書)進行密碼校驗 通過驗證才能進行網(wǎng)絡(luò)請求
下面說一下android 的https (以okhttp為例)
先說下本人的策略 使用二級緩存的方法進行證書加載 現(xiàn)在很多朋友大都是以硬編碼的方式或內(nèi)置證書的方式加載 本人覺得這種方式是不安全的 第一不安全是因為有意破壞者可以通過反編譯 或者 破解獲取你的證書 第二 ca證書是由時間限制的 如果時間到期 再去更換證書 而你只能通過強制更新才能讓用戶進行使用 這個會給用戶很不好的體驗
我的策略是 內(nèi)置加緩存的方式加載證書 首先緩存是需要權(quán)限的 若用戶沒有授權(quán) 則終端無法緩存 用戶也就無法正常使用 此時我使用內(nèi)置的 如果客戶授權(quán)了讀寫權(quán)限 我就是用緩存的 以此避免證書過期問題
證書驗證 也有兩種方式 第一 單項驗證(弱驗證)(服務(wù)器驗證客戶端攜帶的證書是否有效)第二 雙向驗證(強驗證) 客戶端驗證
服務(wù)端握手時返回的公鑰信息進行host驗證 服務(wù)器在驗證客戶端的數(shù)字簽名是否正確 一般雙向驗證是 瀏覽器金融類app等使用的較多 也是非常安全的一種方式 坪哄; 我使用的是第一種單項驗證 因為我的host是我自己設(shè)定好的 所以我沒有進行host 驗證
public class SSLUtil {
/**
* 獲取SSLSocketFactory
*
* @param certificates 證書流文件
* @return
*/
public static SSLSocketFactory getSSLSocketFactory(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());
return sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
返回SSLSocketFactory
// 網(wǎng)絡(luò)請求方法
OkHttpClient.Builder okBuilder = new OkHttpClient.Builder().addInterceptor(interceptor)
.writeTimeout(BaseConstant.NET_WRITE_TIME_OUT, TimeUnit.SECONDS)
.readTimeout(BaseConstant.NET_READ_TIME_OUT, TimeUnit.SECONDS)
.connectTimeout(BaseConstant.NET_REQUEST_TIME_OUT, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addInterceptor(new ErrorStatuInterceptor())
.addInterceptor(new PrintLogInterceptor());
if (CA.getCAFile()!=null){
if (SSLUtil.getSSLSocketFactory(CA.getCAByte()) != null){
okBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}).sslSocketFactory(SSLUtil.getSSLSocketFactory(CA.getCAByte()));
}
}else {
if (SSLUtil.getSSLSocketFactory(CA.getCAByte()) != null){
try {
okBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}).sslSocketFactory(SSLUtil.getSSLSocketFactory(UiUtils.getContext().getAssets().open("nade.cer")));
} catch (IOException e) {
e.printStackTrace();
}
// }).sslSocketFactory(SSLUtil.getSSLSocketFactory(CA.getCAByte()));
}
}
// 此方法用于驗證host 返回true 是不驗證
okBuilder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
這個可以可以根據(jù)需要進行驗證
好了 不多說 到此結(jié)束 有需要可以私信我