Apache在请求到达HTTPS端口前实现URL过滤/白名单配置的方案咨询
Apache在请求到达HTTPS端口前实现URL过滤/白名单配置的方案咨询
首先得明确:单纯靠Apache本身没法实现你要的效果,为啥呢?因为HTTPS的握手流程是先协商SSL证书,等握手完成之后,Apache才会收到请求里的Host头(也就是子域名)。这时候如果没有对应子域名的虚拟主机配置,Apache已经把默认证书发出去了,浏览器自然会弹出SSL错误——这步流程Apache没法跳过,所以必须在它前面加一层能提前解析SNI(SSL握手时客户端发送的服务器名称指示)的工具来过滤请求。
下面给你两个靠谱的实现方案,都是我实际用过的:
方案一:用Nginx做前置反向代理
Nginx可以在SSL握手阶段解析SNI,直接拒绝不在白名单里的请求,连证书都不用发,浏览器就会显示“连接超时”。
步骤很简单:
- 先装Nginx:
sudo apt install nginx - 修改Apache的监听端口,把443改成8080(或者其他没被占用的端口),这样Apache就不再直接对外暴露HTTPS端口了
- 配置Nginx的
/etc/nginx/sites-available/default(或者新建一个配置文件):
# 处理所有无效子域名的请求,直接断开连接 server { listen 443 ssl; server_name _; # 随便整个无效证书就行,反正我们直接拒绝,不会用到它 ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem; ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key; return 444; # Nginx的特殊返回码,直接关闭连接,不发任何响应 } # 处理合法的app1子域名 server { listen 443 ssl; server_name app1.example.com; ssl_certificate /path/to/your/app1-cert.pem; ssl_certificate_key /path/to/your/app1-key.pem; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } # 处理合法的app2子域名 server { listen 443 ssl; server_name app2.example.com; ssl_certificate /path/to/your/app2-cert.pem; ssl_certificate_key /path/to/your/app2-key.pem; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
- 重启Nginx和Apache:
sudo systemctl restart nginx apache2
至于HTTP(80端口)的过滤,直接在Apache里配置就行:
<VirtualHost *:80> ServerName _ RewriteEngine On RewriteRule ^ - [R=444,L] # 直接关闭连接 </VirtualHost> <VirtualHost *:80> ServerName app1.example.com Redirect permanent / https://app1.example.com/ </VirtualHost> <VirtualHost *:80> ServerName app2.example.com Redirect permanent / https://app2.example.com/ </VirtualHost>
方案二:修正HAProxy的配置(你之前可能配错了)
HAProxy同样支持基于SNI的ACL过滤,之前没成功大概率是没用到正确的SNI匹配规则。给你一个可行的配置示例:
修改HAProxy的主配置文件(比如/etc/haproxy/haproxy.cfg):
frontend https-in bind *:443 ssl crt /path/to/your/certs/ # 这里放所有合法子域名的证书,HAProxy会自动根据SNI选择 # 定义白名单ACL,匹配合法的子域名 acl valid_subdomain req.ssl_sni -i app1.example.com app2.example.com # 不在白名单里的请求直接拒绝 tcp-request content reject unless valid_subdomain # 合法请求转发给Apache use_backend apache_backend if valid_subdomain backend apache_backend server apache_localhost 127.0.0.1:8080 check # Apache监听8080端口
然后重启HAProxy:sudo systemctl restart haproxy,同时记得把Apache的443端口改成8080。
为啥Apache本身不行?
再啰嗦一句:Apache的mod_ssl是先完成SSL握手(发送证书),再处理虚拟主机和Host头。也就是说,当Apache知道用户访问的是哪个子域名时,已经把默认证书发出去了,这时候再拒绝也晚了,浏览器已经拿到无效证书,必然弹出SSL错误。所以必须用前置工具在握手阶段就把无效请求拦下来。
备注:内容来源于stack exchange,提问作者root
相关产品推荐
相关产品推荐

