因此,您有了一个管理面板,因为与使用Rails控制台管理应用程序相比,它更容易。 另一方面,这是一个非常敏感的地方。 如果有人获得了访问权限,那将是……不好。
您已经拥有了所有东西:没有保存在电子邮件中的强密码,以及用于整个应用程序和蛮力保护的TLS。
但是,如果您和其他几个人甚至都无法访问管理面板,该怎么办?
一种方法是使其成为Intranet上的内部应用程序。 另一个选择可能是要求相互TLS身份验证, 即 ,客户端还使用客户端证书针对服务器对自身进行身份验证。 这就是我们在这篇文章中要讨论的内容。
设置相互TLS身份验证
相互认证? 这是如何运作的? 它涉及创建您自己的证书颁发机构,为管理面板自签名服务器和客户端证书,以及在浏览器中安装证书颁发机构和客户端证书。
这是否意味着您将不再需要传统的管理员登录保护? 从理论上讲,没有; 不再需要了。 但是,我们想在此处添加另一个不干扰用户的身份验证,因此我们将保留登录表单。 另外,我们仍然需要CSRF保护的登录名。
现有证书
您可能已经在管理面板中使用了TLS,因此,如有可能,请将其移至子域。 这样可以更轻松地为应用程序的不同部分处理不同的证书。
我要在https://client-ssl.bauland42.com/admin上安装我的系统。 出于演示目的,我预先安装了带有流行提供程序的Rails服务器,并且安装了一个简单的管理面板gem和Devise。 您可以像这样在路由中添加子域约束 :
constraints subdomain: 'admin' do
resources :users # or ActiveAdmin.routes(self) for the ActiveAdmin gem
end认证中心(CA)
我们将创建自己的CA,以对服务器和客户端证书请求进行签名。 根CA通常不直接签署证书。 通常,它们创建受信任的中间CA,以尽可能保留未使用的根证书密钥。
由于我们仅使用很少的证书,因此我们将跳过该步骤。 但是,我们必须保持根CA密钥非常安全。 最好的选择是仅将其保留在断开连接的计算机上。
认证机构证书
为了本演示的目的,我们将所有CA密钥和证书保留在/etc/nginx/certs/ca中。 我们将为CA使用密钥长度4096。
此处可以接受密钥长度为256位的3DES或AES加密算法,并且最好使用强密码。 这将为CA创建一个新的私钥和密码:
openssl genrsa -aes256 -out ca/ca.key 4096 chmod 400 ca/ca.key现在,我们可以使用SHA256哈希算法创建有效期为两年的根CA证书(不再使用SHA1):
openssl req -new -x509 -sha256 -days 730 -key ca/ca.key -out ca/ca.crt通过输入将所有属性字段留空. 。 仅CommonName将是42CA来标识证书。
chmod 444 ca/ca.crt您可以openssl x509 -noout -text -in ca/ca.crt使用openssl x509 -noout -text -in ca/ca.crt验证根证书,以检查有效性(2年)。 颁发者和主题均为42CA,因为这是根证书,始终是自签名的。
证书签名请求(CSR)
下一步是来自服务器的CSR,这是为特定域名创建证书的请求。 通常,CA和证书请求者是两个不同的公司,它们不想共享其私钥。 这就是为什么我们需要这个中间步骤。
首先,我们将为服务器创建一个私钥,然后为CSR创建一个私钥。 此处2048位密钥就足够了,因为该密钥仅有效一年,而4096位将减慢TLS握手。 虽然,当然,管理面板将看到相对较低的流量。 这次我们也省略了-aes256选项,因为我们不想在每次启动Web服务器时都输入密码。
openssl genrsa -out server/client-ssl.bauland42.com.key 2048
chmod 400 server/client-ssl.bauland42.com.key
openssl req -new -key server/client-ssl.bauland42.com.key -sha256 -out server/client-ssl.bauland42.com.csr对于后者,我们将为每个CSR详细信息输入一个点,但是“通用名称”必须是服务器的完全限定域名。 就我而言,它是client-ssl.bauland42.com 。
服务器证书
现在,我们将使用根CA签署CSR一年。 系统将提示您输入根CA的密码。
openssl x509 -req -days 365 -sha256 -in server/client-ssl.bauland42.com.csr -CA ca/ca.crt -CAkey ca/ca.key -set_serial 1 -out server/client-ssl.bauland42.com.crt
chmod 444 server/client-ssl.bauland42.com.crtopenssl x509 -noout -text -in server/client-ssl.bauland42.com.crt使用openssl x509 -noout -text -in server/client-ssl.bauland42.com.crt来验证有效性,颁发者(42CA)和主题( client-ssl.bauland42.com )。 可以肯定的是,我们还可以验证信任链。 虽然,它并不是真正的链条-根CA直接签署了服务器证书。 跑:
openssl verify -CAfile ca/ca.crt server/client-ssl.bauland42.com.crt
server/client-ssl.bauland42.com.crt: OK客户端证书(最终)
生成客户端证书与创建服务器证书非常相似。 最好的选择是,如果用户创建了客户端的CSR,则服务器将看不到用户的私钥。 服务器将只签署CSR并将证书返回给用户。 请注意,我们正在使用序列号2表示该证书。
openssl genrsa -out client/heiko.key 2048
openssl req -new -key client/heiko.key -out client/heiko.csr
openssl x509 -req -days 365 -sha256 -in client/heiko.csr -CA ca/ca.crt -CAkey ca/ca.key -set_serial 2 -out client/heiko.crt配置NGINX
我正在使用NGINX进行此演示,并且从Mozilla获得了现代且安全的SSL配置。 在HTTP(端口80)配置中,我将/ admin重定向到HTTPS版本。 对于SSL服务器,我将打开ssl_verify_client并通过ssl_client_certificate发送根CA证书。 您可以在此处找到本文的完整配置和其他资源 。
这是两个重要部分:
server {
listen 80;
...
location /admin {
rewrite ^ https://$host$request_uri? permanent;
}
...
}
server {
listen 443 ssl;
...
ssl_certificate /etc/nginx/certs/server/client-ssl.bauland42.com.crt;
ssl_certificate_key /etc/nginx/certs/server/client-ssl.bauland42.com.key;
ssl_client_certificate /etc/nginx/certs/ca/ca.crt;
ssl_verify_client on;
...
}在浏览器中安装CA
为了通过浏览器连接到管理面板,我们可以在进入管理面板时忽略浏览器警告。 但这并不安全,因此我们必须在系统范围内或仅在浏览器中本地安装CA证书。
我将在Firefox中安装它,因为这是最简单的。 使用scp将CA证书安全地复制到您的计算机:
scp user@IP:/etc/nginx/certs/ca/ca.crt .然后通过Preferences > Advanced > Certificates > View Certificates > Authorities > Import …将其导入Firefox。 我只在“ 此证书可以识别网站 ”复选框中打勾。 现在,在浏览器中重新加载网站,您将看到预期的错误: 400错误的请求,未发送必需的SSL证书 。 如果遇到其他错误,请重新启动Firefox。
安装客户端证书
要安装客户端证书,我们需要一个PKCS#12文件,该文件同时存储证书和客户端的私钥。 您可以创建该文件,或者用户可以向她发送CSR,而不是为她创建私钥。
openssl pkcs12 -export -clcerts -in client/heiko.crt -inkey client/heiko.key -out client/heiko.p12按照提示完成以下步骤:
- 输入导出密码,导入文件时也将需要该密码。
- 使用
scp安全复制文件
user@IP:/etc/nginx/certs/client/heiko.p12 .scp到您的计算机。
user@IP:/etc/nginx/certs/client/heiko.p12 . - 在“偏好设置”>“高级”>“证书”>“查看证书”>“您的证书”中将其导入Firefox。
- 重新启动浏览器。
- 在“证书”选项卡上是“ 服务器请求我的个人证书时”选项。 我选择每次询问我 。
- 在出现的消息框中,选择一个客户端证书。 您可以选择记住本次会议的决定。
在Firefox中选择一个客户端证书。
管理面板
如果您现在转到管理面板,则希望会看到一个客户端证书消息框和其后的管理员登录页面。
您可能需要进行健全性检查,然后在其他浏览器中打开页面。 您将看到“无效的证书颁发机构”警告,但是现在您将转到不安全的站点,仅用于测试。
NGINX将返回“ 400错误请求,未发送必需的SSL证书”错误,因为我们将ssl_verify_client设置ssl_verify_client on。 如果您不信任浏览器,则可以使用curl --insecure尝试相同操作,以忽略证书警告: curl --insecure https://client-ssl.bauland42.com/admin/ 。
授予和撤销访问
将证书发送给同事时,请确保对电子邮件进行加密。 在同一分钟内,在日历中设置一个提醒,以在证书过期至少一周之前更新证书。 它们通常在最坏的时刻过期。
每当颁发证书时,例如,如果有人离开公司,您还必须考虑如何吊销证书。 有证书吊销列表(CRL)和用于正式吊销证书的在线证书状态协议 。
但是,我认为这里的设置过于严格,需要一些持续的维护。 无论如何,可能只有极少数人可以访问管理面板。 因此,我认为我们可以从Rails的客户端证书中将通用名称(CN)列入白名单。
因此,我们将客户证书的主题通过特殊的X-Client-Dn标头从nginx传递给上游服务器:
location @app {
proxy_set_header X-Client-Dn $ssl_client_s_dn;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}标头将如下所示:
/CN=Heiko Webers/emailAddress=42@bauland42.de在应用程序中,我们可以将通用名称列入白名单,如下所示:
raise unless request.headers['HTTP_X_CLIENT_DN'] =~ %r(\A\/CN=(.+)\/) && ['Heiko Webers'].include?($1)由于只有具有有效客户端证书的人员才能访问Rails应用程序,因此您不能仅发送标题字符串进行身份验证。
Firefox中的绿色图标
结论
为了对应用程序敏感区域进行双向TLS身份验证,您需要满足以下条件:
- 一个用于分隔SSL配置的子域(或新域)。
- Web服务器配置。 这是我使用的完整NGINX示例配置 ,并提示了如何在Apache中执行此操作。
- 您自己的证书颁发机构(CA)。
- 自签名的Web服务器和客户端证书。 两者都必须安装在浏览器中。
翻译自: https://www.javacodegeeks.com/2016/03/set-mutual-tls-authentication.html