查看源代码 使用 SSL
要准备应用程序以通过 SSL 提供服务请求,我们需要添加一些配置和两个环境变量。为了使 SSL 能够正常工作,我们需要从证书颁发机构获取密钥文件和证书文件。我们需要配置的环境变量是这两个文件的路径。
配置包括一个新的 https:
键,用于我们的端点,其值是端口、密钥文件路径和证书 (PEM) 文件路径的关键字列表。如果我们添加 otp_app:
键,其值为我们应用程序的名称,Plug 将开始在应用程序的根目录中查找它们。然后,我们可以将这些文件放入我们的 priv
目录中,并将路径设置为 priv/our_keyfile.key
和 priv/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 套接字选项。有关可用选项及其默认值的更多信息,请参阅 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
在很多情况下,您可能希望通过将 HTTP 重定向到 HTTPS 来强制所有传入请求使用 SSL。这可以通过在端点配置中设置 :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]]
要动态地重定向到当前请求的 host
,请将 :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 Strict-Transport-Security" 的缩写,是一种机制,允许网站将自己声明为只能通过安全连接 (HTTPS) 访问。它是为了防止剥离 SSL/TLS 加密的中间人攻击而引入的。HSTS 会导致网络浏览器从 HTTP 重定向到 HTTPS,并且拒绝连接,除非连接使用 SSL/TLS。
设置了 force_ssl: [hsts: true]
后,会添加 Strict-Transport-Security
标头,并带有定义策略有效持续时间的 max-age。现代网络浏览器会对此做出反应,从 HTTP 重定向到 HTTPS,以及其他结果。 RFC6797 定义了 HSTS,它还规定 **浏览器应该跟踪主机的策略,并在策略过期之前应用它。** 它进一步规定 **除 80 端口之外的任何端口上的流量都应假定为已加密**,符合该策略。
虽然建议在生产环境中使用 HSTS,但它可能会导致在访问 localhost 上的应用程序时出现意外行为。例如,使用启用了 HSTS 的 https://localhost:4000
访问应用程序会导致以下情况:来自 localhost 的所有后续流量(端口 80 除外)都应加密。这可能会破坏您计算机上与 Phoenix 应用程序无关的其他本地服务器或代理的流量,并且可能不支持加密流量。
如果您无意中为 localhost 启用了 HSTS,您可能需要重置浏览器的缓存,然后它才会再次接受来自 localhost 的 HTTP 流量。
对于 Chrome
- 打开开发者工具面板。
- 单击并按住地址栏旁边的重新加载图标以显示下拉菜单。
- 选择 "清空缓存并强制重新加载"。
对于 Safari
- 清除您的浏览器缓存。
- 从
~/Library/Cookies/HSTS.plist
中删除条目或完全删除该文件。 - 重新启动 Safari。
对于其他浏览器,请参考 HSTS 的文档。
或者,在 force_ssl
上将 :expires
选项设置为 0
应该会使条目过期并禁用 HSTS。
有关 HSTS 选项的更多信息,请参阅 Plug.SSL。