Android HttpsUrlConnection HTTPS
HttpsUrlConnection HTTPS通信。
HTTPS(Hyper Text Transfer Protocol Secure)
是一种基于SSL/TLS的HTTP,所有的HTTP数据都是在SSL/TLS协议封装之上进行传输的。
HTTPS协议是在HTTP协议的基础上,添加了SSL/TLS握手以及数据加密传输,也属于应用层协议
SSL/TLS协议的基本过程:
1、客户端向服务器端索要并验证公钥
2、双方协商生成“对话密钥”
3、双方采用“对话密钥”进行加密通信
上面过程的前两布,又称为“握手阶段”
SSL/TLS协议的基本思路是采用公钥加密法:
也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。但是这里需要了解两个问题的解决方案。
如何保证公钥不被篡改:
将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。
公钥加密计算量太大,如何减少耗用的时间:
每一次对话(session),客户端和服务器端都生成一个“对话密钥”(session key),用它来加密信息。由于“对话密钥”是对称加密,所以运算速度非常快,而服务器公钥只用于加密“对话密钥”本身,
这样就减少了加密运算的消耗时间
1、HTTPS 访问CA认证的数字证书网站
public void doHttpsConnection(String urls) {
HttpsURLConnection httpsURLConnection = null;
BufferedReader reader = null;
try {
if(urls != null){
if(urls.startsWith("https")){
URL url = new URL(urls); //CA认证的数字证书网站
httpsURLConnection = (HttpsURLConnection) url.openConnection();
httpsURLConnection.setConnectTimeout(5000); //是建立连接的超时时间;
urlCon.setReadTimeout(5000); //传递数据的超时时间
httpsURLConnection.setDoInput(true);
httpsURLConnection.setUseCaches(false);
httpsURLConnection.connect();
reader = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream()));
StringBuilder sBuilder = new StringBuilder();
String line;
int i=0, lineNum=10;
while ((line = reader.readLine()) != null && ++i>10) {
sBuilder.append(line);
}
Log.d("doHttpsConnection", "content=" + sBuilder.toString());
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpsURLConnection != null) {
httpsURLConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
doHttpsConnection("https://www.baidu.com/");
2、HTTPS 访问自签名的数字证书网站
HttpsURLConnection配置为信任所有的CA证书:
这种方式很容易的就能访问自签名的HTTPS网站,但是会导致严重的安全问题,如“中间人攻击”。
中间人攻击
虽然上述方案使用了HTTPS,客户端和服务器端的通信内容得到了加密,嗅探程序无法得到传输的内容,但是无法抵挡“中间人攻击”。
例如,在内网配置一个DNS,把目标服务器域名解析到本地的一个地址,然后在这个地址上使用一个中间服务器作为代理,它使用一个假的证书与客户端通讯,
然后再由这个代理服务器作为客户端连接到实际的服务器,用真的证书与服务器通讯。这样所有的通讯内容都会经过这个代理,而客户端不会感知,这是由于客户端不校验服务器公钥证书导致的
1、实现X509TrustManager接口(但实现中跳过客户端和服务器端认证)
public class TrustAllCertsManager implements X509TrustManager { //X590TrustedManager: TrustManager的子接口,管理X509证书,验证远程安全套接字
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// Do nothing -> accept any certificates
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// Do nothing -> accept any certificates
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
2、HostnameVerifier接口实现
public class VerifyEverythingHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; //不进行url和服务器主机名的验证
}
}
3、SSLContext创建、初始化
TrustManager[] trustManager = new TrustManager[] {new TrustEverythingTrustManager()}; // 创建信任所有CA证书的信任管理器数组
SSLContext sslContext = null; //SSLContext 此类的实例表示安全套接字协议的实现,它是SSLSocketFactory、SSLServerSocketFactory和SSLEngine的工厂
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManager, new java.security.SecureRandom()); //设置SSLContext的信任管理器
} catch (NoSuchAlgorithmException e) {
// do nothing
}catch (KeyManagementException e) {
// do nothing
}
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); //设置HttpsURLConnection类的默认SSLSocketFactory
4、HttpsUrlConnection实例化
public void doHttpsConnection() {
HttpsURLConnection httpsURLConnection = null;
BufferedReader reader = null;
try {
URL url = new URL("https://kyfw.12306.cn/otn/index/init"); //自签名的HTTPS网站,12306登录界面url
httpsURLConnection = (HttpsURLConnection) url.openConnection();
httpsURLConnection.setHostnameVerifier(new VerifyEverythingHostnameVerifier()); //设置HostnameVerifier
httpsURLConnection.setConnectTimeout(5000); //是建立连接的超时时间;
urlCon.setReadTimeout(5000); //传递数据的超时时间
httpsURLConnection.setDoInput(true);
httpsURLConnection.setUseCaches(false);
httpsURLConnection.connect();
reader = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream()));
StringBuilder sBuilder = new StringBuilder();
String line;
int i=0, lineNum=10;
while ((line = reader.readLine()) != null && ++i>10) {
sBuilder.append(line);
}
Log.d("doHttpsConnection", "content=" + sBuilder.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (httpsURLConnection != null) {
httpsURLConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
HttpsURLConnection配置信任指定的CA证书:
为了防止“中间人攻击”,可将服务器端的公钥证书编译到Android应用中(通过配置HttpsUrlConnection的SSLSocketFactory(SSLSocketFactory <- SSLContext <- TrustManager<-KeyStore-
private TrustManager[] createTrustManager() {
BufferedInputStream inputStream = null;
try {
inputStream = new BufferedInputStream(getAssets().open("srca.cer")); //读取assets存放的服务器公钥证书
CertificateFactory cf = CertificateFactory.getInstance("X.509"); // 根据公钥证书创建Certificate对象
Certificate ca = cf.generateCertificate(inputStream);
Log.e("TrustManager", "ca=" + ((X509Certificate) ca).getSubjectDN());
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); // 生成包含当前CA证书的keystore, keystore表示密钥和证书的存储设施
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String algorithm = TrustManagerFactory.getDefaultAlgorithm(); // 使用包含指定CA证书的keystore生成TrustManager[]数组
TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
tmf.init(keyStore);
return tmf.getTrustManagers();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} finally {
if (cerInputStream != null) {
try {
cerInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
3、SSLContext创建、初始化
TrustManager[] trustManager = createTrustManager(); // 创建信任所有CA证书的信任管理器数组
SSLContext sslContext = null;
if (trustManagers == null) {
Log.e("TAG", "tmf create failed!");
return;
}else{
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManager, new SecureRandom()); //设置SSLContext的信任管理器
} catch (NoSuchAlgorithmException e) {
// do nothing
}catch (KeyManagementException e) {
// do nothing
}
}
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); //设置HttpsURLConnection类的默认SSLSocketFactory
4、HttpsUrlConnection实例化,调用上面的doHttpsConnection()函数
doHttpsConnection(“https://kyfw.12306.cn/otn/index/init“); //自签名的HTTPS网站,12306登录界面url