在咱们不管是对服务器仍是客户端进行 HTTPS 进行配置时,首先须要准备好的确定是相关证书文件了,而证书文件是什么又从哪里能够获取到相关证书,而且它们又是什么关系,最后它们怎么在通信中起做用呢?可能不少人都不是很系统的清楚这一块;趁如今有空整理出来给你们入门了解下。node
为了获取证书前,咱们须要生成本身的一对公钥和私钥。在这里咱们会使用到一个叫作 OpenSSL 的工具库。git
# 生成私钥文件 $ openssl genrsa -out server.key 2048 # 也能够经过指定加密算法来生成加密的文件,经过 'openssl genrsa -help' 查看支持的算法 $ openssl genrsa -aes128 -out server.key 2048 # 生成证书文件 $ openssl req -new -x509 -days 3650 \ -subj "/C=CN/L=Guangzhou/O=Guangzhou Example Technology Co., Ltd/CN=example.com" \ -key server.key -out server.crt # e.g. 百度的证书中的身份信息 CN = baidu.com # Common Name(证书所请求的域名) O = Beijing Baidu Netcom Science Technology Co., Ltd # Organization Name OU = service operation department # Organization Unit Name L = beijing # Locality Name S = beijing # Sate or Province Name C = CN # Country Name
# 生成 CA 根证书 $ openssl genrsa -out ca.key 2048 $ openssl req -new -x509 -days 3650 \ -subj "/C=CN/L=Guangzhou/O=CA Technology Co., Ltd/CN=XXX Global Root CA" \ -key ca.key -out ca.crt # 生成 .csr 证书签名请求文件 $ openssl req -new \ -subj "/C=CN/L=Guangzhou/O=Guangzhou Example Technology Co., Ltd/CN=example.com" \ -key server.key \ -out server.csr # 使用 CA 根证书颁发服务器证书 $ openssl x509 -req -sha256 \ -CA ca.crt -CAkey ca.key -CAcreateserial -days 3650 \ -in server.csr \ -out server.crt
在 HTTP 协议传输下,数据都是以明文进行传输,数据安全性得不到保障;使用 HTTPS 加密通信后,数据保密和不可篡都获得进一步的保障;根据 HTTPS 服务器不一样的配置方式,安全性也是不尽相同,下面就是常见的 3 种方式:算法
这种方式须要提早将服务器的证书告知客户端,这样客户端在连接服务器时才能进行对服务器证书认证。shell
通信过程(简化)浏览器
client ----(tcp three way handshake)-----> server client ----(Client Hello)-----> server client <----(Server Hello,public key)----- server client (经过事先保存本地的 server.crt 和服务器发过来的 server.crt 进行比较) client ----(客户端生成对称密钥,经过 server.crt 提取 public key 进行加密发送)-----> server client ----(密钥交换后,按照对称密钥进行加密通信)-----> server
在复杂的网络环境中,服务器证书的传输自己也是一个很是危险的问题。若是在中间某个环节,服务器证书被监听或替换那么对服务器的认证也将再也不可靠。tomcat
为了不证书的传递过程当中被篡改,能够经过一个安全可靠的 CA 根证书分别对服务器和客户端的证书进行签名。这样客户端或服务器在收到对方的证书后能够经过根证书进行验证证书的有效性。安全
通信过程(简化)服务器
client ----(tcp three way handshake)-----> server client ----(Client Hello)-----> server client <----(Server Hello,public key)----- server client (经过 CA 根证书对服务器发过来的 server.crt 进行合法性验证) client ----(客户端生成对称密钥,经过 public key 进行加密发送)-----> server client ----(密钥交换后,按照对称密钥进行加密通信)-----> server
上面 2 种都是由客户端单向验证的,这种则是客户端服务器双向相互验证。网络
客户端经过引入一个 CA 根证书和服务器的名字来实现对服务器进行验证。客户端在链接服务器时会首先请求服务器的证书,而后使用 CA 根证书对收到的服务器端证书进行验证。客户端的证书也采用 CA 根证书签名,服务器端对客户端进行证书认证。session
通信过程(简化)
client ----(tcp three way handshake)-----> server client ----(Client Hello)-----> server client <----(Server Hello,public key)----- server client (经过 CA 根证书对服务器发过来的 server.crt 进行合法性验证) client ----(客户端生成对称密钥,经过 public key 进行加密发送,并发送客户端 client.crt)-----> server server (服务端使用 CA 根证书对 client.crt 进行作法性校验) client ----(密钥交换后,按照对称密钥进行加密通信)-----> server
这种常见于网银系统等交易系统的网站或者 API 使用,确保客户端携带证书进行访问;当无证书的客户端没法进行访问,当访问时会出现 400 Bad Reques <No required SSL certificate was sent >
。
浏览器证书导入须要装换为 PKCS #12 证书文件才能导入,命令以下:
openssl pkcs12 -export -inkey client.key -in client.crt -out client.pfx # 输入口令,导入证书后再请求则会弹出选择证书的选项就正常访问了
说明:JKS 文件扩展名是 .jks 或 .keystore
keytool -list -keystore server.jks
keytool -importkeystore -srckeystore server.jks -srcalias tomcat -destkeystore server.p12 -deststoretype PKCS12
server.crt
、server.key
、ca.crt
文件openssl pkcs12 -in server.p12 -nodes -nocerts -out server.key openssl pkcs12 -in server.p12 -nodes -nokeys -clcerts -out server.crt openssl pkcs12 -in server.p12 -nodes -nokeys -cacerts -out ca.crt
使用加密的私钥配置 Nginx 支持 SSL 时,并使用下面命令去除私钥必须的口令(不然 start、reload 都得输入密码)
$ cp server.key server.key.org $ openssl rsa -in server.key.org -out server.key
server { listen 443 ssl; server_name localhost; ssl on; ssl_certificate ../cert/server.crt; ssl_certificate_key ../cert/server.key; ssl_client_certificate ../cert/ca.crt; ssl_verify_client on; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4:HIGH:!MD5:!aNULL:!eNULL:!NULL:!DH:!EDH:!AESGCM; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; location / { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://localhost:8080; } }