关于https你了解的还不够多

Posted open-Xu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于https你了解的还不够多相关的知识,希望对你有一定的参考价值。

版权声明:本文为openXu原创文章【openXu的博客】,未经博主允许不得以任何形式转载

文章目录

1. HTTPS

android9.0开始强制使用https请求,不仅如此,各大巨头公司都自己的操作系统、浏览器等产品中强制要求使用https。对于开发者来说,可能查看一些文档就能做适配,有很多人并没有真正了解https的原理,包括我自己在之前也没想那么多,只知道它是对数据加密后进行网络传输的,这篇文章使用通俗的语言以及实操示例来一起深入理解https的工作流程。

1.1 密码学

说到加密就想到有《密码学》这本书,笔者第一家公司是做加密锁的,对密码学还算比较熟悉,对于https中涉及的密码学,大家需要对下面几点知识有一个概念性的认识:

对称加密:对称加密的代表算法有AES、DES等,加密和解密使用同一个密钥(可看作是字符串),其加解密效率高,但是密钥在传递过程中可能有被窃取的风险(加解密双方需要得到同一个密钥)。

非对称加密:非对称加密的代表算法有RSA、ElGamal等,其密码分为公钥和私钥,使用公钥加密的数据只有用私钥才能解密,反过来使用私钥加密的数据也只有用公钥才能解密。公钥通常存放在客户端,私钥通常存放在服务器。非对称加密的优点是安全性更高,因为客户端发送给服务器的加密信息只有用服务器的私钥才能解密,因此不用担心被别人破解,但加解密的效率相比于对称加密要差很多。非对称加密还可以用于数字签名,所以通过工具生成的密钥文件中不仅包含公私钥,还包含证书信息。

数字签名:使用非对称加密算法,用私钥对数据加密的过程叫做签名,使用公钥对其解密的过程叫做验证签名,数字签名的目的是保证数据的一致性(中途不被篡改)。如果数据非常大,通常使用数字摘要技术(常见的hash算法、MD5等)得到数据的摘要,然后对摘要进行签名。

数字证书:数字证书从本质上是一种电子文档,一个文件,里面包含一系列的信息,比如证书颁发者、使用者、签名算法、哈希算法、公钥等,数字证书和签名是两个概念,证书就是一个文件,而签名是通过签名算法对证书加密得到签名信息。如果数字证书被签名,它里面就包含了签名链和签名信息。数字证书文件有多种格式,不同的格式存放的内容不太一样,不同平台可能支持不同格式的证书。

证书格式(了解一下即可)
PKCS 全称是 Public-Key Cryptography Standards ,是由 RSA 实验室与其它安全系统开发商为促进公钥密码的发展而制订的一系列标准,PKCS 目前共发布过 15 个标准。 常用的有:

  • PKCS#7 Cryptographic Message Syntax Standard
  • PKCS#10 Certification Request Standard
  • PKCS#12 Personal Information Exchange Syntax Standard

X.509是常见通用的证书格式。所有的证书都符合为Public Key Infrastructure (PKI) 制定的 ITU-T X509 国际标准。

  • PKCS#7常用的后缀是: .P7B .P7C .SPC
  • PKCS#12常用的后缀有: .P12 .PFX
  • X.509 DER编码(ASCII)的后缀是: .DER .CER .CRT
  • X.509 PAM编码(Base64)的后缀是: .PEM .CER .CRT
  • .cer/.crt是用于存放证书,它是2进制形式存放的,不含私钥。
  • .pem跟crt/cer的区别是它以Ascii来表示。
  • pfx/p12用于存放个人证书/私钥,他通常包含保护密码,2进制方式
  • p10是证书请求
  • p7r是CA对证书请求的回复,只用于导入
  • p7b以树状展示证书链(certificate chain),同时也支持单个证书,不含私钥。

1.2 HTTP安全问题

传统http协议传输数据是通过明文,存在着数据被监听数据被篡改的风险,为了让数据安全,需要对数据进行加密后传输,下面一步步来看https协议加接密过程是怎样演进的。

对称密钥安全问题

网络传输数据追求高效率,如果要对数据进行加解密首先考虑到的就是使用对称加密算法。对称密钥是浏览器还是服务器生成并不重要,重要的是如何让这个密钥只让它们俩知晓,而不被任何监听者知晓呢。比如让浏览器随机生成一个对称加密密钥,用于后续网络请求对数据进行加密,为了让服务端收到加密后的数据对其进行解密,浏览器首先会将对称密钥(明文)发送给服务端。你会发现不管怎么商定,浏览器和网站的首次通信过程必定是明文的,这就意味着,按照上述的工作流程始终无法创建一个安全的对称加密密钥。

使用非对称加密对对称密钥加密

上述对称密钥传输的安全问题可以通过非对称加密解决。服务端生成非对称加密的公钥和私钥,并将公钥公布出来(发给浏览器),私钥自己藏好。浏览器如果要访问服务器,时首先对对称密钥使用公钥加密后传输给服务端,服务端收到加密后的对称密钥密文使用私钥解密,从而安全的得到浏览器生成的对称密钥。通过这种方式,只有浏览器和服务器首次商定对称密钥时需要使用非对称加密,当服务器拿到对称密钥后双方就可以对通信数据使用对称加密了,避免每次通信使用非对称加解密造成效率低下的问题。

非对称公钥的安全问题

上面通过非对称加密保证了对称密钥的安全性,但是真的安全吗?公钥的公开可能导致公钥被篡改,如果浏览器使用了假的公钥对数据进行加密,篡改者就可以使用假私钥解密,然后对数据篡改后通过网站的公钥加密再发给网站,网站收到的就是被篡改后的数据。本来引进非对称加密是为了保证对称密钥的安全,结果又引来了新的密钥安全问题。
导致这个问题的根源就是浏览器并不知道拿到的公钥是否真的是网站的公钥。解决这个问题有一种办法是将世界上所有网站的公钥都预置在操作系统中,这显然是不现实的,这时候CA机构就出现了。

1.3 CA机构(Catificate Authority)

CA机构的作用就是对网站的数字证书进行签名,从而让浏览器(客户端)验证数字证书合法且未被篡改,数字证书中的公钥确实是网站的公钥

CA机构专门用于给各个网站签发数字证书,从而保证浏览器可以安全地获得各个网站的公钥。网站的管理员需要向CA机构进行申请,将自己的公钥和网站信息提交给CA机构,CA机构则会使用网站的公钥和一些其他的信息(网站域名、有效时长等)来制作证书(certificate),然后使用摘要算法得到证书的摘要(指纹字符串),再使用自己的私钥对摘要进行签名(加密),最后将签名信息打包进数字证书返回给网站,管理员只需要将获得的证书配置到网站服务器上即可。

每当有浏览器请求网站时,首先会将证书返回给浏览器,此时浏览器会用CA机构的公钥来对证书中的签名信息验签(解密),如果能解密成功得到摘要和证书摘要一致,就说明这个证书中的网站的公钥确实来自这个网站,没有被篡改。我们可以在浏览器的地址栏上点击网址左侧的小锁图标来查看证书的详细信息。当浏览器安全的拿到网站的公钥,其他的步骤就如同上面描述的过程了。

如果使用CA公钥无法对网站返回的证书签名信息进行解密验签,则说明证书不是合法的CA机构签发的,也有可能被篡改了,浏览器上就会显示异常界面您的连接不是私密连接

CA机构公钥的安全问题

上面说过公钥的公开可能导致公钥被篡改,CA机构的公钥不也一样吗?世界上的网站是无限的,但是CA机构总共也没多少家,任何正版操作系统都会将所有主流CA机构的证书(内包含公钥)内置到操作系统当中,我们不用额外获取,解密时只需遍历系统中所有内置的CA机构的公钥,只要有任何一个公钥能够正常解密出数据,就说明它是合法的。

签名链

windows10运行certmgr.msc查看操作系统内置的证书,这些证书分为很多种,比如根证书颁发CA机构的证书、受信任的发布者、三方根证书、个人等,为什么要这样分呢?说的通俗一点就是公认的CA机构就只有那么几家,如果全球所有网站都找它们签名,那就忙不过来了,所以出现一些三方CA机构,这些三方CA机构可以对网站签名,被签名的网站如果需要被浏览器信任,那就需要将三方CA机构的证书内置在操作系统,如果没有被内置,那就让根CA机构对三方CA机构的证书进行签名,这样一来,三方CA机构的证书就被浏览器信任了,而通过它签名的网站证书也被信任。通常情况下网站的数字证书中会包含它的签名链,只要签名链的末端证书是被系统信任的即可。

1.4 HTTPS工作流程

https采用的是对称加密和非对称加密结构的方式,使用对称加密对正常传输数据加解密,使用非对称加密协商对称密钥。

CA中心可以对网站的数字证书进行签名,使得浏览器可以分辨哪些网站的数字证书是可信任的,其实就是确保浏览器拿到的网站公钥确实来自这个网站

HTTPS在传输数据之前需要浏览器网站之间进行一次握手,以确立双方加密传输数据的对称密钥,过程如下:

  1. 客户端将它所支持的算法列表和一个用作产生密钥的随机数发送给服务器
  2. 服务器从算法列表中选择一种加密算法,并将它和一份包含服务器公用密钥的证书发送给客户端;该证书还包含了用于认证目的的服务器标识,服务器同时还提供了一个用作产生密钥的随机数
  3. 客户端对服务器的证书进行验证(有关验证证书,可以参考数字签名),并抽取服务器的公用密钥;然后,再产生一个称作pre_master_secret的随机密码串作为通讯过程中对称加密的秘钥,并使用服务器的公用密钥对其进行加密,将加密后的信息发送给服务器
  4. 网站接收浏览器发来的数据之后,通过私钥进行解密,然后HASH校验,如果一致,则使用浏览器发来的数字串使加密一段握手消息发给浏览器。
  5. 浏览器解密,并HASH校验,没有问题,则握手结束。接下来的传输过程将由之前浏览器生成的随机密码并利用对称加密算法进行加密。

2. 网站支持https

下面通过SpringBoot实现一个简单的web工程,并一步步配置证书来体验一下这个过程

2.1 SpringBoot

工程结构

首先应该创建一个web项目,这里使用的是SpringBoot,通过IntelliJ IDEA创建一个maven工程,工程结构如下:

maven配置

//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>HttpsTest</groupId>
    <artifactId>HttpsTest</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--springBoot 启动jar-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>
    </dependencies>
</project>

项目配置

# application.yaml
server:
  port: 8081

源码

//MyApplication.java
package com.openxu.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication 
    public static void main(String[] args) 
        SpringApplication.run(MyApplication.class,args);
    


//User.java 省略了getter\\setter\\toString
public class User 
    private String userId;
    private String userName;

//Response.java 省略了getter\\setter\\toString
public class Response<T> implements Serializable 
    private Integer code;
    private T data;
    private String msg;


//UserController.java
package com.openxu.api.controller;
import com.openxu.api.module.Response;
import com.openxu.api.module.User;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;

@CrossOrigin(origins = "*")
@RestController
@RequestMapping(value="/user")
public class UserController 
    //http://192.168.1.129:8081/user/get   ipconfig得到本机ip
    @GetMapping(value = "/get")
    public Response<List<User>> getUser()
        List<User> users = new ArrayList<User>();
        User user = new User();
        user.setUserId("1");
        user.setUserName("openXu");
        users.add(user);
        return new Response(1, users, "请求成功");
    

然后运行MyApplication,成功后在浏览器访问http://192.168.1.129:8081/user/get(ipconfig得到本机ip为192.168.1.129)得到接口返回的数据:

"code":1,"data":["userId":"1","userName":"openXu"],"msg":"请求成功"

2.2 开启SSL

这里首先介绍一下SSL(Secure Socket Layer安全套接层),它位于HTTP和TCP层之间,简单的说它就是一个技术标准,用于规范网络传输中数据怎样加解密。SSL更新了很多版本,在3.0时互联网标准化组织对其进行了标准化,标准化之后更名为TLS1.0(Transport Layer Security安全传输层协议),可以说TLS就是SSL的3.1版本,它们是同一个东西,而https = http + TLS/SSL。

网站需要支持https,首先需要有一个证书(其实就是一个密钥库文件)。怎样生成密钥库呢?可以通过一些工具实现,比如OpenSSL,它是一个开源的强大的安全套接字层密码库。还可以使用jdk自带的keytool(密钥和证书管理工具)。下面通过keytool生成的openxu_serve.p12,.p12是一种证书文件格式,可以看作是一个密钥库,可以存放公钥、私钥和证书信息,通过密钥库口令保护私钥。

//-alias设置别名
//-storetype 设置证书格式
//-keyalg设置加密算法
//-keysize设置证书大小
//-keystore设置证书文件地址
//-validity设置有效天数
//-storepass 设置密钥库口令
//-ext <value> X.509 扩展  可以配置ip,这个非常重要,浏览器可判断当前请求的ip是否被证书包含

D:\\WorkSpace\\IntelliJ\\HttpsTest>keytool -genkeypair -alias openxu_server -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore src/main/resources/openxu_serve
r.p12 -validity 3650 -ext san=ip:192.168.1.129 -storepass 123456
您的名字与姓氏是什么?
  [Unknown]:  xu
您的组织单位名称是什么?
  [Unknown]:  open
您的组织名称是什么?
  [Unknown]:  openXu
您所在的城市或区域名称是什么?
  [Unknown]:  bj
您所在的省/市/自治区名称是什么?
  [Unknown]:  bj
该单位的双字母国家/地区代码是什么?
  [Unknown]:  cn
CN=xu, OU=open, O=openXu, L=bj, ST=bj, C=cn是否正确?
  [否]:  y

application.yaml中配置ssl:

server:
  port: 8081
  ssl:
    #刚才生成的https证书地址
    key-store: classpath:openxu_server.p12  # 刚才生成的https证书地址
    key-store-password: 123456        # 密钥库口令
    key-password: 123456
    key-store-type: PKCS12             # 协议类型
    key-alias: openxu_server
    enabled: true

重新运行MyApplication,成功后在浏览器访问http://192.168.1.129:8081/user/get:

Bad Request
This combination of host and port requires TLS.

被告知请求需要错误的请求,当前网站需要TLS,也就是说需要使用https请求,所以我们换成https://192.168.1.129:8081/user/get。浏览器发出警告:您的连接不是私密连接,它说我们的数字证书是无效的不受信任的。点击高级->继续前往,就可以成功请求到数据。这里只是演示没有被CA机构签名的网站数字证书是不被浏览器信任的。

2.3 自签名证书

上面我们只是给网站生成了一个密钥库文件(包含数字证书),然后在配置文件中开启了ssl,配置了密钥文件。当浏览器请求网站时,发现使用的是https,网站就会通过配置的密钥库中导出数字证书,这个证书中包含了公钥,将证书发给浏览器,浏览器拿到证书后使用系统内置CA公钥去验签,由于我们的数字证书并没有通过CA签名,所以浏览器认为这个数字证书是不合法的。

一般情况下,如果需要浏览器信任网站的证书,可以向CA机构申请对网站的证书进行签名(使用CA机构私钥加密),这样浏览器访问网站拿到网站的证书和CA签名信息,就可以验证网站的证书有没有被篡改,如果验证签名没有出问题那么网站的证书就可信任。但是有很多网站可能因为各种原因并没有通过CA签名,比如之前(现在已经通过CA签名)的中国铁路,在浏览器访问https://kyfw.12306.cn/otn/被告知它的网站证书是无效的。没有通过CA机构签名的数字证书称之为自签名证书(网站充当自己的CA),当然我们模拟CA生成一对公私钥,对网站的证书进行签名,但是浏览器并没有内置我们的签名证书,被签名的网站证书照样是不被信任的。

让浏览器信任一个网站的数字证书有两种方法,第一种就是网站的数字证书通过系统信任的CA机构签名,第二种是配置浏览器使其信任网站的数字证书或者对其签名的证书。

下面我们设置浏览器信任网站的证书,首先通过keytool -export命令从密钥库证书文件中导出一个数字证书文件openxu_server.cer,.cer同.p12一样也是一种证书格式,不同的是.cer只包含公钥:

//-export导出证书
//-alias 证书别名
//-file 证书输出文件
//-keystore 证书使用的密钥库(从里面拿到公钥)
//-storepass密钥库密码

D:\\WorkSpace\\IntelliJ\\HttpsTest>keytool -export -alias openxu_server -file openxu_server.cer -keystore src\\main\\resources\\openxu_server.p12 -storepass 123456
存储在文件 <openxu_server.cer> 中的证书

设置浏览器信任我们的网站证书:

设置-->隐私设置和安全性-->安全性-->管理证书-->受信任的根证书颁发机构-->导入-->选择刚刚生成的openxu_server.cer文件-->下一步...-->完成-->重启浏览器

通过上面的步骤将网站的数字证书(未签名)导入到“受信任的根证书颁发机构”目录下,这时再请求https://192.168.1.129:8081/user/get就不会发出警告了,而且浏览器会告诉我们这个连接是安全的。

2.4 获取网站的数字证书

不同的系统内置的CA证书可能不一样,下面仅仅只是举一个栗子,不一定是真的。比如https://www.baidu.com/百度的数字证书是通过某一个CA机构签名了的,而windows系统中内置了这个CA的证书,在windows上的浏览器则可以顺利的访问百度https。但是Android系统中并没有内置对百度签名的CA机构的证书,android上访问百度就会报错,这种情况下我们可以在windows浏览器中下载百度的数字证书文件,然后在android中进行一些设置(下面会讲)就可以访问https://www.baidu.com/了。怎样下载某个网站的数字证书呢?

点击浏览器地址栏左边的小锁-->证书-->证书信息-->复制到文件-->下一步...-->输出导出的文件名C:\\Users\\admin\\Desktop\\baidu.cer-->完成

3. Android 9.0强制使用https

Android P(9.0)网络安全策略不允许明文通信,强制使用https,会阻塞http请求,如果app使用的第三方sdk有http,将全部被阻塞。报如下错误:

//网络安全策略不允许与本地主机进行明文通信
UnknownServiceException: CLEARTEXT communication to localhost not permitted by network security policy

或者

//不允许向*发送明文HTTP请求
IOException java.io.IOException: Cleartext HTTP traffic to * not permitted

3.1 usesCleartextTraffic允许使用明文通信

最简单的兼容方式是在AndroidManifest文件的application设置android:usesCleartextTraffic="true"表示当前应用允许使用明文通信,也就是说可以使用http。

//允许使用明文通信
android:usesCleartextTraffic="true"

3.2 代码配置网站证书

上面的适配办法只能是一个过渡,不是长久之计,况且上面示例中的web工程只支持https,并不支持http(如果需要支持http还需要写一些代码,这个大家可以网上查一下Springboot同时支持http和https),所以我们必须要使用https怎么办呢?其实我们的app就和上面的浏览器一样只需要配置app的网络请求框架信任网站的数字证书就可以了,如果不配置直接请求上面的接口会报错:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

首先需要将网站的数字证书拷贝到项目assets文件夹下,其实可以随便放,只要能读取到就行,然后对OkHttpClient进行设置信任我们网站的证书就可以完成请求了,接口ip是局域网,这里运行需要使用模拟器:

private void getUser()
    try
        //CertificateFactory可以从资源文件或者InputStream流中加载数字证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        InputStream inputStream = getResources().getAssets().open("openxu_server.cer");
        Certificate cer = certificateFactory.generateCertificate(inputStream);

        //KeyStore用于存储加密密钥和证书,可以保存多个(key value的形式保存)
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null);
        keyStore.setCertificateEntry("openxu_server", cer);

        //信任管理器工厂
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        //利用keyStore去初始化TrustManagerFactory
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) 
            throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
        
        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];

        //SSLContext表示一个安全套接字协议实现,TLS(Transport Layer Security,安全传输层),TLS是建立在传输层TCP协议之上的协议,服务于应用层,它的前身是SSL(Secure Socket Layer,安全套接字层),它实现了将应用层的报文进行加密后再交由TCP进行传输的功能。
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, new TrustManager[]  trustManager , new SecureRandom());

        //设置https
        OkHttpClient client = new OkHttpClient.Builder()
                //OkHttpClient设置SSL
                .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0])
                .build();

        client.newCall(new Request.Builder()
                .url("https://192.168.1.129:8081/user/get")
                .get()
                .build())
                .enqueue(new Callback() 
                    @Override
                    public void onFailure(Call call, IOException e) 
                        e.printStackTrace();
                        Log.e("FragmentHome", "请求数据失败:"+e.getMessage());
                    
                    @Override
                    public void onResponse(Call call, Response response) throws IOException 
                        Log.w("FragmentHome", "请求数据:"+response.body().string());
                    
                );
     catch (Exception e) 
        e.printStackTrace();
    

提取证书内容

我们还可以将证书中的内容提取出来,作为字符串常量,这样就不需要将证书打包到app中了:

D:\\WorkSpace\\IntelliJ\\HttpsTest>keytool -printcert -rfc -file openxu_server.cer
-----BEGIN CERTIFICATE-----
MIIDWDCCAkCgAwIBAgIEVeFUNTANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJj
bjELMAkGA1UECBMCYmoxCzAJBgNVBAcTAmJqMQ8wDQYDVQQKEwZvcGVuWHUxDTAL
BgNVBAsTBG9wZW4xCzAJBgNVBAMTAnh1MB4XDTIwMTExODA3MTI1OVoXDTMwMTEx
NjA3MTI1OVowVDELMAkGA1UEBhMCY24xCzAJBgNVBAgTAmJqMQswCQYDVQQHEwJi
ajEPMA0GA1UEChMGb3Blblh1MQ0wCwYDVQQLEwRvcGVuMQswCQYDVQQDEwJ4dTCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKrJTJnjggd4k8lP31+D34He
VJFQgPSL9f/6JCHAldoQ+XJJjoUQ0k6TNwJ6rqy9tg+iIogS6tk7UWPwbp1julha
U1jtuHAfRNWSvMniq2MZsznBJBJm0lwHZn2I+J1f5jlPDcvr9NPr7iincdMV1aJN
sr+zuMggiug9t2xRYydCUMrgJ+ckQFEHH97fPCOng9rXwT4VTs6ESgemokiHDbdo
duUdC5vdF455/NEiI+0AYaJ2u9N5TKypn2rREjPVCxpGlN8SHNOvdIUysAXaZSwD
qBpxWnuembbCqw5fMegf6+tuo1XODLf8TcJdNqpPfvsCI99BE+6FOSYHSsHp0U0C
AwEAAaMyMDAwDwYDVR0RBAgwBocEwKgBgTAdBgNVHQ4EFgQUZjsaBT2iG/zwAQOM
ONdSzz+M5TcwDQYJKoZIhvcNAQELBQADggEBAGXFdmr/fkmFZbDKq39ahmeKQw8+
Hi2pUCL2psXukCjd5jJ+hkuaeEGNgvrRpKHInpdJ3FID7Gtd89GJTEDzdZwksDE3
DQQdjfYe2OEqjPbC0GPblnYjdJLsWEzOJ9EYPgmPIpaf4wyC3M18yu6bdU8WZUGJ
V05r4LytGvXr0WugGywJh8NW0gjXPwGQUlly8JEflPrySq8e+3vdP2rbxIPt4VqL
+duA8UvIm2MVmdGN25uzV0GKuZDu11B4p7GAfb6B6yu8ETLIpATTw0bgXF4mgUfP
twhCtSIPKtOF4Ev+0jOnzpc12bAlyBGpP99vL2ZbjdaJU00VFNzeWysicts=
-----END CERTIFICATE-----


private final String certStr = "-----BEGIN CERTIFICATE-----\\n" +
        "MIIDWDCCAkCgAwIBAgIEVeFUNTANBgkqhkiG9w0BAQsFADBUMQswCQYDVQQGEwJj\\n" +
        "bjELMAkGA1UECBMCYmoxCzAJBgNVBAcTAmJqMQ8wDQYDVQQKEwZvcGVuWHUxDTAL\\n" +
        "BgNVBAsTBG9wZW4xCzAJBgNVBAMTAnh1MB4XDTIwMTExODA3MTI1OVoXDTMwMTEx\\n" +
        "NjA3MTI1OVowVDELMAkGA1UEBhMCY24xCzAJBgNVBAgTAmJqMQswCQYDVQQHEwJi\\n" +
        "ajEPMA0GA1UEChMGb3Blblh1MQ0wCwYDVQQLEwRvcGVuMQswCQYDVQQDEwJ4dTCC\\n" +
        "ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKrJTJnjggd4k8lP31+D34He\\n" +
        "VJFQgPSL9f/6JCHAldoQ+XJJjoUQ0k6TNwJ6rqy9tg+iIogS6tk7UWPwbp1julha\\n" +
        "U1jtuHAfRNWSvMniq2MZsznBJBJm0lwHZn2I+J1f5jlPDcvr9NPr7iincdMV1aJN\\n" +
        "sr+zuMggiug9t2xRYydCUMrgJ+ckQFEHH97fPCOng9rXwT4VTs6ESgemokiHDbdo\\n" +
        "duUdC5vdF455/NEiI+0AYaJ2u9N5TKypn2rREjPVCxpGlN8SHNOvdIUysAXaZSwD\\n" +
        "qBpxWnuembbCqw5fMegf6+tuo1XODLf8TcJdNqpPfvsCI99BE+6FOSYHSsHp0U0C\\n" +
        "AwEAAaMyMDAwDwYDVR0RBAgwBocEwKgBgTAdBgNVHQ4EFgQUZjsaBT2iG/zwAQOM\\n" +
        "ONdSzz+M5TcwDQYJKoZIhvcNAQELBQADggEBAGXFdmr/fkmFZbDKq39ahmeKQw8+\\n" +
        "Hi2pUCL2psXukCjd5jJ+hkuaeEGNgvrRpKHInpdJ3FID7Gtd89GJTEDzdZwksDE3\\n" +
        "DQQdjfYe2OEqjPbC0GPblnYjdJLsWEzOJ9EYPgmPIpaf4wyC3M18yu6bdU8WZUGJ\\n" +
        "V05r4LytGvXr0WugGywJh8NW0gjXPwGQUlly8JEflPrySq8e+3vdP2rbxIPt4VqL\\n" +
        "+duA8UvIm2MVmdGN25uzV0GKuZDu11B4p7GAfb6B6yu8ETLIpATTw0bgXF4mgUfP\\n" +
        "twhCtSIPKtOF4Ev+0jOnzpc12bAlyBGpP99vL2ZbjdaJU00VFNzeWysicts=\\n" +
        "-----END CERTIFICATE-----";

private void getUser()
    try
        ...
//          InputStream inputStream = getResources().getAssets().open("openxu_server.cer");
            InputStream inputStream = new Buffer().writeUtf8(certStr).inputStream();
        ...
     catch (Exception e) 
        e.printStackTrace();
    

3.3 android:networkSecurityConfig网络安全性配置

3.2中通过代码配置网站的数字证书看起来非常繁琐,android提供了xml配置的方式来实现网络安全配置。在AndroidManifest文件的application节点配置

android:networkSecurityConfig="@xml/network_security_config"

network_security_config.xml内容如下,具体配置参考网络安全配置:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!--cleartextTrafficPermitted = true允许明文通信,支持http-->
    <!--Android 9(API 28)以下默认cleartextTrafficPermitted="true" ,9.0以上默认为false,这就是为什么9.0以上不允许http请求的原因-->
    <base-config cleartextTrafficPermitted="true" >
        <trust-anchors>
            <!--信任系统预装CA证书,所有使用这些内置CA机构签名的网站数字证书都将被信任-->
            <!--可在设置-安全和隐私-系统安全-加密与凭据-信任的凭据 中查看系统内置CA证书-->
            <certificates src="system" />
            <!--添加自签名数字证书-->
            <certificates src="@raw/baidu"/>  <!--添加百度的证书(通过浏览器导出的)-->
            <certificates src="@raw/openxu_server"/>
        </trust-anchors>
    </base-config>
    <!--添加自签名数字证书,网站有多个域名的情况-->
    <domain-config cleartextTrafficPermitted="false">
        <!--可配置多个ip-->
        <domain includeSubdomains京东面试官:呦,你对中间件 Mycat了解的还挺深~

第零次作业

关于Linux系统,这些知识你都了解吗?

java 线程方法join的简单总结

java 线程方法join的简单总结

关于Java就业和学习时长?