温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

android下使用https协议发请求

发布时间:2020-07-24 20:01:56 来源:网络 阅读:1272 作者:weigq811202 栏目:移动开发

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() {@Override
br/>@Override
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() {@Override
br/>@Override

        @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/");//有证书但不用配的.

}

}

.

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI