名词解释:
对称加密:
对称加密就是通信双方使用同一把钥匙加密/解密信息,该方法的优点是加密过程简单,缺点是如何安全的将钥匙送到通讯双方手中。
非对称加密:
在非对称加密(典型算法RSA)中,加密和解密是采用不同的密钥,公钥是公开的,不需要保密,而私钥是由个人自己持有,公钥和私钥都能分别进行加密和解密。该方法的缺点是加密过程复杂,通讯效率低。
证书:
数字证书则是由证书认证机构(CA)对证书申请者真实身份验证之后,用CA的根证书对申请人的一些基本信息以及申请人的公钥进行签名(相当于加盖发证书机 构的公章)后形成的一个数字文件。CA完成签发证书后,会将证书发布在CA的证书库(目录服务器)中,任何人都可以查询和下载,因此数字证书和公钥一样是公开的。数字证书就是经过CA认证过的公钥。
自签名证书
证书除了由第三方私钥签名(比如由ca机构签名),也可以用自己的私钥签名。 用自己的私钥给自己的公钥签名的证书称为自签名证书。
加密通讯:
Alice想和Bob通讯,因此他俩互换公钥。想和谁通讯,就用对方的公钥加密。
1、Alice用Bob的公开密钥加密她的消息,然后传送给Bob。
2、Bob用他的私人密钥解密Alice的消息。
认证:
认证的目的是想鉴别用户的真伪,因此使用自己的私钥加密,只要自己的公钥能解开,就能证明自己的身份,这一过程被称为签名。想和谁认证,就用自己的私钥加密。
1、Alice用她的私钥对文件加密,从而对文件签名。
2、Alice将签名的文件传送给Bob。
3、Bob用Alice的公钥解密文件,从而验证Alice的身份。
HTTPS通讯过程:
https采用混合加密方式(非对称加密+对称加密结合),它使用非对称加密传递对称加密的key,然后通讯双方用这把对称加密的key进行通讯。既解决了非对称加密复杂的问题,又解决了对称加密的钥匙传递问题。
但是这时通讯双方并不知道对方是不是真的对方,因此需要一个很有公信度的第三方来校验彼此(CA机构)
https七层网络模型如下表所示:
HTTPS(应用层) |
(表示层) |
SSL(会话层) |
TCP(传输层) |
IP(网络层) |
以太网(数据链路层) |
数据线/wifi(物理层) |
Https是基于TCP协议的,因此整个通讯只建立一次连接,使用3次握手建立连接。
整个通讯步骤如下:(Alice为服务器,Bob为客户端)
1、Bob想和Alice通讯(客户端访问服务端),Bob向Alice发送hello、随机字符串B_String_1和自己支持的对称加密算法列表(ABCD……)(第一次握手)
2、Alice将自己的公钥发给CA,CA用自己的私钥加密(签名)后将其还给Alice。Alice就获得了CA认证的公钥,简称证书。
3、Alice收到B_String_1并保存下来,自己也生成一个随机字符串A_String_1、自己的CA签名公钥(证书)和选定的加密算法A,一并发给Bob。(第二次握手)
4、Bob会检验证书的真实性,首先与浏览器内置(Android则是操作系统内置)证书比对来确认这个公钥的真实性,比对成功后,Bob会用CA的公钥解密证书,就获得了Alice的公钥。
5、将A_String_1保存下来,并知晓使用A算法加密。Bob生成随机字符串B_String_2,并使用Alice的公钥加密对称B_String_2,发给Alice。(第三次握手)
6、Alice使用自己的私钥解密,获得B_String_2,至此双方都有B_String_1、A_String_1和B_String_2,以及知晓A算法了。
7、之后双方使用B_String_1+A_String_1+B_String_2生成对称密钥key,并用A算法进行加解密通讯。
Android请求https
Android在请求https时,会出现两种情况:
1、请求的服务器的公钥证书是由CA机构颁发的(例如www.baidu.com),系统就会帮我做证书校验,不需要额外的操作。
2、请求的服务器的公钥证书是非CA机构颁发的自签名证书(例如开发的服务器),就需要我们自己做证书校验(单向校验)。
1、CA签名
针对CA签名的服务器,不需要做特殊的校验,直接发起请求即可。
这里使用URLConnection、HttpsURLConnection甚至HttpURLConnection都可以
PS:因为HttpsURLConnection和HttpURLConnection继承自URLConnection,最终都是走URLConnection的openConnection方法。
log打印方法:
public class MyLog {
private static final String TAG = "####";
public static void log(InputStream inputStream){
byte[] bytes = new byte[100];
int flag=0;
while (true){
try {
if (!((flag=inputStream.read(bytes))!=-1)) break;
} catch (IOException e) {
throw new RuntimeException(e);
}
Log.i(TAG, new String(bytes));
}
}
}
具体代码:
public class Use_CA_Thread extends Thread{
@Override
public void run() {
try {
URL url = new URL("https://www.baidu.com/");
URLConnection urlConnection = url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();
MyLog.log(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
super.run();
}
}
访问成功:
若出现报错SSLHandshakeException,可能是测试机版本较低/时区错误/位置错误/配置了代理,需要更换高版本测试机/修改时区/修改位置/关闭代理。
2、自签名
对于自签名证书就需要做证书校验,或者做证书忽略才能访问。
证书校验:
Android应用需要先导入自签证书(.pem或.der),通常是放置在res/raw目录或者assets目录下,我这里是用charles的证书测的。
将证书文件读取为InputStream,使用CertificateFactory解析为Certificate对象。接着,创建一个KeyStore对象,并将证书放入该对象中。然后,通过TrustManagerFactory初始化信任管理器,并最终创建一个SSLContext对象,让HttpsURLConnection设置SSLContext。
具体代码如下:
public class Use_self_certificate extends Thread{
Context context;
public Use_self_certificate(Context context) {
this.context = context;
}
@Override
public void run() {
super.run();
try {
//创建CertificateFactory
//X.509为标准数字证书格式,所有的证书都符合X.509国标
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
//读取证书
InputStream cainputStream=context.getResources().openRawResource(R.raw.chls);
//通过CertificateFactory生成ca
Certificate ca = certificateFactory.generateCertificate(cainputStream);
cainputStream.close();
//KeyStore有多种格式,JKS、BKS等,这里使用默认模式
String keyStoreType = KeyStore.getDefaultType();
//创建KeyStore
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
//加载keystore文件和密码,这里都为空
keyStore.load(null,null);
//设置ca
keyStore.setCertificateEntry("ca",ca);
//获取TrustManagerFactory算法名称
String algorithm = TrustManagerFactory.getDefaultAlgorithm();
//创建TrustManager
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(algorithm);
//TrustManager信任keystore
trustManagerFactory.init(keyStore);
//创建 SSLContext并使用TrustManager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
//创建HttpsURLConnection
URL url = new URL("https://www.baidu.com");
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
//HttpsURLConnection设置SSLContext
httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());
InputStream in = httpsURLConnection.getInputStream();
MyLog.log(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
打印成功
若是报错SSLHandshakeException,可能是服务器与客户端不匹配
证书忽略
自定义TrustManager,让其不做验证,以达成证书忽略的目的。
代码如下:
public class Use_ignore_ca extends Thread{
@Override
public void run() {
super.run();
//自定义TrustManager[]对象
TrustManager[] trustManagers = new TrustManager[]{
//创建X509TrustManager对象
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//不验证客户端
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
//不验证服务端
}
@Override
public X509Certificate[] getAcceptedIssuers() {
//直接返回
return new X509Certificate[0];
}
}
};
try {
SSLContext sslContext;
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null,trustManagers,null);
URL url = new URL("https://www.baidu.com");
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
//HttpsURLConnection设置SSLContext
httpsURLConnection.setSSLSocketFactory(sslContext.getSocketFactory());
InputStream in = httpsURLConnection.getInputStream();
MyLog.log(in);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
打印成功
3、网络安全配置文件
使用一个 XML 文件来自定义网络安全配置,这样可以不需要修改代码,在manifest中进行添加,可以配置如下四种特征:
- 自定义信任CA:针对应用的安全连接自定义哪些CA机构值得信赖。
- 调试CA:在应用中以安全方式调试。
- 停用明文流量:防止应用意外使用明文流量。
- 证书固定:应用仅能连接到特定的证书。
<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>
</manifest>
自定义可信 CA
默认情况下,来自所有应用的安全连接(使用 TLS 和 HTTPS 之类的协议)均信任预装的系统 CA。
通过配置network_security_config.xml,使用 base-config(应用范围)或 domain-config(针对域名)自定义来配置信任域名和信任CA,证书格式为PEM或者DER。
base-config:信任系统证书和其他额外证书,额外证书存放在raw/extracas中。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="@raw/chls"/>
</trust-anchors>
</base-config>
</network-security-config>
domain-config:指定域名及指定CA
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">www.baidu.com</domain>
<trust-anchors>
<certificates src="@raw/chls"/>
</trust-anchors>
</domain-config>
</network-security-config>
调试CA
使用 debug-overrides 指定仅在 android:debuggable 为 true 时才可信的仅调试 CA。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<debug-overrides>
<trust-anchors>
<certificates src="@raw/chls"/>
</trust-anchors>
</debug-overrides>
</network-security-config>
停用明文流量
设置针对某域名停用明文流量,可以禁止所有针对该域名的HTTP访问。
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">www.baidu.com</domain>
</domain-config>
</network-security-config>
固定证书
通过公钥的哈希值来匹配证书(X.509 证书的 SubjectPublicKeyInfo),以防止中间人攻击。固定证书时应包含一个备份密钥和证书到期时间,来防止证书更新等问题。文章来源:https://www.toymoban.com/news/detail-792386.html
查看证书的hash文章来源地址https://www.toymoban.com/news/detail-792386.html
//在线提取百度证书
openssl s_client -connect www.baidu.com:443 -showcerts | openssl x509 -outform der > baidu.der
//提取公钥
openssl x509 -inform der -in baidu.der -pubkey -noout > baidu.pem
//提取证书sha256的base64格式
openssl dgst -sha256 -binary baidu.pem | openssl enc -base64
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">https://www.baidu.com/</domain>
<pin-set expiration="2023-12-19">
<pin digest="SHA-256">MDVrY/WE2mxGTwXzTdBJtGvHawYRfuOC2Nb6ZeVhIQw=</pin>
<!-- backup pin -->
<pin digest="SHA-256">MDVrY/WE2mxGTwXzTdBJtGvHawYRfuOC2Nb6ZeVhIQw=</pin>
</pin-set>
</domain-config>
</network-security-config>
到了这里,关于Android https开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!