由于2017年初開始禁止未使用https的應用上架appstore,領導們開始考慮在我們的應用中使用https,這讓我很頭疼,以前聽到過https,用httpwatch抓知乎、微信的包的時候都看到這些應用使用的都是https,對https感覺很熟悉,其實是一知半解的,這下要在應用中使用,看來必須要好好研究下了。
下面是研究https在簡書上搜索到的幾篇優秀文章:
http://www.jianshu.com/p/ce1557c1868d;
http://www.jianshu.com/p/d79b37216558;
http://www.jianshu.com/p/4494774963a9;
http://www.jianshu.com/p/7cdd2324f639;
要使用HTTPS肯定要知道一些概念,從上面幾篇優秀文章里找出來幾個必須要了解的概念:
1.HTTP:一種明文傳輸協議,交互過程以及數據傳輸都沒有進行加密,通信雙方沒有進行身份驗證,通信過程容易遭到劫持、篡改的安全問題。
2.SSL:安全套接層。
3.HTTPS:只是一種在HTTP協議的基礎上加了一層SSL的封裝,之后具有了以下三個特征:
數據完整性:數據傳輸經過完整性校驗
數據隱私性:數據經過加密
身份認證:第三方不能偽造客戶端或者服務端的身份
4.對稱加密:采用單密碼加密,同一個密鑰可以用來加密,也可以用來解密,簡單理解就是加解密都是用的同一個秘鑰。特點:體量小,算法公開,加密效率特別高。
5.非對稱加密:有2個秘鑰,一個是公開的秘鑰,一個是私有密鑰,這兩個是一對,互相配合加密和解密,公鑰加密用私鑰解密,私鑰加密公鑰解密。特點:速度慢,但是加 密很可靠
6.CA 證書:其實就是XXX機構頒發的一個包含公鑰和密鑰的證書。
下面用一張我畫的圖來理解下HTTPS的工作原理:
第一步:client向service發送一條請求,告訴service,client支持哪種算法(比如:對稱加密算法有DES,RC5,密鑰交換算法有RSA和DH,摘要算法有md5和SHA等)
第二步:service接收到client的消息后,分析之后,選擇一種client支持的算法,把證書發送給client的,這個證書里面包含了一些證書的基本信息(例如:失效時間,名稱,域名信息,公鑰等)
第三步:client接收到信息后,利用本地存在的數字證書對service的證書進行驗證,如果驗證失敗,會彈出一個提示框來顯示錯誤信息,驗證通過,生成一個隨機數,然后證書中的公鑰進行加密,發送給service
第四步:service接收到加密的隨機數之后,用公鑰進行解密,取出隨機數,然后把這個隨機數當做密鑰對要加密的內容進行對稱加密,發送給client
第五步:client接收到service發送的密文,用之前保存的隨機數作為密鑰進行解密,還原密文
第六步:之后client和service進行數據交互,利用那個隨機數作為密鑰進行加解密
到這里對很多https的概念還是很迷茫,比如數字認證識什么東東,在第二步的時候client是怎么驗證service的證書?,service怎么對client的身份做校驗,然后就反反復復又查資料,上面的問題都可以在下面的博客中找到
http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html
現在應該能到得到一個結論,證書可以由國際上公認的證書機構頒發,一般客戶端的證書驗證的應用程序對這些機構頒發的證書完全信任,不過一般情況下,我們會讓客戶端程序安裝我們服務端的根證書,保證客戶端可以信任我們的證書。
好了,廢話不多說,看代碼
/** * 初始化有證書的SSLContext * <p> * client.cer 是后臺申請提供的,不包含密鑰信息 * * @param context * @return * @throws NoSuchAlgorithmException * @throws IOException * @throws CertificateException * @throws KeyStoreException * @throws UnrecoverableKeyException * @throws KeyManagementException */public static SSLContext getSSLContextWithCer(Context context) throws NoSuchAlgorithmException, IOException, CertificateException, KeyStoreException, UnrecoverableKeyException, KeyManagementException { //實例化SSLContext SSLContext sslContext = SSLContext.getInstance("SSL"); // 從assets中加載證書,在HTTPS通訊中最常用的是cer/crt和pem InputStream inputStream = context.getAssets().open("client.cer"); // 證書工廠 CertificateFactory cerFactory = CertificateFactory.getInstance("X.509"); Certificate cer = cerFactory.generateCertificate(inputStream); // 密鑰庫 KeyStore keyStory = KeyStore.getInstance("PKCS12"); //沒有密鑰 keyStory.load(null, null); // 加載證書到密鑰庫中 keyStory.setCertificateEntry("ass", cer); // 密鑰管理器 KeyManagerFactory kMFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kMFactory.init(keyStory, null); // 信任管理器 TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmFactory.init(keyStory); //初始化sslContext sslContext.init(kMFactory.getKeyManagers(), tmFactory.getTrustManagers(), new SecureRandom()); inputStream.close(); return sslContext;}
/** * 獲取SSLContext * * @return * @throws NoSuchAlgorithmException * @throws KeyManagementException */public static SSLContext getSSLContextWithoutCer() throws NoSuchAlgorithmException, KeyManagementException { // 實例化SSLContext SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, new TrustManager[]{trustManagers}, new SecureRandom()); return sslContext;}/** * 自定義信任管理器 */PRivate static TrustManager trustManagers = new 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 new X509Certificate[0]; }};//驗證主機名public static HostnameVerifier hostnameVerifier = new HostnameVerifier() { @Override public boolean verify(String hostname, SSLsession session) { // TODO Auto-generated method stub return true; }};
新聞熱點
疑難解答