转 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是最简单的布局了.所有放在布局里的 ...
随机推荐
- 《JavaScript高级程序设计》读书笔记 ---语句
do-while语句do-while 语句是一种后测试循环语句,即只有在循环体中的代码执行之后,才会测试出口条件.换句话说,在对条件表达式求值之前,循环体内的代码至少会被执行一次.以下是do-whil ...
- php 上传缩放图片
有时上传图片时因为图片太大了,不仅占用空间,消耗流量,而且影响浏(图片的尺寸大小不一).下面分享一种等比例不失真缩放图片的方法,这样,不管上传的图片尺有多大,都会自动压缩到我们设置尺寸值的范围之内.经 ...
- html 框架属性
<html> <head> <title></title> </head> <frameset col ...
- divide an integer into X parts (as even as possible)
the algorithm is like this: it evenly spreads an integer N over K cells. for i = 0 to K array[i] = N ...
- php 获取地址栏参数
javascript实现: top.location.href 顶级窗口的地址this.location.href 当前窗口的地址 PHP实现: //获取域名或主机地址 echo $_SERVER[' ...
- OpenGL 图形管道(graphics pipeline)过程
1.总结:Graphics pipeline 主要分为两部分工作 把3D坐标转换成2D坐标 把2D坐标转换成真实的有颜色的像素 2.下图就是一个顶点数据经过几个步骤后转化成显示在屏幕上像素的过程(一般 ...
- 做.net的早晚会用到,并且网上还没有这方面的正确资料或几乎很少
原文网址:http://www.cnblogs.com/langu/archive/2012/03/23/2413990.html 一直以来,找安装程序的msi源文件路径得到的都是“system32” ...
- mysql主从数据库
Mysql主从配置,实现读写分离 大型网站为了软解大量的并发访问,除了在网站实现分布式负载均衡,远远不够.到了数据业务层.数据访问层,如果还是传统的数据结构,或者只是单单靠一台服务器扛,如此多的数据库 ...
- OpenGL----绘制立方体,定点数组与顶点缓冲
,立方体是很简单,但是这里只是拿立方体做一个例子,来说明OpenGL在绘制方法上的改进.从原始一点的办法开始一个立方体有六个面,每个面是一个正方形,好,绘制六个正方形就可以了. glBegin(GL_ ...
- Hibernate 系列教程12-继承-Join策略
Employee public class Employee { private Long id; private String name; HourlyEmployee public class H ...