HTTPS的使用以及在Android客户端中的应用



寂寞的时候想要人陪,失落的时候想要人懂。想要的不是形式上的热闹,而是内心里的感动。想要的不是物质上的丰裕,而是精神上的托付。

一.Https

什么是https

  1. HTTPS

    HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。 它是一个URI scheme(抽象标识符体系),句法类同 http:体系。用于安全的HTTP数据传输。

  2. SSL/TSL

    SSL和TLS都是加密协议,旨在基于不安全的基础设施提供安全通信。这意味着,如果正确部署这些协议,就可以对互联网上的任意一个服务打开通信信道,并且可以确信你会与正确的服务器通信,安全地交换信息(你的数据不会被他人截取,而且在接收时会保持原样)。这些协议保护着通信链路即传输层,这也是TLS名称的由来。

    安全不是TLS的唯一目标。TLS实际上有以下四个主要目标(按优先顺序排列)。

    • 加密安全

      这是主要问题:为任意愿意交换信息的双方启用安全通信。

    • 互操作性

      独立的编程人员应该能够使用通用的加密参数开发程序和库,使它们可以相互通信。

    • 可扩展性

      你很快就会看到,TLS是一种能高效开发和部署加密协议的框架。其重要目标是独立于实
      际使用的加密基元(例如密码和散列函数),从而不需要创建新的协议,就允许从一个基
      元迁移到另一个。

    • 效率

      最终的目标是在实现上述所有目标的基础上保持性能成本在可接受的范围内。这需要尽
      量减少昂贵的加密操作的执行次数,并提供一个会话缓存方案,以避免这些加密操作在
      随后的连接中被执行。

二.使用Openssl生成自签名证书

  1. Step1 生成自己的CA根证书

    • 生成CA私钥文件ca.key:

      openssl genrsa -out ca_private.key 1024

    • 生成X.509证书签名请求文件ca.csr:

      openssl req -new -key ca_private.key -out ca.csr

      在生成ca.csr的过程中,会让输入一些组织信息等。

    • 生成X.509格式的CA根证书ca_public.crt(公钥证书):

      openssl x509 -req -in ca.csr -signkey ca_private.key -out ca_public.crt

  2. Step2 生成服务端证书

    • 先生成服务器私钥文件server_private.key:

      openssl genrsa -out server_private.key 1024

    • 根据服务器私钥生成服务器公钥文件server_public.pem:

      openssl rsa -in server_private.key -pubout -out server_public.pem

    • 服务器端需要向CA机构申请签名证书,在申请签名证书之前依然是创建自己的证书签名请求文件server.csr:

      openssl req -new -key server_prviate.key -out server.csr

    对于用于HTTPS的CSR,Common Name必须和网站域名一致,以便之后进行Host Name校验。

    • 服务器端用server.csr文件向CA申请证书,签名过程需要CA的公钥证书和私钥参与,最终颁发一个带有CA签名的服务器端证书server.crt:

      1
      openssl x509 -req -CA ca_public.crt -CAkey ca_private.key -CAcreateserial -in server.csr -out server.crt

三.生成Android客户端可以使用的证书

  1. 从key和crt生成pkcs12格式的

    1
    keystorepenssl pkcs12 -export -in server.crt -inkey server_private.key -out out.p12 -name tomcat -CAfile ca_public.crt -caname root -chain
  2. 生成tomcat需要的keystore

    1
    keytool -importkeystore -v  -srckeystore out.p12 -srcstoretype pkcs12 -srcstorepass QAZwsx -destkeystore tomcat.keystore -deststoretype jks -deststorepass QAZwsx

四.Apache使用Let’s Encrypt的免费证书

  • 实现步骤:
  1. 安装Let’s Encrypt

    1
    2
    3
    Let's Encrypt的项目主页是 https://github.com/certbot/certbot ,可以使用git下载,也可以到主页直接下载ZIP压缩包进入文件夹中,执行如下命令,之后Let's Encrypt会安装一些软件

    ./letsencrypt-auto --help
  1. 安装Apache服务器

    1
    2
    3
    4
    5
    在CentOS7中安装apache的命令
    yum install httpd

    在centos7中安装apache的ssl模块
    yum install mod_ssl
  1. 安装java环境

    1
    2
    yum list java*
    yum install java-1.8.0-openjdk* -y
  2. 安装tomcat

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    cd /usr/local
    //下载安装包
    wget https://mc.qcloudimg.com/static/archive/fa66329388f85c08e8d6c12ceb8b2ca3/apache-tomcat-7.0.77.tar.gz
    //解压
    tar -zxf apache-tomcat-7.0.77.tar.gz
    //重命名文件夹
    mv apache-tomcat-7.0.77 /usr/local/tomcat7
    //进入bin目录
    cd /usr/local/tomcat7/bin
    //给shell文件权限
    chmod 777 *.sh
    //启动服务器
    ./startup.sh
  3. 配置Apache

    1
    2
    3
    4
    5
    6
    修改httpd.conf文件
    添加如下代码,功能是将http协议的请求自动跳转到https协议

    RewriteEngine on
    RewriteCond %{SERVER_PORT} 80
    RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    修改ssl.conf文件
    将Listen 443 https 删掉,不然会和后边的虚拟主机配置冲突
    将<VirtualHost *:443>标签中#ServerName www.example.com:443 前边的#去掉,域名改为自己的域名,Let's Encrypt生成的证书就是绑定这个域名的,我试过改成ip后,Let's Encrypt不支持

    在<VirtualHost *:443>标签中添加以下代码, 功能是将所有请求转发到tomcat服务器 ,这里用的是ajp协议,如果想用http协议,将ajp改为http,8009改为8080

    ProxyVia On
    ProxyRequests Off
    ProxyPass / ajp://127.0.0.1:8009/
    ProxyPassReverse / ajp://127.0.0.1:8009/
    <Proxy *>
    Require all granted
    </Proxy>
    <Location />
    Require all granted
    </Location>
    1
    配置文件改好后,使用httpd -t命令检查配置文件是否有错误,没错误的话,就可以使用service httpd star启动服务
  1. 安装证书

    1
    2
    3
    ./letsencrypt-auto --apache --apache-le-vhost-ext /etc/httpd/conf.d/ssl.conf --register-unsafely-without-email 

    证书生成后会放在/etc/letsencrypt/live/www.example.com/目录中,Let's Encrypt会自动修改ssl.conf文件,关联证书

五.Nginx使用https和免费证书

  1. 安装Nginx

    这是linux公社的一个安装方式 安装方法

  1. 克隆certbot脚本

    1
    2
    3
    $ git clone https://github.com/certbot/certbot
    $ cd certbot
    $ ./certbot-auto --help
  1. 更新Openssl

    1
    yum update openssl
  1. 申请证书

    1
    2
    3
    4
    5
    6
    ./certbot-auto --help		//没报错后执行
    ./certbot-auto certonly --standalone -d www.myserver.com //然后会提示输入验证邮箱


    成功后证书文件保存在/etc/letsencrypt/live/www.myserver.com/文件夹下
    这里只需要后两个文件
  2. 配置文件修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    server {
    listen 443;
    server_name www.myserver.com;
    root /var/www/html;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/www.myserver.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.myserver.com/privkey.pem;

    location / {
    index index.php index.html index.htm;
    }

    location ~ /\. {
    return 403;
    }
    }

    # 最后还要记得配置80端口,这样它才会强行把所有指向80端口的http链接转变为https请求:

    server {
    listen 80;
    server_name www.myserver.com;
    return 301 https://www.myserver.com$request_uri;
    }
  3. 证书自动更新

    Let’s Encrypt 的证书90天就过期了,所以,你还要设置上自动化的更新脚本,最容易的莫过于使用 crontab 了。使用 crontab -e 命令加入如下的定时作业(每个月都强制更新一下):

    1
    2
    0 0 1 * * /etc/certbot/certbot-auto renew --force-renewal
    5 0 1 * * /usr/local/nginx/sbin/nginx -s reload

    你也可以每天凌晨1点检查一下:

    1
    0 1 * * * /etc/certbot/certbot-auto renew

    crontab 中有六个字段,其含义如下:

    • 第1个字段:分钟 (0-59)
    • 第2个字段:小时 (0-23)
    • 第3个字段:日期 (1-31)
    • 第4个字段:月份 (1-12 [12 代表 December])
    • 第5个字段:一周当中的某天 (0-7 [7 或 0 代表星期天])
    • /path/to/command – 计划执行的脚本或命令的名称

六.使用nginx反向代理Tomcat

  1. 修改nginx配置文件

    1
    2
    3
    4
    5
    6
    7
    8
    在443端口的service下修改

    location / {
    proxy_pass http://127.0.0.1:8080/;
    proxy_redirect off;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  1. 关闭centos的8080端口

    1
    2
    3
    4
    5
    使用centos7的防火墙关闭8080端口
    # firewall-cmd --remove-prot=8080/tcp --permanent
    --permanent 参数作用是永久生效不加重启后不生效果
    重启防火墙
    # firewall-cmd --reload

七.在Android客户端中进行证书验证

  1. 在Okhttp或者Retrofit中进行证书锁定

    1
    2
    3
    4
    OkHttpClient client = new OkHttpClient.Builder()
    .certificatePinner(new CertificatePinner.Builder()
    .add("主机名", "sha256/sha256的值")
    .build());

    //sha256值可以通过 Sll Lab

  2. 进行主机名校验

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    OkHttpClient client = new OkHttpClient.Builder()
    .certificatePinner(new CertificatePinner.Builder()
    .add("主机名", "sha256/sha256的值")
    //主机名校验
    .hostnameVerifier(new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
    if (hostname.equals("hello.hl262.top"))
    return true;
    return false;
    }
    })
    .build());
  1. 证书更新问题

    1
    2
    3
    Let’s Encrypt的免费证书90天到期
    服务端证书过期客户端将无法访问
    可以从服务器获取sha265