1.理論知識
https簡介
HTTPS(全稱:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全為目標的HTTP通道,簡單講是HTTP的安全版。即HTTP下加入SSL層,HTTPS的安全基礎是SSL,因此加密的詳細內容就需要SSL。
超文本傳輸協議HTTP協議被用於在Web瀏覽器和網站服務器之間傳遞信息。HTTP協議以明文方式發送內容,不提供任何方式的數據加密,如果攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文,就可以直接讀懂其中的信息,因此HTTP協議不適合傳輸一些敏感信息,比如信用卡號、密碼等。
為了解決HTTP協議的這一缺陷,需要使用另一種協議:安全套接字層超文本傳輸協議HTTPS。為了數據傳輸的安全,HTTPS在HTTP的基礎上加入了SSL協議,SSL依靠證書來驗證服務器的身份,並為瀏覽器和服務器之間的通信加密。
HTTPS和HTTP的區別主要為以下四點:
- https協議需要到ca申請證書,一般免費證書很少,需要交費。
- http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。
- http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,后者是443。
- http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。
簡單的說,https就是在http的基礎上嵌套SSL協議,由此來實現身份認證,要理解SSL,還要說明一下非對稱加密體系。
非對稱加密
有非對稱加密,那么當然也有對稱加密,下面簡單說一下這兩者的區別。
- 對稱加密:指的是加密和解密使用的是同一個密鑰,發送者使用秘鑰A對信息加密,然后傳送密文,接受者使用密鑰A對密文解密,得到信息。若此時使用密鑰B解密此密文,則無法進行解密。為了保證加密的可靠性,發送者和接受者都要保證密鑰A不被泄露。
- 非對稱加密:使用一對密鑰進行加密和解密操作,分別稱為公鑰和私鑰,公鑰和私鑰是成對生成的,公鑰往往是公開的,任何人都可以得到,私鑰是保密的,只有特定的人才擁有。非對稱加密有兩種典型的使用情況,分別是加密和驗證。
下面簡單介紹加密與驗證。
加密:
- 加密是為了傳送需要保密的信息,所以需要保證只有特定的人才可以對信息進行解密。
- 發送者使用公鑰A加密,接受者使用私鑰A解密。假設所有人都擁有公鑰A,只有張三有私鑰A,那么,其他人想要給張三發送信息,只需要將信息使用公鑰A加密,那么密文只有擁有私鑰A的張三才可以解密。
驗證:
- 驗證是為了向其他人證明“我就是我”的問題。
- 在這里,發送者使用私鑰進行A簽名,接受者使用公鑰A進行驗證。還是假設所有人都擁有公鑰A,只有張三有私鑰A,現在張三要向其他人證明自己就是張三,於是張三將“我是張三”這段信息使用私鑰A進行簽名,發送給其他人,其他人使用公鑰A解密,得到簽名“我是張三”,於是其他人就認為這段信息是張三發送的。
- 這里有一個問題,就是任何人都可以使用自己的私鑰將“我是張三”簽名,從而仿冒張三,假設此時有一個李四,他用自己的私鑰B簽名“我是張三”,這使其他擁有公鑰B的人會認為李四就是張三。
- 解決這個問題的方法就是引入有足夠公信力的第三方,由第三方負責驗證誰是誰的問題(就像我們使用公安局簽發的身份證就可以證明自己是自己)。張三為了證明自己是張三,他會將“我是張三”發送給第三方,第三方用自己的私鑰C將驗證信息加密(這就是簽名),將加密后的簽名返回給張三,以后張三就會使用這個簽名來證明自己是張三。其他人只會只用第三方的公鑰對簽名進行驗證。這是如果李四要仿冒自己是張三,他用自己私鑰B加密后的驗證信息,其他人用第三方的公鑰C是無法解密的。
- 在https中,CA就是這個第三方,CA(Certificate Authority),也稱為電子商務認證中心,是負責發放和管理數字證書的權威機構,並作為電子商務交易中受信任的第三方,承擔公鑰體系中公鑰的合法性檢驗的責任。CA具體流程下面再說。
https建立流程
首先上圖,這張圖顯示了https建立的流程。
下面簡單解釋一下這個流程:
- CA建立,並頒發給自己根證書。即CA使用自己的私鑰,將CA的驗證信息和自己的公鑰打包加密成根證書。
- CA與瀏覽器廠商(browser vendor)聯系,告訴瀏覽器廠商自己的證書,如果瀏覽器廠商信任這個CA,就會把這個CA的證書加入到自己開發的瀏覽器中。
- 一個想要獲取https服務的網站,首先要將自己的驗證信息和自己的公鑰發送給CA,並向CA申請自己的證書,CA在驗證這個網站的合法性之后,會用CA自己的私鑰對網站的驗證信息和公鑰打包加密,形成這個網站的證書,並將這個證書頒發給網站。
- 現在網站已經有了自己的證書了,於是他可以搭建自己的https服務。
- 現在一個客戶端要使用網站的https服務,網站會將自己的證書發送給客戶端。客戶端使用CA的證書對網站證書進行驗證,核實無誤后建立安全連接,即SSL握手過程。
- 由客戶端開始。客戶端發送SSL版本,以及加密和壓縮算法給服務器。服務器檢查是否支持此版本SSL,並啟動客戶端期望的加密和壓縮算法。
- 基礎配置完畢后,服務器發送自己的證書。該證書必須被客戶端信任,或者被客戶端信任的CA所信任。
- 客戶端驗證證書,並核實服務器的身份是正確的。
- 驗證完畢后,兩者協商之后使用的加密方式,並且客戶端告訴服務器,從現在起,所有數據互換都是加密的,並發送一個加密的驗證”消息“給服務器。
- 服務器驗證是客戶端發送的,並且”消息“可以被解密。服務器將解密后的”消息“發送給客戶端。客戶端核實后,安全連接。握手結束。
- 之后,客戶端和服務器可以使用https服務進行加密通信了,不過之后的通信一般使用對稱加密算法來實現,因為相較於非對稱加密,對稱加密所占資源更少。
2.搭建https服務
本機環境:Ubuntu 17.10 , Openssl 1.0.2g , FireFox 57.0.1 (64 位) , Apache 2.4.27
首先確認安裝OpenSSL
確定OpenSSL版本:
$openssl version
如果版本低於1.0.1f,建議升級,因為1.0.1f版本之下的OpenSSL有一個Heartbleed漏洞。
安裝OpenSSL:
$sudo apt-get install openssl
自建CA
因為向CA申請簽名是需要收費的,所以我們選擇自己搭建一個CA來完成這個實驗過程。
首先建立myCA目錄用於存放CA相關信息
cd && mkdir -p myCA/signedcerts && mkdir myCA/private && cd myCA
myCA 用於存放 CA 根證書,證書數據庫,以及后續服務器生成的證書,密鑰以及請求
signedcerts:保存簽名證書的 copy
private: 包含私鑰
之后配置myCA相關參數,在myCA目錄下進行
echo '01'>serial && touh index.txt
然后創建 caconfig.cnf 文件
vim ~/myCA/caconfig.cnf
caconfig.cnf文件內容如下
# My sample caconfig.cnf file.
#
# Default configuration to use when one is not provided on the command line.
#
[ ca ]
default_ca = local_ca
#
#
# Default location of directories and files needed to generate certificates.
#
[ local_ca ]
dir = /home/<username>/myCA # 這里要將username替換為你的用戶名
certificate = $dir/cacert.pem
database = $dir/index.txt
new_certs_dir = $dir/signedcerts
private_key = $dir/private/cakey.pem
serial = $dir/serial
#
#
# Default expiration and encryption policies for certificates.
#
default_crl_days = 365
default_days = 1825
default_md = SHA256
#
policy = local_ca_policy
x509_extensions = local_ca_extensions
#
#
# Default policy to use when generating server certificates. The following
# fields must be defined in the server certificate.
#
[ local_ca_policy ]
commonName = supplied
stateOrProvinceName = supplied
countryName = supplied
emailAddress = supplied
organizationName = supplied
organizationalUnitName = supplied
#
#
# x509 extensions to use when generating server certificates.
#
[ local_ca_extensions ]
subjectAltName = DNS:localhost
basicConstraints = CA:false
nsCertType = server
#
#
# The default root certificate generation policy.
#
[ req ]
default_bits = 2048
default_keyfile = /home/<username>/myCA/private/cakey.pem # 這里要將username替換為你的用戶名
default_md = SHA256
#
prompt = no
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions
#
#
# Root Certificate Authority distinguished name. Change these fields to match
# your local environment!
#
[ root_ca_distinguished_name ]
commonName = MyOwn Root Certificate Authority # CA機構名
stateOrProvinceName = JS # CA所在省份
countryName = CN # CA所在國家(僅限2個字符)
emailAddress = XXXX@XXX.com # 郵箱
organizationName = XXX #
organizationalUnitName = XXX #
#
[ root_ca_extensions ]
basicConstraints = CA:true
生成 CA 根證書和密鑰
export OPENSSL_CONF=~/myCA/caconfig.cnf #該命令用於給環境變量 OPENSSL_CONF 賦值為caconfig.cnf。
openssl req -x509 -newkey rsa:2048 -out cacert.pem -outform PEM -days 1825 # 生成 CA 根證書和密鑰
該命令需要用戶設置密碼。不要忘記。
以上步驟生成了 CA 自簽名根證書,和 RSA 公/私密鑰對。證書的格式是 PEM,有效期是1825天。
- /myCA/cacert.pem: CA 根證書
- /myCA/private/cakey.pem: CA 私鑰
創建服務器公私鑰
生成服務器配置文件exampleserver.cnf
vim ~/myCA/exampleserver.cnf
exampleserver.cnf文件內容如下
#
# exampleserver.cnf
#
[ req ]
prompt = no
distinguished_name = server_distinguished_name
[ server_distinguished_name ]
commonName = localhost # 服務器域名
stateOrProvinceName = JS # 服務器所在省份
countryName = CN # 服務器所在國家(僅限2個字符)
emailAddress = XXXX@XXX.com # 郵箱
organizationName = XXX #
organizationalUnitName = XXX #
生成服務器證書和密鑰
export OPENSSL_CONF =~/myCA/exampleserver.cnf # 該命令設置環境變量 OPENSSL_CONF,使得 openssl 更換配置文件。
openssl req -newkey rsa:1024 -keyout tempkey.pem -keyform PEM -out tempreq.pem -outform PEM
同樣的,需要輸入密碼短語。
之后,有2種對臨時秘鑰的操作,選擇其一即可
1.將臨時私鑰轉換為 unencrypted key,即秘鑰不加密狀態。
penssl rsa -in tempkey.pem -out server_key.pem
需要輸入密碼短語。
2.如果希望將 key 保持為加密狀態,直接改名
mv tempkey.pem server_key.pem
兩者的區別是,第二種需要在服務器啟動時輸入私鑰的密碼短語,否則會導致服務器啟動失敗,但第二種安全性高於第一種,可以更好的保護秘鑰。
使用 CA key 對服務器證書簽名
export OPENSSL_CONF=~/myCA/caconfig.cnf
openssl ca -in tempkey.pem -out server_crt.pem
刪除臨時證書和密碼文件
rm -f tempkey.pem && rm -f tempreq.pem
現在,自簽名的服務器證書和密鑰對便產生了:
- server_crt.pem : 服務器證書文件
- server_key.pem : 服務器密鑰文件
配置 Apache
建立ssl配置文件,lab-ssl.conf
vim /etc/apache2/sites-available/lab-ssl.conf
lab-ssl.conf文件內容如下
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/lab # 網站目錄
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on
# A self-signed (snakeoil) certificate can be created by installing
# the ssl-cert package. See
# /usr/share/doc/apache2/README.Debian.gz for more info.
# If both key and certificate are stored in the same file, only the
# SSLCertificateFile directive is needed.
#SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
#SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
# 網站證書和私鑰地址
SSLCertificateFile /home/libaoquan/myCA/server_crt.pem
SSLCertificateKeyFile /home/libaoquan/myCA/server_key.pem
# Server Certificate Chain:
# Point SSLCertificateChainFile at a file containing the
# concatenation of PEM encoded CA certificates which form the
# certificate chain for the server certificate. Alternatively
# the referenced file can be the same as SSLCertificateFile
# when the CA certificates are directly appended to the server
# certificate for convinience.
#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt
# Certificate Authority (CA):
# Set the CA certificate verification path where to find CA
# certificates for client authentication or alternatively one
# huge file containing all of them (file must be PEM encoded)
# Note: Inside SSLCACertificatePath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCACertificatePath /etc/ssl/certs/
#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
# Certificate Revocation Lists (CRL):
# Set the CA revocation path where to find CA CRLs for client
# authentication or alternatively one huge file containing all
# of them (file must be PEM encoded)
# Note: Inside SSLCARevocationPath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCARevocationPath /etc/apache2/ssl.crl/
#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
# Client Authentication (Type):
# Client certificate verification type and depth. Types are
# none, optional, require and optional_no_ca. Depth is a
# number which specifies how deeply to verify the certificate
# issuer chain before deciding the certificate is not valid.
#SSLVerifyClient require
#SSLVerifyDepth 10
# SSL Engine Options:
# Set various options for the SSL engine.
# o FakeBasicAuth:
# Translate the client X.509 into a Basic Authorisation. This means that
# the standard Auth/DBMAuth methods can be used for access control. The
# user name is the `one line' version of the client's X.509 certificate.
# Note that no password is obtained from the user. Every entry in the user
# file needs this password: `xxj31ZMTZzkVA'.
# o ExportCertData:
# This exports two additional environment variables: SSL_CLIENT_CERT and
# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
# server (always existing) and the client (only existing when client
# authentication is used). This can be used to import the certificates
# into CGI scripts.
# o StdEnvVars:
# This exports the standard SSL/TLS related `SSL_*' environment variables.
# Per default this exportation is switched off for performance reasons,
# because the extraction step is an expensive operation and is usually
# useless for serving static content. So one usually enables the
# exportation for CGI and SSI requests only.
# o OptRenegotiate:
# This enables optimized SSL connection renegotiation handling when SSL
# directives are used in per-directory context.
#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
# SSL Protocol Adjustments:
# The safe and default but still SSL/TLS standard compliant shutdown
# approach is that mod_ssl sends the close notify alert but doesn't wait for
# the close notify alert from client. When you need a different shutdown
# approach you can use one of the following variables:
# o ssl-unclean-shutdown:
# This forces an unclean shutdown when the connection is closed, i.e. no
# SSL close notify alert is send or allowed to received. This violates
# the SSL/TLS standard but is needed for some brain-dead browsers. Use
# this when you receive I/O errors because of the standard approach where
# mod_ssl sends the close notify alert.
# o ssl-accurate-shutdown:
# This forces an accurate shutdown when the connection is closed, i.e. a
# SSL close notify alert is send and mod_ssl waits for the close notify
# alert of the client. This is 100% SSL/TLS standard compliant, but in
# practice often causes hanging connections with brain-dead browsers. Use
# this only for browsers where you know that their SSL implementation
# works correctly.
# Notice: Most problems of broken clients are also related to the HTTP
# keep-alive facility, so you usually additionally want to disable
# keep-alive for those clients, too. Use variable "nokeepalive" for this.
# Similarly, one has to force some clients to use HTTP/1.0 to workaround
# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
# "force-response-1.0" for this.
# BrowserMatch "MSIE [2-6]" \
# nokeepalive ssl-unclean-shutdown \
# downgrade-1.0 force-response-1.0
</VirtualHost>
</IfModule>
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
啟動ssl服務
a2ensite /etc/apache2/sites-available/lab-ssl.conf
a2enmod ssl
查看是否正確配置
在瀏覽器地址欄輸入 https://localhost
發現瀏覽器不信任這個網站,為什么?行為這個網站的證書是用我們自己的CA簽名的,瀏覽器並不信任我們自己建立的CA,所以我們需要手動導入CA證書讓瀏覽器信任我們的CA。
導入步驟如下:
打開 FireFox 瀏覽器,依次選擇“編輯”----“首選項”----“隱私與安全”----“證書”----“查看證書”----“證書機構”,點擊導入,選擇 myCA 目錄下的根證書“cacert.pem”, 導入。
之后,再次瀏覽localhost
地址欄有一個綠色的鎖,至此https服務搭建完成。