Node.js Express如何获取真实源主机名以防止伪造?
解决Express中获取真实源主机名的问题
核心问题原因
req.hostname直接读取HTTP请求头的Host字段,客户端可随意篡改该字段,因此无法直接用它获取真实主机名。针对多域名场景,推荐以下几种可靠方案:
方案1:通过反向代理传递真实主机信息
若应用部署在Nginx、Apache等反向代理后,这是最稳妥的方案:
- 配置反向代理,将原始请求的真实主机名通过自定义请求头传递给Express:
以Nginx为例,添加配置:proxy_set_header X-Real-Host $host; proxy_set_header X-Forwarded-Host $host; - 在Express中开启信任代理配置,确保能正确读取代理传递的头信息:
app.set('trust proxy', true); // 也可指定信任的代理IP范围,比如仅信任本地代理:app.set('trust proxy', ['127.0.0.1']) - 之后通过
req.get('X-Real-Host')或req.get('X-Forwarded-Host')即可获取真实主机名——代理层会传递原始请求的真实Host,客户端篡改的Host会被代理忽略。
方案2:端口-域名映射(无代理场景)
若应用直接暴露在公网,且每个域名绑定独立端口,可在应用内部维护端口与域名的映射表:
// 预先配置域名与端口的对应关系 const domainPortMap = { 'example.com': 3000, 'foo.com': 3001, 'bar.com': 3002 }; app.use((req, res, next) => { // 通过当前请求的本地端口反向查找对应域名 const realHostname = Object.keys(domainPortMap).find(domain => domainPortMap[domain] === req.socket.localPort); req.realHostname = realHostname; next(); });
该方案的前提是每个域名对应唯一端口,客户端无法修改请求的目标端口(除非直接访问其他端口,对应不同域名),因此能保证获取到真实主机名。
方案3:HTTPS证书验证(加密场景)
若应用启用了HTTPS,可利用TLS握手阶段的证书信息确认真实域名:
app.use((req, res, next) => { if (req.socket.encrypted) { // 获取当前连接的服务器证书 const serverCert = req.socket.getPeerCertificate(true); // 从证书的CN字段提取真实域名(前提是每个域名对应独立SSL证书) const realHostname = serverCert.subject.CN; req.realHostname = realHostname; } next(); });
客户端无法篡改TLS握手时使用的证书,因此该方式能确保获取到的域名是真实绑定的证书域名,安全性最高。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

