我目前使用客户端 SSL 身份验证来保护敏感内容。用户需要将我们使用 OpenSSL 生成的证书导入到他们的浏览器中。当用户访问网站时,如果他们的浏览器或操作系统的钥匙串中没有证书,我们会将他们重定向到自定义 403 页面。这是使用以下 Apache 配置实现的。
<VirtualHost *:443>
ServerName host.tld
ServerAlias www.host.tld
ServerAdmin [email protected]
DocumentRoot /var/www/path
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCertificateFile /etc/ssl/host/host.crt
SSLCertificateKeyFile /etc/ssl/host.key
SSLCACertificateFile /etc/ssl/cacert.pem
SSLVerifyClient optional
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
SSLVerifyDepth 10
# SSLCARevocationPath /etc/ssl/crl
SSLCARevocationFile /etc/ssl/ca.crl
SSLCARevocationCheck chain
RewriteEngine on
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{SSL:SSL_CLIENT_VERIFY} !=SUCCESS
RewriteRule .? - [F]
ErrorDocument 403 /403.html
</VirtualHost>
我想更进一步,引入一些条件,如果他们有证书,就加载特定的 DocumentRoot,如果他们没有客户端证书,就加载另一个 DocumentRoot。
总结:website.com
- 用户 A 使用客户端 SSL 访问,从 /var/www/has_ssl 提供 website.com
- 用户 B 无需客户端 SSL 即可访问,从 /var/www/no_ssl 提供 website.com
如果为空,我可以用来%{SSL:SSL_CLIENT_S_DN_CN} =""
重定向到路径,但我不确定如何根据证书的存在重写 DocumentRoot。
我已经为此苦苦挣扎了几天。任何帮助或指点都将不胜感激。
答案1
据我所知,您无法有条件地设置DocumentRoot
。但是,您可以使用 mod_rewrite 在内部重写请求,就像在未设置客户端 SSL 时返回 403 响应一样。
例如,如果您设置:
DocumentRoot /var/www
然后在内部重写所有请求以使其/var/www/has_ssl
成功或/var/www/no_ssl
失败。
RewriteEngine on
RewriteCond %{SSL:SSL_CLIENT_VERIFY} !=SUCCESS
RewriteRule ^ /no_ssl%{REQUEST_URI} [L]
RewriteCond %{SSL:SSL_CLIENT_VERIFY} =SUCCESS
RewriteRule ^ /has_ssl%{REQUEST_URI} [L]
为了防止直接访问/no_ssl
或/has_ssl
子目录,您可以实施外部重定向前上面的重写会从请求中删除子目录。例如:
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^/(no_ssl|has_ssl)(.*) /$1 [R=301,L]