檢視原始碼 使用 SSL

若要準備一個應用程式透過 SSL 服務要求,我們需要加入一些設定,以及兩個環境變數。對 SSL 而言,實際上我們需要從憑證授權機構取得金鑰檔和憑證檔。我們需要的環境變數,就是這兩個檔案的路徑。

設定包含一個新的 https: 鍵,這是一個端點的關鍵字清單,其值則是埠號、金鑰檔路徑,以及憑證 (PEM) 檔路徑。如果我們加入 otp_app: 鍵,其值是我們應用程式的名稱,Plug 便會從我們的應用程式根目錄開始搜尋。接著我們可以將這些檔案放入 priv 目錄,並設定路徑為 priv/our_keyfile.keypriv/our_cert.crt

以下是 config/runtime.exs 中的範例設定。

import Config

config :hello, HelloWeb.Endpoint,
  http: [port: {:system, "PORT"}],
  url: [host: "example.com"],
  cache_static_manifest: "priv/static/cache_manifest.json",
  https: [
    port: 443,
    cipher_suite: :strong,
    otp_app: :hello,
    keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
    certfile: System.get_env("SOME_APP_SSL_CERT_PATH"),
    # OPTIONAL Key for intermediate certificates:
    cacertfile: System.get_env("INTERMEDIATE_CERTFILE_PATH")
  ]

如果沒有 otp_app: 鍵,我們需要提供檔案的絕對路徑,不論它們在檔案系統中的任何位置,讓 Plug 能夠找到它們。

Path.expand("../../../some/path/to/ssl/key.pem", __DIR__)

https: 鍵下的選項會傳遞給 Plug 介面,通常是 Bandit,接著它會使用 Plug.SSL 選取 TLS Socket 選項。請參閱 Plug.SSL.configure/1 文件,以取得更多關於可用選項及其預設值的資訊。Plug HTTPS 指南Erlang/OTP ssl 文件也提供有價值的資訊。

開發中的 SSL

如果你希望在開發中使用 HTTPS,可以透過執行以下指令產生自簽憑證: mix phx.gen.cert。這需要 Erlang/OTP 20 或更新的版本。

使用你的自簽憑證,你的開發設定在 config/dev.exs 中可以更新為執行 HTTPS 端點

config :my_app, MyAppWeb.Endpoint,
  ...
  https: [
    port: 4001,
    cipher_suite: :strong,
    keyfile: "priv/cert/selfsigned_key.pem",
    certfile: "priv/cert/selfsigned.pem"
  ]

這可以取代你的 http 設定,或者你可以在不同的埠上執行 HTTP 和 HTTPS 伺服器。

強制 SSL

在許多情況下,你會希望強制所有進來的請求使用 SSL,方法是以重新導向 HTTP 到 HTTPS。這可透過設定端點組態中的選項 :force_ssl 完成。它預期會有一個選項清單,這些選項會轉送至 Plug.SSL。預設情況下,它會在 HTTPS 請求中設定「strict-transport-security」標頭,強制瀏覽器永遠使用 HTTPS。如果傳送不安全的 (HTTP) 請求,它會使用 :url 組態中所指定的 :host 重新導向至 HTTPS 版本。例如

config :my_app, MyAppWeb.Endpoint,
  force_ssl: [rewrite_on: [:x_forwarded_proto]]

若要動態地重新導向至目前請求的 主機,請將 :force_ssl 組態中的 :host 設定為 nil

config :my_app, MyAppWeb.Endpoint,
  force_ssl: [rewrite_on: [:x_forwarded_proto], host: nil]

在這些範例中, rewrite_on: 鍵指定了一個反向代理程式或負載平衡器於應用程式前所使用的 HTTP 標頭,用來表示請求是由 HTTP 或 HTTPS 接收的。有關將 TLS 卸載至外部元素的含意之詳細資訊,特別是與安全性 cookie 相關的部分,請參閱 Plug HTTPS 指南。請注意,該文件中傳遞給 Plug.SSL 的選項應使用 Phoenix 應用程式中的 force_ssl: 端點選項設定。

重要的是要注意, force_ssl:編譯 期間的組態,因此通常會設定在 prod.exs 中,如果從 runtime.exs 設定時不會作用。

HSTS

HSTS 是「HTTP 嚴格傳輸安全」的縮寫,是一種允許網站宣告自身僅可透過安全連線 (HTTPS) 存取的機制。它的引入是為了防止會移除 SSL/TLS 加密的中間人攻擊。HSTS 會導致網路瀏覽器從 HTTP 重新導向至 HTTPS,以及拒絕連線,除非該連線使用 SSL/TLS。

在設定 force_ssl: [hsts: true] 時,將新增 Strict-Transport-Security 標頭,其中附有定義原則有效期間的最大生存期。現代網路瀏覽器會透過從 HTTP 重新導向至 HTTPS 等方式對此回應。定義 HSTS 的 RFC6797 也規定,瀏覽器應追蹤主機的原則並應用於其到期日為止。它進一步規定,根據原則,假設在 80 埠以外的任何埠上的傳輸已加密。

儘管在執行階段會建議 HSTS,但在 localhost 上存取應用程式時可能會導致意料之外的行為。例如,存取在 https://127.0.0.1:4000 啟用 HSTS 的應用程式,就會導致所有後續來自 localhost 的流量(第 80 埠例外)預期都會被加密。這會中斷傳送至電腦上與 Phoenix 應用程式無關,且可能不支援加密流量的其他本機伺服器或代理伺服器的流量。

如果您不小心為 localhost 啟用 HSTS,您可能需要重設瀏覽器的快取,瀏覽器才會再度接受來自 localhost 的 HTTP 流量。

針對 Chrome

  1. 開啟「開發人員工具」面板。
  2. 按住網址列旁邊的「重新載入」圖示,就會出現一個下拉式選單。
  3. 選取「清除快取並強行重新載入」。

針對 Safari

  1. 清除瀏覽器的快取。
  2. 移除 ~/Library/Cookies/HSTS.plist 中的項目,或直接刪除整個檔案。
  3. 重新啟動 Safari。

針對其他瀏覽器,請查閱 HSTS 文件。

或者,將 force_ssl 上的 :expires 選項設定為 0 應該會使項目過期並停用 HSTS。

如需瞭解 HSTS 選項的更多資訊,請見 Plug.SSL