转 Android HTTPS详解
前言
HTTPS原理
SSL/TLS协议作用
基本的运行过程
握手阶段的详细过程
客户端发出请求(ClientHello)
服务器回应(ServerHello)
客户端回应
服务器的最后回应
握手结束
服务器基于Nginx搭建HTTPS虚拟站点
Android实现HTTPS通信
- package com.example.photocrop;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- import org.apache.http.HttpResponse;
- import org.apache.http.HttpStatus;
- import org.apache.http.StatusLine;
- import org.apache.http.client.HttpClient;
- import org.apache.http.client.methods.HttpPost;
- import org.apache.http.client.methods.HttpUriRequest;
- import android.app.Activity;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.AsyncTask.Status;
- import android.text.TextUtils;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- public class MainActivity extends Activity {
- private Button httpsButton;
- private TextView conTextView;
- private CreateHttpsConnTask httpsTask;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- httpsButton = (Button) findViewById(R.id.create_https_button);
- httpsButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- runHttpsConnection();
- }
- });
- conTextView = (TextView) findViewById(R.id.content_textview);
- conTextView.setText("初始为空");
- }
- private void runHttpsConnection() {
- if (httpsTask == null || httpsTask.getStatus() == Status.FINISHED) {
- httpsTask = new CreateHttpsConnTask();
- httpsTask.execute();
- }
- }
- private class CreateHttpsConnTask extends AsyncTask<Void, Void, Void> {
- private static final String HTTPS_EXAMPLE_URL = "自定义";
- private StringBuffer sBuffer = new StringBuffer();
- @Override
- protected Void doInBackground(Void... params) {
- HttpUriRequest request = new HttpPost(HTTPS_EXAMPLE_URL);
- HttpClient httpClient = HttpUtils.getHttpsClient();
- try {
- HttpResponse httpResponse = httpClient.execute(request);
- if (httpResponse != null) {
- StatusLine statusLine = httpResponse.getStatusLine();
- if (statusLine != null
- && statusLine.getStatusCode() == HttpStatus.SC_OK) {
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(
- httpResponse.getEntity().getContent(),
- "UTF-8"));
- String line = null;
- while ((line = reader.readLine()) != null) {
- sBuffer.append(line);
- }
- } catch (Exception e) {
- Log.e("https", e.getMessage());
- } finally {
- if (reader != null) {
- reader.close();
- reader = null;
- }
- }
- }
- }
- } catch (Exception e) {
- Log.e("https", e.getMessage());
- } finally {
- }
- return null;
- }
- @Override
- protected void onPostExecute(Void result) {
- if (!TextUtils.isEmpty(sBuffer.toString())) {
- conTextView.setText(sBuffer.toString());
- }
- }
- }
- }
HttpUtils.java
- package com.example.photocrop;
- import org.apache.http.HttpVersion;
- import org.apache.http.client.HttpClient;
- import org.apache.http.conn.ClientConnectionManager;
- 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.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.HttpProtocolParams;
- import org.apache.http.protocol.HTTP;
- import android.content.Context;
- public class HttpUtils {
- public static HttpClient getHttpsClient() {
- BasicHttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
- HttpProtocolParams.setUseExpectContinue(params, true);
- SchemeRegistry schReg = new SchemeRegistry();
- schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
- ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);
- return new DefaultHttpClient(connMgr, params);
- }
- public static HttpClient getCustomClient() {
- BasicHttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
- HttpProtocolParams.setUseExpectContinue(params, true);
- SchemeRegistry schReg = new SchemeRegistry();
- schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schReg.register(new Scheme("https", MySSLSocketFactory.getSocketFactory(), 443));
- ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);
- return new DefaultHttpClient(connMgr, params);
- }
- public static HttpClient getSpecialKeyStoreClient(Context context) {
- BasicHttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
- HttpProtocolParams.setUseExpectContinue(params, true);
- SchemeRegistry schReg = new SchemeRegistry();
- schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schReg.register(new Scheme("https", CustomerSocketFactory.getSocketFactory(context), 443));
- ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);
- return new DefaultHttpClient(connMgr, params);
- }
- }
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
- <Button
- android:id="@+id/create_https_button"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello_world"
- android:textSize="16sp" />
- <TextView
- android:id="@+id/content_textview"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:textSize="16sp" />
- </LinearLayout>
- schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
加入对HTTPS的支持,就可以有效的建立HTTPS连接了,例如“https://www.google.com.hk”了,但是访问自己基于Nginx搭建的HTTPS服务器却不行,因为它使用了不被系统承认的自定义证书,会报出如下问题:No peer certificate。
使用自定义证书并忽略验证的HTTPS连接方式
- package com.example.photocrop;
- import java.io.IOException;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.security.KeyManagementException;
- import java.security.KeyStore;
- import java.security.KeyStoreException;
- import java.security.NoSuchAlgorithmException;
- import java.security.UnrecoverableKeyException;
- import java.security.cert.CertificateException;
- import java.security.cert.X509Certificate;
- import javax.net.ssl.SSLContext;
- import javax.net.ssl.TrustManager;
- import javax.net.ssl.X509TrustManager;
- import org.apache.http.conn.ssl.SSLSocketFactory;
- public class MySSLSocketFactory extends SSLSocketFactory {
- SSLContext sslContext = SSLContext.getInstance("TLS");
- public MySSLSocketFactory(KeyStore truststore)
- throws NoSuchAlgorithmException, KeyManagementException,
- KeyStoreException, UnrecoverableKeyException {
- super(truststore);
- TrustManager tm = new X509TrustManager() {
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- @Override
- public void checkServerTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- }
- @Override
- public void checkClientTrusted(X509Certificate[] chain,
- String authType) throws CertificateException {
- }
- };
- sslContext.init(null, new TrustManager[] { tm }, null);
- }
- @Override
- public Socket createSocket() throws IOException {
- return sslContext.getSocketFactory().createSocket();
- }
- @Override
- public Socket createSocket(Socket socket, String host, int port,
- boolean autoClose) throws IOException, UnknownHostException {
- return sslContext.getSocketFactory().createSocket(socket, host, port,
- autoClose);
- }
- public static SSLSocketFactory getSocketFactory() {
- try {
- KeyStore trustStore = KeyStore.getInstance(KeyStore
- .getDefaultType());
- trustStore.load(null, null);
- SSLSocketFactory factory = new MySSLSocketFactory(trustStore);
- return factory;
- } catch (Exception e) {
- e.getMessage();
- return null;
- }
- }
- }
同时,需要修改DefaultHttpClient的register方法,改为自己构建的sslsocket:
- public static HttpClient getCustomClient() {
- BasicHttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
- HttpProtocolParams.setUseExpectContinue(params, true);
- SchemeRegistry schReg = new SchemeRegistry();
- schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schReg.register(new Scheme("https", MySSLSocketFactory.getSocketFactory(), 443));
- ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);
- return new DefaultHttpClient(connMgr, params);
- }
这样就可以成功的访问自己构建的基于Nginx的HTTPS虚拟站点了。
缺陷:
使用自定义证书建立HTTPS连接
生成KeyStore
要验证自定义证书,首先要把证书编译到应用中,这需要使用keytool工具生产KeyStore文件。这里的证书就是指目标服务器的公钥,可以从web服务器配置的.crt文件或.pem文件获得。同时,你需要配置bouncycastle,我下载的是bcprov-jdk16-145.jar,至于配置大家自行google就好了。
- keytool -importcert -v -trustcacerts -alias example -file www.example.com.crt -keystore example.bks -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /home/wzy/Downloads/java/jdk1.7.0_60/jre/lib/ext/bcprov-jdk16-145.jar -storepass pw123456
运行后将显示证书内容并提示你是否确认,输入Y回车即可。
生产KeyStore文件成功后,将其放在app应用的res/raw目录下即可。
使用自定义KeyStore实现连接
- package com.example.photocrop;
- import java.io.IOException;
- import java.io.InputStream;
- import java.security.KeyManagementException;
- import java.security.KeyStore;
- import java.security.KeyStoreException;
- import java.security.NoSuchAlgorithmException;
- import java.security.UnrecoverableKeyException;
- import org.apache.http.conn.ssl.SSLSocketFactory;
- import android.content.Context;
- public class CustomerSocketFactory extends SSLSocketFactory {
- private static final String PASSWD = "pw123456";
- public CustomerSocketFactory(KeyStore truststore)
- throws NoSuchAlgorithmException, KeyManagementException,
- KeyStoreException, UnrecoverableKeyException {
- super(truststore);
- }
- public static SSLSocketFactory getSocketFactory(Context context) {
- InputStream input = null;
- try {
- input = context.getResources().openRawResource(R.raw.example);
- KeyStore trustStore = KeyStore.getInstance(KeyStore
- .getDefaultType());
- trustStore.load(input, PASSWD.toCharArray());
- SSLSocketFactory factory = new CustomerSocketFactory(trustStore);
- return factory;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- } finally {
- if (input != null) {
- try {
- input.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- input = null;
- }
- }
- }
- }
同时,需要修改DefaultHttpClient的register方法,改为自己构建的sslsocket:
- public static HttpClient getSpecialKeyStoreClient(Context context) {
- BasicHttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
- HttpProtocolParams.setUseExpectContinue(params, true);
- SchemeRegistry schReg = new SchemeRegistry();
- schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- schReg.register(new Scheme("https", CustomerSocketFactory.getSocketFactory(context), 443));
- ClientConnectionManager connMgr = new ThreadSafeClientConnManager(params, schReg);
- return new DefaultHttpClient(connMgr, params);
- }
转 Android HTTPS详解的更多相关文章
- Android ConstraintLayout详解(from jianshu)
Android ConstraintLayout详解 https://www.jianshu.com/p/a8b49ff64cd3 1. 概述 在本篇文章中,你会学习到有关Constraint ...
- 最全面的Android Webview详解
转自:最全面的Android Webview详解 前言 现在很多App里都内置了Web网页(Hyprid App),比如说很多电商平台,淘宝.京东.聚划算等等,如下图 那么这种该如何实现呢?其实这是 ...
- Android Notification 详解(一)——基本操作
Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...
- Android Notification 详解——基本操作
Android Notification 详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 前几天项目中有用到 Android 通知相关的内容,索性把 Android Notificatio ...
- 公钥与私钥,HTTPS详解
1.公钥与私钥原理1)鲍勃有两把钥匙,一把是公钥,另一把是私钥2)鲍勃把公钥送给他的朋友们----帕蒂.道格.苏珊----每人一把.3)苏珊要给鲍勃写一封保密的信.她写完后用鲍勃的公钥加密,就可以达到 ...
- Android ActionBar详解
Android ActionBar详解 分类: Android2014-04-30 15:23 1094人阅读 评论(0) 收藏 举报 androidActionBar 目录(?)[+] 第4 ...
- Android 签名详解
Android 签名详解 AndroidOPhoneAnt设计模式Eclipse 在Android 系统中,所有安装 到 系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程 ...
- Android编译系统详解(一)
++++++++++++++++++++++++++++++++++++++++++ 本文系本站原创,欢迎转载! 转载请注明出处: http://blog.csdn.net/mr_raptor/art ...
- Android布局详解之一:FrameLayout
原创文章,如有转载,请注明出处:http://blog.csdn.net/yihui823/article/details/6702273 FrameLayout是最简单的布局了.所有放在布局里的 ...
随机推荐
- 基于ZooKeeper的分布式Session实现
1. 认识ZooKeeper ZooKeeper—— “动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而不是像走在原始丛林里,心惊胆颤的被 ...
- 转:jmeter之线程组
虽然有三个添加线程组的选项,名字不一样, 创建之后,其界面是完全一样的.之前的版本只有一个线程组的名字.现在多一个setUp theread Group 与terDown Thread Group 1 ...
- 在OSchina上看到的清理到缓存的方法
/* * *文 件 名: DataCleanManager.java * 描 述: 主要功能有清除内/外缓存,清除数据库,清除sharedPreference,清除files和清除自定义目录 */ i ...
- loadunner使用socket协议来实现多客户端连接同一服务器脚本(使用到IP欺骗技术)
第一部分: #include "lrs.h" vuser_init(){ lrs_startup(257); return 0;} 第二部分: Action(){ char *Re ...
- Linux系统采用netstat命令查看DDOS攻击的方法
Linux系统采用netstat命令查看DDOS攻击的方法 来源:互联网 作者:佚名 时间:07-05 15:10:21 [大 中 小] 这篇文章主要为大家介绍了Linux系统采用netstat命令查 ...
- PHPExcel解决内存占用过大问题-dw 查找memoryCacheSize把1M改为2048M
http://blog.sina.com.cn/s/blog_4ec7952d0101fcrd.html PHPExcel解决内存占用过大问题-设置单元格对象缓存 PHPExcel是一个很强大的处理E ...
- Git 删除文件
在Git中,删除也是一种修改的操作,我们验证一下,先在工作目录中添加一个新文件test.txt,并且提交: $ git statusOn branch masterUntracked files: ...
- World Cup
World Cup Time Limit : 2000/1000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other) Total Su ...
- 关于stringWithFormat: - 两段NSString如何合成一段
http://blog.sina.com.cn/s/blog_6b1e4a0601019pib.html str = [NSString stringWithFormat:@"%@,%@&q ...
- centos主机信任
一.实现原理 使用一种被称为"公私钥"认证的方式来进行ssh登录."公私钥"认证方式简单的解释是: 首先在客户端上创建一对公私钥(公钥文件:~/.ssh/id_ ...