技术联盟

Android HTTPS详解

前言

最近有一个跟Https相关的问题需要解决,因此花时间学习了一下Android平台Https的使用,同时也看了一些Https的原理,这里分享一下学习心得。

HTTPS原理

HTTPS(Hyper Text Transfer Protocol Secure),是一种基于SSL/TLS的HTTP,所有的HTTP数据都是在SSL/TLS协议封装之上进行传输的。HTTPS协议是在HTTP协议的基础上,添加了SSL/TLS握手以及数据加密传输,也属于应用层协议。所以,研究HTTPS协议原理,最终其实就是研究SSL/TLS协议。

SSL/TLS协议作用

不使用SSL/TLS的HTTP通信,就是不加密的通信,所有的信息明文传播,带来了三大风险:

1. 窃听风险:第三方可以获知通信内容。

2. 篡改风险:第三方可以修改通知内容。

3. 冒充风险:第三方可以冒充他人身份参与通信。

SSL/TLS协议是为了解决这三大风险而设计的,希望达到:

1. 所有信息都是加密传输,第三方无法窃听。

2. 具有校验机制,一旦被篡改,通信双方都会立刻发现。

3. 配备身份证书,防止身份被冒充。

基本的运行过程

SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。但是这里需要了解两个问题的解决方案。

1. 如何保证公钥不被篡改?

解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。

2. 公钥加密计算量太大,如何减少耗用的时间?

解决方法:每一次对话(session),客户端和服务器端都生成一个“对话密钥”(session key),用它来加密信息。由于“对话密钥”是对称加密,所以运算速度非常快,而服务器公钥只用于加密“对话密钥”本身,这样就减少了加密运算的消耗时间。

因此,SSL/TLS协议的基本过程是这样的:

1. 客户端向服务器端索要并验证公钥。

2. 双方协商生成“对话密钥”。

3. 双方采用“对话密钥”进行加密通信。

上面过程的前两布,又称为“握手阶段”。

握手阶段的详细过程

“握手阶段”涉及四次通信,需要注意的是,“握手阶段”的所有通信都是明文的。

客户端发出请求(ClientHello)

首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。在这一步中,客户端主要向服务器提供以下信息:

1. 支持的协议版本,比如TLS 1.0版

2. 一个客户端生成的随机数,稍后用于生成“对话密钥”。

3. 支持的加密方法,比如RSA公钥加密。

4. 支持的压缩方法。

这里需要注意的是,客户端发送的信息之中不包括服务器的域名。也就是说,理论上服务器只能包含一个网站,否则会分不清应用向客户端提供哪一个网站的数字证书。这就是为什么通常一台服务器只能有一张数字证书的原因。

服务器回应(ServerHello)

服务器收到客户端请求后,向客户端发出回应,这叫做ServerHello。服务器的回应包含以下内容:

1. 确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。

2. 一个服务器生成的随机数,稍后用于生成“对话密钥”。

3. 确认使用的加密方法,比如RSA公钥加密。

4. 服务器证书。

除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含一项请求,要求客户端提供“客户端证书”。比如,金融机构往往只允许认证客户连入自己的网络,就会向正式客户提供USB密钥,里面就包含了一张客户端证书。

客户端回应

客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁发,或者证书中的域名与实际域名不一致,或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项消息。

1. 一个随机数。该随机数用服务器公钥加密,防止被窃听。

2. 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

3. 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项通常也是前面发送的所有内容的hash值,用来供服务器校验。

上面第一项随机数,是整个握手阶段出现的第三个随机数,又称“pre-master key”。有了它以后,客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同一把“会话密钥”。

服务器的最后回应

服务器收到客户端的第三个随机数pre-master key之后,计算生成本次会话所用的“会话密钥”。然后,向客户端最后发送下面信息。

1. 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

2. 服务器握手结束通知,表示服务器的握手阶段已经结束。这一项同时也是前面发生的所有内容的hash值,用来供客户端校验。

握手结束

至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用“会话密钥”加密内容。

服务器基于Nginx搭建HTTPS虚拟站点

之前一篇文章详细介绍了在服务器端如何生成SSL证书,并基于Nginx搭建HTTPS服务器,链接:Nginx搭建HTTPS服务器

Android实现HTTPS通信

由于各种原因吧,这里使用HttpClicent类讲解一下Android如何建立HTTPS连接。代码demo如下。

MainActivity.java

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;


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);
}
}

activity_main.xml

<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>

Android使用DefaultHttpClient建立HTTPS连接,关键需要加入对HTTPS的支持:

schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));

加入对HTTPS的支持,就可以有效的建立HTTPS连接了,例如“https://www.google.com.hk”了,但是访问自己基于Nginx搭建的HTTPS服务器却不行,因为它使用了不被系统承认的自定义证书,会报出如下问题:No peer certificate。

使用自定义证书并忽略验证的HTTPS连接方式

解决证书不被系统承认的方法,就是跳过系统校验。要跳过系统校验,就不能再使用系统标准的SSL SocketFactory了,需要自定义一个。然后为了在这个自定义SSL SocketFactory里跳过校验,还需要自定义一个TrustManager,在其中忽略所有校验,即TrustAll。

MySSLSocketFactory.java实现代码如下:

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,客户端和服务器端的通信内容得到了加密,嗅探程序无法得到传输的内容,但是无法抵挡“中间人攻击”。例如,在内网配置一个DNS,把目标服务器域名解析到本地的一个地址,然后在这个地址上使用一个中间服务器作为代理,它使用一个假的证书与客户端通讯,然后再由这个代理服务器作为客户端连接到实际的服务器,用真的证书与服务器通讯。这样所有的通讯内容都会经过这个代理,而客户端不会感知,这是由于客户端不校验服务器公钥证书导致的。

使用自定义证书建立HTTPS连接

为了防止上面方案可能导致的“中间人攻击”,我们可以下载服务器端公钥证书,然后将公钥证书编译到Android应用中,由应用自己来验证证书。

生成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实现连接

思路和TrushAll差不多,也是需要一个自定义的SSLSokcetFactory,不过因为还需要验证证书,因此不需要自定义TrustManager了。

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);
}

转自:http://www.tuicool.com/articles/6NvEZj

 

android httpClient 支持HTTPS的2种处理方式

 

转自http://my.oschina.net/blackylin/blog/144136

参考http://developer.android.com/training/articles/security-ssl.html#Concepts

http://www.ibm.com/developerworks/cn/java/j-lo-ssltls/

 

问题:

项目中Android https或http请求地址重定向为HTTPS的地址,相信很多人都遇到了这个异常(无终端认证):
 javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

解决过程:

1.没遇到过的问题,搜索吧,少年

log里出现这个异常,作者第一次遇到,不知道啥意思。看下字面意思,是ssl协议中没有终端认证。SSL?作者没用到ssl协议呀,只是通过httpClient请求一个重定向https的地址。
好吧,google下,知道了个差不多情况的帖子,http://www.eoeandroid.com/thread-161747-1-1.html。恩恩,一个不错的帖子,给出了个解决方案。照着来试下。添加个继承SSLSocketFactory的
自定义类。并在初始化httpclient支持https时,注册进去。看下面代码:

01 public class HttpClientHelper {
02
03     private static HttpClient httpClient;
04
05     private HttpClientHelper() {
06     }
07
08     public static synchronized HttpClient getHttpClient() {
09
10         if (null == httpClient) {
11             // 初始化工作
12             try {
13                 KeyStore trustStore = KeyStore.getInstance(KeyStore
14                         .getDefaultType());
15                 trustStore.load(null, null);
16                 SSLSocketFactory sf = new SSLSocketFactoryEx(trustStore);
17                 sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  //允许所有主机的验证
18
19                 HttpParams params = new BasicHttpParams();
20
21                 HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
22                 HttpProtocolParams.setContentCharset(params,
23                         HTTP.DEFAULT_CONTENT_CHARSET);
24                 HttpProtocolParams.setUseExpectContinue(params, true);
25
26                 // 设置连接管理器的超时
27                 ConnManagerParams.setTimeout(params, 10000);
28                 // 设置连接超时
29                 HttpConnectionParams.setConnectionTimeout(params, 10000);
30                 // 设置socket超时
31                 HttpConnectionParams.setSoTimeout(params, 10000);
32
33                 // 设置http https支持
34                 SchemeRegistry schReg = new SchemeRegistry();
35                 schReg.register(new Scheme(“http”, PlainSocketFactory
36                         .getSocketFactory(), 80));
37                 schReg.register(new Scheme(“https”, sf, 443));
38
39                 ClientConnectionManager conManager = new ThreadSafeClientConnManager(
40                         params, schReg);
41
42                 httpClient = new DefaultHttpClient(conManager, params);
43             } catch (Exception e) {
44                 e.printStackTrace();
45                 return new DefaultHttpClient();
46             }
47         }
48         return httpClient;
49     }
50
51 }
52
53 class SSLSocketFactoryEx extends SSLSocketFactory {
54
55     SSLContext sslContext = SSLContext.getInstance(“TLS”);
56
57     public SSLSocketFactoryEx(KeyStore truststore)
58             throws NoSuchAlgorithmException, KeyManagementException,
59             KeyStoreException, UnrecoverableKeyException {
60         super(truststore);
61
62         TrustManager tm = new X509TrustManager() {
63
64             @Override
65             public java.security.cert.X509Certificate[] getAcceptedIssuers() {
66                 return null;
67             }
68
69             @Override
70             public void checkClientTrusted(
71                     java.security.cert.X509Certificate[] chain, String authType)
72                     throws java.security.cert.CertificateException {
73
74             }
75
76             @Override
77             public void checkServerTrusted(
78                     java.security.cert.X509Certificate[] chain, String authType)
79                     throws java.security.cert.CertificateException {
80
81             }
82         };
83
84         sslContext.init(null, new TrustManager[] { tm }, null);
85     }
86
87     @Override
88     public Socket createSocket(Socket socket, String host, int port,
89             boolean autoClose) throws IOException, UnknownHostException {
90         return sslContext.getSocketFactory().createSocket(socket, host, port,
91                 autoClose);
92     }
93
94     @Override
95     public Socket createSocket() throws IOException {
96         return sslContext.getSocketFactory().createSocket();
97     }
98 }

ok,run下,狂乱的点到测试按钮,深吸口气,盯着eclipse中的logat。咦?神奇的竟然没有报之前的 javax.net.ssl.SSLPeerUnverifiedException: No peer certificate的异常了。服务端的数据正常返回了。,狂喜中…

 

2.了解并分析问题

狂喜中,得分析这问题诶。不然老大来问,啥情况?楞半天不知道咋说(作者就经常这样,所以吸取教训。所以的弄懂出现的问题,学习+汇报工作)。
思来想去,就是作者请求的是一个重定向https的地址。好吧,那就学习下https(之前被老大深深的教过,http就是request/response)。继续搜索吧,少年。下面总结下学习到的https知识。

2.1 https

 

HTTPS:超文本安全传输协议,和HTTP相比,多了一个SSL/TSL的认证过程,端口为443。(鄙视下之前说的)

作者没用到ssl协议呀,只是通过httpClient请求一个重定向https的地址

 

1.peer终端发送一个request,https服务端把支持的加密算法等以证书的形式返回一个身份信息(包含ca颁发机构和加密公钥等)。

2.获取证书之后,验证证书合法性。

3.随机产生一个密钥,并以证书当中的公钥加密。

4.request https服务端,把用公钥加密过的密钥传送给https服务端。

5.https服务端用自己的密钥解密,获取随机值。

6.之后双方传送数据都用此密钥加密后通信。

看下面一张网上的得来的https的时序图:

 

 

2.2分析下出现问题的原因

 

好吧,大概的流程知道了。定位已经非常清楚了。在第2步验证证书时,无法验证。为啥无法验证呢?没有添加信任。详细参考下

http://www.cnblogs.com/P_Chou/archive/2010/12/27/https-ssl-certification.html讲的非常清楚https-ssl的认证过程,膜拜下该作者

 

这样想来,上面提供的解决方案就是添加默认信任全部证书。以此来通过接下来的通信。

3.解决问题

但是,这样问题是解决了。但是觉得还是不带靠谱(信任全部证书有点危险)。继续噼噼啪啪的网上搜索一番。又找到了一种解决方案,其过程大致这样的:

1.浏览器访问https地址,保存提示的证书到本地,放到android项目中的assets目录。

2.导入证书,代码如下。

3.把证书添加为信任。
01 String requestHTTPSPage(String mUrl) {
02         InputStream ins = null;
03         String result = “”;
04         try {
05             ins = context.getAssets().open(“app_pay.cer”); //下载的证书放到项目中的assets目录中
06             CertificateFactory cerFactory = CertificateFactory
07                     .getInstance(“X.509”);
08             Certificate cer = cerFactory.generateCertificate(ins);
09             KeyStore keyStore = KeyStore.getInstance(“PKCS12”, “BC”);
10             keyStore.load(null, null);
11             keyStore.setCertificateEntry(“trust”, cer);
12
13             SSLSocketFactory socketFactory = new SSLSocketFactory(keyStore);
14             Scheme sch = new Scheme(“https”, socketFactory, 443);
15             HttpClient mHttpClient = new DefaultHttpClient();
16             mHttpClient.getConnectionManager().getSchemeRegistry()
17                     .register(sch);
18
19             BufferedReader reader = null;
20             try {
21                 Log.d(TAG, “executeGet is in,murl:” + mUrl);
22                 HttpGet request = new HttpGet();
23                 request.setURI(new URI(mUrl));
24                 HttpResponse response = mHttpClient.execute(request);
25                 if (response.getStatusLine().getStatusCode() != 200) {
26                     request.abort();
27                     return result;
28                 }
29
30                 reader = new BufferedReader(new InputStreamReader(response
31                         .getEntity().getContent()));
32                 StringBuffer buffer = new StringBuffer();
33                 String line = null;
34                 while ((line = reader.readLine()) != null) {
35                     buffer.append(line);
36                 }
37                 result = buffer.toString();
38                 Log.d(TAG, “mUrl=” + mUrl + “\nresult = ” + result);
39             } catch (Exception e) {
40                 e.printStackTrace();
41             } finally {
42                 if (reader != null) {
43                     reader.close();
44                 }
45             }
46         } catch (Exception e) {
47             // TODO: handle exception
48         } finally {
49             try {
50                 if (ins != null)
51                     ins.close();
52             } catch (IOException e) {
53                 e.printStackTrace();
54             }
55         }
56         return result;
57     }
接着,验证下呗。吼吼,稀里糊涂的又可以了。感动的泪流满面。

 

最后总结:

2种方法都解决了作者遇到的问题,这里记录下。以防下次遇到,希望能给遇到相同问题朋友有所参考帮助。

转自:http://blog.csdn.net/lihenair/article/details/17441169

 

Android 实现 HttpClient 请求Https

如题,默认下,HttpClient是不能请求Https的,需要自己获取

  1. private static final int SET_CONNECTION_TIMEOUT = 5 * 1000;  
  2.     private static final int SET_SOCKET_TIMEOUT = 20 * 1000;  
  3.       
  4.     public static HttpClient getNewHttpClient() {  
  5.         try {  
  6.             KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  
  7.             trustStore.load(nullnull);  
  8.   
  9.             SSLSocketFactory sf = new MySSLSocketFactory(trustStore);  
  10.             sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
  11.   
  12.             HttpParams params = new BasicHttpParams();  
  13.   
  14.             HttpConnectionParams.setConnectionTimeout(params, 10000);  
  15.             HttpConnectionParams.setSoTimeout(params, 10000);  
  16.   
  17.             HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);  
  18.             HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);  
  19.   
  20.             SchemeRegistry registry = new SchemeRegistry();  
  21.             registry.register(new Scheme(“http”, PlainSocketFactory.getSocketFactory(), 80));  
  22.             registry.register(new Scheme(“https”, sf, 443));  
  23.   
  24.             ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);  
  25.   
  26.             HttpConnectionParams.setConnectionTimeout(params, SET_CONNECTION_TIMEOUT);  
  27.             HttpConnectionParams.setSoTimeout(params, SET_SOCKET_TIMEOUT);  
  28.             HttpClient client = new DefaultHttpClient(ccm, params);  
  29.   
  30.             return client;  
  31.         } catch (Exception e) {  
  32.             return new DefaultHttpClient();  
  33.         }  
  34.     }  


下面是MySSLSocketFactory类

  1. private static class MySSLSocketFactory extends SSLSocketFactory {  
  2.         SSLContext sslContext = SSLContext.getInstance(“TLS”);  
  3.   
  4.         public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException,  
  5.                 KeyManagementException, KeyStoreException, UnrecoverableKeyException {  
  6.             super(truststore);  
  7.   
  8.             TrustManager tm = new X509TrustManager() {  
  9.                 public void checkClientTrusted(X509Certificate[] chain, String authType)  
  10.                         throws CertificateException {  
  11.                 }  
  12.   
  13.                 public void checkServerTrusted(X509Certificate[] chain, String authType)  
  14.                         throws CertificateException {  
  15.                 }  
  16.   
  17.                 public X509Certificate[] getAcceptedIssuers() {  
  18.                     return null;  
  19.                 }  
  20.             };  
  21.   
  22.             sslContext.init(nullnew TrustManager[] { tm }, null);  
  23.         }  
  24.   
  25.         @Override  
  26.         public Socket createSocket(Socket socket, String host, int port, boolean autoClose)  
  27.                 throws IOException, UnknownHostException {  
  28.             return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);  
  29.         }  
  30.   
  31.         @Override  
  32.         public Socket createSocket() throws IOException {  
  33.             return sslContext.getSocketFactory().createSocket();  
  34.         }  
  35.     }  

通过上面的方法获得HttpClient对象就可以请求Https了

转自:http://blog.csdn.net/heynine/article/details/8279304

Share this:

码字很辛苦,转载请注明来自技术联盟《Android HTTPS详解》

评论