https是一个创建在密码学基础之上的一种安全通讯协议,准确来讲是基于HTTP协议和SSL/TSL的组合,要想理解HTTPS必须了解密码学的一些相关基础概念。java
公钥密码体制分为三个部分,公钥,私钥,加密解密算法,加密解密过程以下:android
在对称加密算法中,加密使用的密钥和解密使用的密钥是相同的。也就是说,加密和解密都是使用的同一个密钥。所以对称加密算法要保证安全性的话,密钥要作好保密,只能让使用的人知道,不能对外公开。这个和上面的公钥密码体制有所不一样,公钥密码体制中加密是用公钥,解密使用私钥,而对称加密算法中,加密和解密都是使用同一个密钥,不区分公钥和私钥。 密钥,通常就是一个字符串或数字,在加密或者解密时传递给加密/解密算法。前面在公钥密码体制中说到的公钥、私钥就是密钥,公钥是加密使用的密钥,私钥是解密使用的密钥。算法
RSA密码体制是一种公钥密码体制,公钥公开,私钥保密,它的加密解密算法是公开的。 由公钥加密的内容能够而且只能由私钥进行解密,而且由私钥加密的内容能够而且只能由公钥进行解密。也就是说,RSA的这一对公钥、私钥均可以用来加密和解密,而且一方加密的内容能够由而且只能由对方进行解密。浏览器
在非对称加密算法中,加密使用的密钥和解密使用的密钥是不相同的。前面所说的公钥密码体制就是一种非对称加密算法,他的公钥和是私钥是不能相同的,也就是说加密使用的密钥和解密使用的密钥不一样,所以它是一个非对称加密算法。安全
了解了以上的基础概念以后咱们就能够聊聊为何安全了,这里咱们就能够笼统的讲一下当咱们打开一个https连接的时候发生了什么事情。bash
经过上诉简单的描述,也可了解到https通讯是是经过各类加密算法及证书比对校验完成的一个http通讯。服务器
ssl Secure Sockets Layer,如今应该叫"TLS",但因为习惯问题,咱们仍是叫"SSL"比较多,ssl证书是数字证书的一种,数字证书有较多的内容项,里面的内容比较多——Version、Serial number、Signature algorithm 等等,挑几个重要的解释一下。网络
·Symantec (which bought VeriSign's SSL interests and owns Thawte and Geotrust) 38.1% 市场份额app
·Comodo SSL 29.1%框架
·Go Daddy 13.4%
·GlobalSign 10%
安卓系统中, 你能够在下列路径中找到证书颁发机构: 设置 -> 安全 -> 受信任的凭证
最佳和最安全的私钥获取方法是向可信任的证书颁发机构 (CA)(例如将带您完成身份验证过程的赛门铁克公司)申请一个证书。一旦有了本身的证书,就能够生成您本身的私钥。您可使用该私钥为您的可执行文件或软件库签名,私钥仅可经过可追溯到 CA 的公钥解锁,而公钥已预安装在大部分浏览器中。若是在签名后代码被篡改,公钥将不能核实私钥签名的真实性,浏览器将当即向任未尝试下载代码的人弹出警告窗口。若是代码无缺无损,则将提供您的文。
自签名证书就是没有经过受信任的证书颁发机构, 本身给本身颁发的证书.
SSL 证书大体分三类:
X.509 - 这是一种证书标准,主要定义了证书中应该包含哪些内容.其详情能够参考RFC5280,SSL/TLS使用的就是这种证书标准.
一样的X.509证书,可能有不一样的编码格式,目前有如下两种编码格式.
PEM - Privacy Enhanced Mail,打开看文本格式,以"-----BEGIN..."开头, "-----END..."结尾,内容是BASE64编码. 查看PEM格式证书的信息:openssl x509 -in certificate.pem -text -noout Apache和*NIX服务器偏向于使用这种编码格式.
DER - Distinguished Encoding Rules,打开看是二进制格式,不可读. 查看DER格式证书的信息:openssl x509 -in certificate.der -inform der -text -noout Java和Windows服务器偏向于使用这种编码格式.
在 Android 和 java中 更多的是使用keystore。最经常使用的工具就是keytool. Keytool是一个Java数据证书的管理工具 ,Keytool将密钥(key)和证书(certificates)存在一个称为keystore的文件中。 在keystore里,包含两种数据:
每一个keystore都关联这一个独一无二的alias,这个alias一般不区分大小写
以上所述皆是对HTTPS SSL/TLS的概念叙述,经过这个描述会让你对下面的配置以及编码更加了解。咱们在Android 开发中配置项目支持HTTPS这是个基本的操做。下面我会以OkHttp网络框架为例。经过如下三点可完成项目配置。
Android OkHttp框架默认是提供了对系统用户信任证书的校验。若是服务器下发的证书是被Android信任机构颁发的证书是不会出现安全提示的,或者是用户添加到系统的证书也是不会出现任何安全提示。
在 AOSP 源码库中,CA 根证书主要存放在 system/ca-certificates 目录下,而在 Android 系统中,则存放在 /system/etc/security/ 目录下。因此咱们没有Root的手机是没法进行添加根证书的。
也能够根据如下配置进行系统根证书安全校验
public static SSLSocketFactory getSSLSocketFactory() {
SSLSocketFactory ssfFactory = null;
SSLContext sc = null;
try {
sc = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
sc.init((KeyManager[]) null, trustManagerFactory.getTrustManagers(), new SecureRandom());
ssfFactory = sc.getSocketFactory();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return ssfFactory;
}
复制代码
不管是权威机构颁发的证书仍是自签名的,打包一份到 app 内部,好比存放在 asset 里,下面的示例展现了此过程:从 InputStream 获取一个特定的 CA,用该 CA 建立 KeyStore,而后用后者建立和初始化 TrustManager。TrustManager 是系统用于验证来自服务器的证书的工具,可使用一个或多个 CA 从 KeyStore建立,而建立的 TrustManager 将仅信任这些 CA。
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
复制代码
以上代码,能够解决证书信任问题。但同时须要注意的是,这里是基于Android默认的信任检查来解决的。由于咱们没有对TrustManager作任何修改,若是仍然遇到证书校验不经过的状况,则须要从新实现TrustManager,请用如下代码代替“tmf.getTrustManagers()”:
。这时候咱们须要经过自定义的校验方式方可完成校验。经过自定义X509TrustManager来实现checkServerTrusted的校验,其实就是经过上诉介绍的SSL/TLS校验的方式
context.init(null, new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
for (X509Certificate cert : chain) {
// Make sure that it hasn't expired. cert.checkValidity(); // Verify the certificate's public key chain.
try {
cert.verify(((X509Certificate) ca).getPublicKey());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
}
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}, null);
复制代码
先校验证书的日期是否过时,其次经过本地预置证书的公钥对服务器下发的数字证书进行对比校验。
Android P新特性,全面禁止了非安全的http链接,若是要使用非加密链接,须要配置network security config
步骤以下:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
//用于辅助抓包,7.0以上证书的权限变了
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
//信任用户证书
<certificates src="user"></certificates>
//信任用户本身安装的证书
<certificates src="system"></certificates>
//定义白名单
<certificates src="@raw/cn_area"></certificates>
</trust-anchors>
</base-config>
<!-- 使用自签名 SSL 证书的主机 配置-->
<!-- cleartextTrafficPermitted="false" 强制校验https 不然能够容许经过http-->
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">example.com</domain> <!-- 过滤域名,可配置多个 -->
<domain includeSubdomains="true">example1.com</domain> <!-- 通常会将 CDN 配置在此 -->
<trust-anchors>
<!--这就是咱们本身的证书-->
<!--若是要信任多个证书,就能够写多个-->
<certificates src="@raw/cn_area"/>
<!--也能够把这些证书放在一个目录下-->
<certificates src="@raw/cn_area"/>
//信任用户证书
<certificates src="user"></certificates>
//信任用户本身安装的证书
<certificates src="system"></certificates>
</trust-anchors>
<!-- 固定证书-->
<pin-set expiration="2018-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
<!-- backup pin -->
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
</pin-set>
</domain-config>
<!-- debug 模式配置调试CA-->
<debug-overrides>
<trust-anchors>
//信任用户证书
<certificates src="user"></certificates>
//信任用户本身安装的证书
<certificates src="system"></certificates>
</trust-anchors>
</debug-overrides>
</network-security-config>
复制代码
若是咱们的某个网址的证书是自签名的证书,咱们想要访问这个网址,能够进行以下配置
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<trust-anchors>
<!--这就是咱们本身的证书-->
<!--若是要信任多个证书,就能够写多个-->
<certificates src="@raw/my_ca"/>
<!--也能够把这些证书放在一个目录下-->
<certificates src="@raw/trusted_roots"/>
</trust-anchors>
</domain-config>
</network-security-config>
复制代码
若是咱们想让App信任除系统以外的其余的CA,能够进行以下配置
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config>
<trust-anchors>
<!--在base-config中配置额外的CA-->
<certificates src="@raw/extracas"/>
<certificates src="system"/>
</trust-anchors>
</base-config>
</network-security-config>
复制代码
若是咱们在调试的时候staging服务器不是正规CA,咱们能够进行以下配置
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--debug-overrides表示在调试状态下信任的CA,当android:debugable为true的时候,是调试状态-->
<debug-overrides>
<trust-anchors>
<certificates src="@raw/debug_cas"/>
</trust-anchors>
</debug-overrides>
</network-security-config>
复制代码
通常状况下,应用信任全部预装 CA。若是有预装 CA 签发欺诈性证书,则应用将面临被中间人攻击的风险。有些应用经过限制信任的 CA 集或经过固定证书,选择限制其接受的证书集
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<pin-set expiration="2018-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
<!-- backup pin -->
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
</pin-set>
</domain-config>
</network-security-config>
复制代码
更详细的信息请参考Android Security Config
数字证书转化https://blog.csdn.net/xiangguiwang/article/details/76400805