信安實踐——自建CA證書搭建https服務器


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服務搭建完成。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM