赞
踩
Android用Java开发,Java自带的http API有HttpURLConnection,Android系统又加上了Apache Httpclient,后来在22版本中HttpClient又被Google删除,所以我们不使用HttpClient来做网络请求了,这里只给出HttpURLConnection的方式。
原生的写法理解的没问题了,用第三方的写法也好弄.这里就不写了,有需要的同学联系我哈.我再补充
在讲android连接https的请求之前,其实应该先学习一下https的知识.https是另一种协议,跟http类似,也是发一次请求request建立一次链接connection带回一次信息response后再把链接断开.但又增加了新的内容:在发送请求前,要先把数据用SSL加密,而接收的信息也是服务端用SSL加密后的,需要先解密后才能正常使用.这样就确保了有人即便在网络上抓包,也无法知道到底传输的数据是什么,因为别人不知道你们的密钥是什么,比较安全.那有人就说了,客户端client怎么和服务端server商定一个只有双方知道的密钥呢?啊,能这样想就证明你已经对HTTPS的SSL加密有一些认识了.其实过程也简单.一般来说服务端server都是些网站,都是任何人都能访问的,但客户端又得得到一个只有自己和server知道而其它client不知道的密钥.其实这步也不难啊,只要client第一次访问server时,server象管理session一样给它一个唯一字符串,以后双方都用这个做密钥就好了嘛.
有了上一步的想法,好象HTTPS也很好理解,但是,人家HTTPS想的事情比这个要多.人家是这样想的:在做某些事情之前客户端client必须要先信任这个server不是仿冒的才跟它通信.也就是说有些事情是不能在钓鱼网站(仿冒的网站,就算你搞了DNS进攻让别人比如支付宝的域名指向你的服务器)上做的.这一步又是如何完成的呢?其实是客户端要先有服务端的一个签名文件(有时又叫指纹信息),也就是CA证书.终于说到服务端的CA证书了,好了,下面说对我们这次工作有用的东西,有关HTTPS和SSL的更多知识,大家可以去参考百度百科.
服务端用的CA证书,其实分为两种,一:花了钱向一个什么中心申请注册的,另一种是自己用工具生成一个而不去花钱注册.
第一种,就象百度这样的,我们可以直接象用HTTP一样是去这样的HTTPS的链接.因为这样的,你的connection会自动从注册中心下载证书并配置.大网站一般都这样.
第二种,就需要做处理.要做的处理写下面.
处理如下:
先跟服务端要一个证书文件,然后通过一大段代码设置到我们的HttpURLConnection中.其实就是让我们的client端信任此server.
((HttpsURLConnection) httpConn).setSSLSocketFactory(sslSocketFactory); //至于这个sslSocketFactory如何通过证书产生,哈哈.好大一段代码,参考完整的代码中的写法吧.
但好象还有没有证书的,配置就是让HttpURLConnection相信一个没证书的配置,然后添加信任的域名,其实可以理解为只要是域名符合我就相信啦!!靠,这client客户端这次可以被加了dns欺骗的钓鱼网站进攻了...
((HttpsURLConnection) urlConnection).setSSLSocketFactory(sslSocketFactory);
((HttpsURLConnection) urlConnection).setHostnameVerifier(SSLContextUtil.hostnameVerifier);
看,多了一行吧.
经测试,没有证书只相信域名的这种做法,其实对那些需要证书且需要配置的网站,也能正常访问.看来CA证书还真是仅仅只做了让客户端如何相信他啊,也就是防钓鱼进攻.
简单说一下什么是钓鱼进攻:就是进攻者为了得到你的支付宝账号和密码,就做了一个跟支付宝网站看上去一样的网站,然后想办法引导你在他的网站上登录你的支付宝....这就是钓鱼....
所谓的DNS进攻,就是让别人的正常域名不再指向别人的网站,比如支付宝的域名本来是指向阿里的支付宝网站服务器的ip的,但被进攻成功后,就变成了指向进攻者的钓鱼网站的IP了..此时用户就算检查浏览器中地址栏的域名,也无法排除.
为了防止这样的事情发生,HTTPS协议规定了客户端在使用HTTPS之前,必须得先确认server服务端的身份,于是引入CA证书.为了方便客户端client去访问他,又引入一个什么注册中心.
下面是我的例子的所有代码
SSLContextUtil类,核心类.
package cn.wei.https;
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.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.TrustManagerFactory;
import android.content.Context;
public class SSLContextUtil {
private static SSLContext mSSLContext;
private static SSLContext mNoCarSSLContext;
private static HostnameVerifier hostnameVerifier = new HostnameVerifier() {br/>@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
public static SSLContext getSSLContext() {
return mSSLContext;
}
public static SSLContext getNoCarSSLContext() {
return mNoCarSSLContext;
}
public static HostnameVerifier getHostnameVerifier(){
return hostnameVerifier;
}
public static void init(Context c) {
try {
mSSLContext = getSSLContext2(c);
} catch (Exception e) {
e.printStackTrace();
}
try {
mNoCarSSLContext = getNoCarSLLContext2();
} catch (Exception e) {
e.printStackTrace();
}
}
private static SSLContext getNoCarSLLContext2() {
// SSLContext sslContext = null;
//X509TrustManager a;//为了import这个类,就得这样写一下.
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {br/>@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
- @Override
- public void checkServerTrusted(X509Certificate[] chain, String authType) {}
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
- }}, new SecureRandom());
- } catch (Exception e) {
- e.printStackTrace();
- }
- return sslContext;
}
private static SSLContext getSSLContext2(Context c)
throws NoSuchAlgorithmException, IOException, CertificateException,
KeyStoreException, UnrecoverableKeyException,
KeyManagementException {
// 生成SSLContext对象
SSLContext sslContext = SSLContext.getInstance("TLS");
// 从assets中加载证书
InputStream inStream = c.getAssets().open("srca.cer");
// 证书工厂
CertificateFactory cerFactory = CertificateFactory.getInstance("X.509");
Certificate cer = cerFactory.generateCertificate(inStream);
// 密钥库
KeyStore kStore = KeyStore.getInstance("PKCS12");
kStore.load(null, null);
kStore.setCertificateEntry("trust", cer);// 加载证书到密钥库中
// 密钥管理器
KeyManagerFactory keyFactory = KeyManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyFactory.init(kStore, null);// 加载密钥库到管理器
// 信任管理器
TrustManagerFactory tFactory = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tFactory.init(kStore);// 加载密钥库到信任管理器
// 初始化
sslContext.init(keyFactory.getKeyManagers(),
tFactory.getTrustManagers(), new SecureRandom());
return sslContext;
}
}
Application类,辅助初始化的
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
SSLContextUtil.init(this);
}
}
Activity类,使用的.
package cn.wei.https;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView tv_html;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_html = (TextView) this.findViewById(R.id.tv_html);
AsyncTask<String, String, String> at = new AsyncTask<String, String, String>() {
@Override
protected String doInBackground(String... params) {
HttpURLConnection httpConn = null;
try {
URL url = new URL(params[0]);
URLConnection conn = url.openConnection();
httpConn = (HttpURLConnection) conn;
// 设置SSLSocketFoactory,这里有两种:1.需要安全证书 2.不需要安全证书;看官且往下看
if (httpConn instanceof HttpsURLConnection) { // 是Https请求
// 0.需要证书但不需要配的.什么也不用写.比如百度的https://www.baidu.com
// 1.需要安全证书且需要配的.
// SSLContext sslContext = SSLContextUtil.getSSLContext();
// if (sslContext != null) {
// SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// ((HttpsURLConnection) httpConn).setSSLSocketFactory(sslSocketFactory);
//
//
// }
// 2.不需要安全证书但需要配的:server端有但没给,client端配置直接相信此域名.
// SSLContext sslContext = SSLContextUtil.getNoCarSSLContext();
// if (sslContext != null) {
// SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
// ((HttpsURLConnection) httpConn).setSSLSocketFactory(sslSocketFactory);
// ((HttpsURLConnection) httpConn).setHostnameVerifier(SSLContextUtil.getHostnameVerifier());
// }
}
httpConn.setRequestMethod("GET");
httpConn.setReadTimeout(16000);
httpConn.setConnectTimeout(16000);
int resCode = httpConn.getResponseCode();
if (resCode == 200) {
try (InputStream in = httpConn.getInputStream();
Reader r = new InputStreamReader(in, "UTF-8");
BufferedReader br = new BufferedReader(r);) {
String line = null;
StringBuilder sb = new StringBuilder();
do {
line = br.readLine();
sb.append(line).append("\n");
} while (line != null);
return sb.toString();
} catch (IOException e) {
throw e;
}
} else {
return "网络请求错误.resCode:" + resCode;
}
} catch (MalformedURLException e) {
e.printStackTrace();
return "err:" + e.getMessage();
} catch (IOException e) {
e.printStackTrace();
return "err:" + e.getMessage();
} finally {
httpConn.disconnect();
}
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
tv_html.setText(result);
}
};
//at.execute("https://kyfw.12306.cn/otn/");//这个是有证书需要配的.
//at.execute("https://www.baidu.com");//百度是有证书但不用配的.
at.execute("https://www.alipay.com/");//有证书但不用配的.
}
}
.
转载于:https://blog.51cto.com/12093642/2049505
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。