是時候來了解下 HTTPS 網站的部署了

2018 年的最後一個月,我終於決定給本身 3 年前申請的域名搞個 SSL 證書,讓網站能夠上車 HTTPS。免費、適合我的網站(玩票)的 SSL 證書方案,首選 Let's Encrypt。可是與一開始「一小時搞定」的預期不一樣,最終完成整件事情花了我一個週末的時間,仍是有必要記錄下來。html

背景

固然 HTTPS 是大勢所趨,但由於懶本身並無真正地搞過 SSL 證書、部署 HTTPS 網站。終於痛下決心部署 HTTPS 是源於本身想要在本身申請的騰訊雲 VPS 主機上部署一套 jenkins 站點,而由於我域名沒有在國內備案,致使使用域名訪問時被騰訊雲限制不可訪問。 從我的開發者手動部署一個可運行網站的方案提及:node

  1. 事先準備
    • 一個可經過公網 IP 訪問的雲主機做爲服務器,以我我的雲主機 IP 爲例:118.24.121.85
    • 在域名商所購買的域名,以我我的域名爲例:myan.im
  2. 經過 ssh 登陸到服務器,手動安裝並啓動 Nginx 服務
  3. 在域名商網站上添加一條 A 類型的 DNS 記錄,將域名 c.myan.im 指向以上 IP 地址
    • 配置成功後,經過 ping 命令便可檢查 DNS 生效

完成第 2 步後,咱們就已經能夠經過 IP 和端口(默認 80)直接訪問網站,驗證也經過。nginx

curl http://118.24.121.85
複製代碼

完成第 3 步後,原本指望的表現是訪問 http://c.myan.im 也有一樣的表現,但很不幸:git

dnspod重定向截圖

經過 curl 檢查也可發現,http 請求返回的是 302 頭,Location 頭爲 dnspod.qcloud.com/static/bloc…程序員

> curl http://c.myan.im -v

< HTTP/1.1 302
< Location: https://dnspod.qcloud.com/static/block.html?d=c.myan.im
複製代碼

very-good

總算見識到了網站不備案的後果!可見咱們把我的網站域名解析到國內主機,沒有問題。但若是網站沒有備案,對不起門都不讓你進🤷。web

至於技術上如何實現,其實這就是典型的 HTTP 劫持問題,站在騰訊雲的角度思考:chrome

  1. HTTP 請求發起,路由到 Web Server 的服務器 IP,要通過騰訊雲的網絡
  2. 請求鏈路到達騰訊雲主機前,騰訊雲能夠 獲取 HTTP 請求詳情
  3. 騰訊雲讀取報文 Host,檢查是否備案;如未備案,則直接返回 302 重定向狀態,請求未觸發服務器相應的 IP:PORT
  4. 瀏覽器收到 302 並跳轉到 Location 指定地址

問題出如今第 3 步,由於 HTTP 是明文傳輸協議,意味着不光騰訊雲,甚至客戶端到服務端網絡鏈路上的任何一個環節,都能夠讀取 HTTP 報文內容。apache

HTTP 劫持案例後端

  1. 運營商劫持網頁,插入流量包廣告
  2. Charles 代理修改請求,修改返回值
  3. 路由器修改 User-Agent 頭,致使 bug

HTTPS 反劫持

原理

從基本原理上講,HTTPS 能夠說是 HTTP 與 SSL/TLS 協議的結合。在進行應用層的報文傳輸前,要經過 TLS 協議創建加密會話。瀏覽器

tls-handshake

固然這個圖的握手原理並非本文的重點,咱們關注的是所謂證書在 SSL 鏈接中的做用。在 Let's Encrypt 的工具 certbot 文檔頁,他們這樣解釋什麼是證書:

A public key or digital certificate (formerly called an SSL certificate) uses a public key and a private key to enable secure communication between a client program (web browser, email client, etc.) and a server over an encrypted SSL (secure socket layer) or TLS (transport layer security) connection. The certificate is used both to encrypt the initial stage of communication (secure key exchange) and to identify the server. The certificate includes information about the key, information about the server identity, and the digital signature of the certificate issuer. If the issuer is trusted by the software that initiates the communication, and the signature is valid, then the key can be used to communicate securely with the server identified by the certificate. Using a certificate is a good way to prevent 「man-in-the-middle」 attacks, in which someone in between you and the server you think you are talking to is able to insert their own (harmful) content.

能夠總結爲如下幾點:

  • 證書使用一個密鑰對(公鑰、私鑰)用來加密客戶端與服務端通訊
  • 證書做用包括:通信初始化階段加密、代表服務器身份
  • 證書包含了公鑰信息、服務器身份信息,以及證書籤發者簽名

除了咱們平常在瀏覽器中訪問 HTTPS 網站,能夠在點擊地址欄左側看到正在訪問網站的 SSL 證書,還有這些案例,咱們能夠感知到證書的存在的:

  • 多年前的 12306 須要本身下載證書、安裝證書
  • 採用 EAP-PEAP 認證的企業 WiFi 辦公網絡,在客戶端(如手機)連上 WiFi 後,操做系統會提醒咱們安裝公司企業證書並信任,這樣一來客戶端就能夠訪問該證書保護的內網(Intranet)HTTPS 網站
  • iOS 安裝企業 App,信任證書後,能夠繞過 App Store 安裝應用

獲取自簽名 SSL 證書

從自簽名證書提及:咱們能夠本身簽名,本身生成一個證書,並在 nginx 部署。

瀏覽器同樣會發起請求,但在與服務器端創建安全套接層過程當中,瀏覽器會認爲該證書不可信任。理論上:咱們能夠把本身的證書,內置在瀏覽器中,就能夠解決這個問題。


如下是實踐步驟:

  1. 生成 key 與證書

    openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
    複製代碼

    該命令生成的證書是 CA 根證書,使用

  2. 檢查證書

    openssl x509 -text -noout -in certificate.pem
    複製代碼
  3. 有了證書文件、key 文件後,就能夠在 nginx 裏使用以下配置,啓用 HTTPS 支持,並監聽 443 端口:

    server {
        listen       80;
        listen       443 ssl;
        server_name  fake.myan.im;
        root         /usr/share/nginx/html;
    
        ssl on;
        ssl_certificate /path/to/certificate.pem; # 證書文件路徑
        ssl_certificate_key /path/to/key.pem; # key 文件路徑
        error_page 404 /404.html;
        location = /40x.html {
            root   html;
        }
    
        location / {
        }
    
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
    複製代碼

    其後,使用經過 sudo systemctl restart nginx 命令重啓 nginx 進程。

  4. 瀏覽器訪問 fake.myan.im 被瀏覽器告警:證書無效

  5. scp 下載證書文件到本地,並雙擊打開證書文件,安裝並信任該證書

    # remote.host 爲遠程主機地址
    # ~/local/path 爲本地下載目錄
    scp remote.host:/path/to/certificate.pem ~/local/path
    複製代碼

    Install Certificate

使用 Safari 瀏覽器查看,即發現已經能夠訪問了。

safari-self-signed-https

若是使用 Chrome 瀏覽器訪問,會發現仍是會證書錯誤。這是由於 Chrome 58 後的版本,對自簽名證書的安全性要求更高,須要更復雜的自簽名過程。參考 serverfault.com/questions/8…

真實世界裏的證書申請和使用

如今咱們知道,自簽名證書也好,真實有含金量的真實證書也好,歸根結底都只是一個證書文件。咱們須要把它放在咱們的主機上,再配置一下 nginx 使用這個證書來 Serve HTTPS 服務。

免費的證書最流行的選擇是 Let's Encrypt,由國內雲服務商也有本身配套的 SSL 證書可以使用,但 Let's Encrypt 勝在足夠通用。其限制是默認只有 3 個月有效期,到期後須要從新 renew 操做。

要了解 Let's Encrypt 的工做原理,參考:How It Works - Let's Encrypt - Free SSL/TLS Certificates

關於 Let's Encrypt 常見問題,參考:FAQ - Let's Encrypt - Free SSL/TLS Certificates

Let's Encrypt 提供的核心服務是證書頒發的基礎服務,不少第三方服務在此基礎上作了封裝,給用戶提供免費證書服務。一個典型的例子是咱們不少人耳熟能詳的 Github Pages 服務,Github Pages 支持綁定自定義的域名,啓用域名綁定後無需用戶自行配置,就能夠經過 https:// 協議訪問。

要手動獲取證書,並自行部署 HTTPS,Let's Encrypt 推薦使用 eff.org 的命令行工具 Certbot

安裝 certbot-auto 命令行

TL;DR:不要使用 yum 安裝的包,wget 下載腳本便可

參考 certbot.eff.org/docs/instal… 說明文檔,直接把命令行工具下載到本地。

> wget https://dl.eff.org/certbot-auto
> chmod a+x ./certbot-auto
> ./certbot-auto --help
複製代碼

使用 certbot 自動模式獲取指定域名證書

certbot 有自動模式,能夠幫 nginx,apache 等服務器自動生成證書文件並配置網站。

咱們以 real.myan.im 爲例,示範如何獲取該域名的證書。

  1. 首先須要配置 http 服務,關鍵配置以下。在 conf.d 目錄下新建文件,並重啓 nginx 服務

    server {
        listen       80;
        server_name  real.myan.im;
        root         /usr/share/nginx/html;
    
        location / {
        }
    }
    複製代碼
  2. 執行 certbot-auto 命令,默認即會使用自動模式進入 CLI 交互

  3. ~ > ./certbot-auto
    複製代碼

    依次選擇指定域名,如下是交互式輸出:

    Which names would you like to activate HTTPS for?
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    1: g.myan.im
    2: real.myan.im
    3: v.myan.im
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select the appropriate numbers separated by commas and/or spaces, or leave input
    blank to select all options shown (Enter 'c' to cancel): 2
    Obtaining a new certificate
    Performing the following challenges:
    http-01 challenge for real.myan.im
    Waiting for verification...
    Cleaning up challenges
    Deploying Certificate to VirtualHost /etc/nginx/conf.d/real.conf
    
    Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    1: No redirect - Make no further changes to the webserver configuration.
    2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
    new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
    Redirecting all traffic on port 80 to ssl in /etc/nginx/conf.d/real.conf
    
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Congratulations! You have successfully enabled https://real.myan.im
    
    You should test your configuration at:
    https://www.ssllabs.com/ssltest/analyze.html?d=real.myan.im
    複製代碼
  4. 訪問 real.myan.im 見證奇蹟

certbot 工具自動模式,幫助咱們傻瓜式地完成了證書申請、網站全部權驗證、nginx 配置三個過程。

輸出文件保存在指定目錄下,其中最重要的證書文件和私鑰文件,咱們能夠保存到其餘地方。

certbot 腳本執行原理

要了解自動模式的工做原理,咱們要來讀一下 log 輸出。

首先自動模式會去讀取 nginx 已有的網站配置,須要依賴咱們實現配置好 http 格式的 Web 服務。

自動模式下,有一個自動完成的步驟:

Performing the following challenges:
http-01 challenge for real.myan.im
Waiting for verification...
Cleaning up challenges
複製代碼

背後所作的事情,是向咱們的 real.myan.im 發送一個特定 URL 的 http 請求,指望獲得某隨機值,該數值由 Lets Encrypt 指定。若匹配,則認爲申請該證書的操做人員,擁有該網站全部權。

這裏意味着,若是我在國內的主機上使用 certbot 執行以上操做,命令執行到此會出錯。由於全部使用 HTTP 方式訪問的請求,都會被劫持,返回 302 重定向。

此後繼續執行,certbot 就得到到了證書和密鑰文件,並完成了指定 nginx 服務的 ssl 配置過程。

certbot 手動模式獲取通配符 SSl 證書

若是有多個子域名想要支持 https,一個個地使用通配符能夠更加方便節省人力。

對於我的來講,通配符證書更加適合咱們使用手動模式完成。

  1. 收集證書信息
  2. 發起質詢(challenge),以確認操做人是否確實有其所聲稱的域名全部權
  3. 驗證經過,下發證書

以 *.subdomain.myan.im 爲例,咱們執行如下命令。

> ./certbot-auto certonly --manual --preferred-challenges=dns --email mamengguang@gmail.com -d *.subdomain.myan.im
複製代碼

certbot 將會輸出:

Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for subdomain.myan.im

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.subdomain.myan.im with the following value:

KCH1u2GEXay6HNkfbfQd5zqP4tvp-sMFtF9UXHmRRpU

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
複製代碼

此時,咱們須要停下來,登陸 DNS 服務控制檯,按照要求添加一條 TXT 類型的 DNS 記錄。

add-txt-record

使用如下命令能夠驗證

dig -t txt _acme-challenge.subdomain.myan.im
複製代碼

acme-challenge-verify

點擊 Enter,繼續向下執行:

Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:

...
複製代碼

到此咱們就獲得了一個支持通配符的 SSL 證書,爲了驗證其有效性,咱們能夠新增多個符合通配符的子域名,部署在這臺主機上。

  • 新增 DNS 記錄:x.subdomain.myan.im 到 118.24.121.85
  • 在 host 機上新增 nginx 配置,/etc/nginx/conf.d/x.subdomain.myan.im

對比

絕對域名 通配符域名
適用環境 HTTP 網絡通暢,無劫持 A. 子網站無需分開管理 B. 操做者擁有域名 DNS 管理權
驗證方式 經過 HTTP 請求驗證 經過 DNS Record 驗證
certbot 操做 自動模式,傻瓜式操做 手動模式,須要自行切到 DNS 管理平臺添加

咱們這裏爲表達方便所說的所謂「絕對域名」和「通配符域名」,實際對應着 SSL 證書的 Common Names 信息。但 Common Names 值與證書所適配的域名嚴格來講不是一個概念,由於 SSL 證書最新標準支持主題備用名稱(Subject Alternative Name,SAN)特性,該特性容許一個證書能夠保護主域名和其餘多個額外的備用域名。

一個典型的例子是 Google 的 *.google.com 證書,證書的 Common Names 爲 *.google.com 可是它除了支持 google.com 下的各級子域名,也支持 google.cngoogle.ca 等 Google 各國家頂級域名甚至 youtube.com 等 Google 旗下域名。

以下圖是 youtube.com 網站的 SSL 證書 *.google.com。

youtube-ssl

上面的例子中,咱們使用 *.subdomain.myan.im 這樣的 「通配符證書」 保護 subdomain.myan.im 的子域名,也是由於 SAN 特性的支持。

證書續期

在實際使用 certbot 過程當中,考慮 Let's Encrypt 免費證書 90 天的有效期限制,務必還要在到期前自行 renew 證書。

這裏能夠配置 crontab 任務自動定時執行 renew 操做,再也不贅述,可參考這一篇博客文章 Let's Encrypt 終於支持通配符證書了

小結

以上是我使用 Let's Encrypt 爲我的網站部署 HTTPS 的踩坑記錄,順便還有部署過程當中關於 HTTPS 的知識點探索:

  • HTTP 劫持
  • 經過 HTTPS 反劫持,理解 SSL 證書做用
  • 使用 certbot 工具獲取免費 Let's Encrypt 證書方式

篇幅所限內容省去很多細節,僅偏向於基本概念與操做流程。

固然在公司的實際工做中,HTTPS 證書的維護和部署通常都由專業運維人員負責,但做爲先後端程序員,本身上手部署一下 HTTPS,更有利於讓咱們知曉 HTTPS 其然與其因此然。因此 Just Do It 吧!

相關文章
相關標籤/搜索