Sails req.secure 详解:判断 HTTPS/WSS 安全连接及反向代理场景下的正确姿势
2026/9/20 17:19:39 网站建设 项目流程
  • 后端

【免费下载链接】sails

Realtime MVC Framework for Node.js

项目地址:https://gitcode.com/gh_mirrors/sa/sails
点击查看免费下载

导读

req.secure是 Sails 在请求对象(req)上暴露的一个布尔型便捷属性,用于判断当前请求是否通过安全连接(https://wss://)发送。它常用于控制器、策略(policies)或自定义中间件中做协议级别的分支逻辑——例如强制 HTTPS、仅在加密通道下放行敏感接口、或为sails.config.session.cookie.secure提供运行时依据。读完本文,你将掌握req.secure的判定原理、它与req.protocol/trust proxy的关系,以及在生产环境(尤其存在反向代理或负载均衡器)下如何正确配置,避免安全判断失效。

一、属性定义与基本用法

根据官方参考文档 req.secure 的定义:

Indicates whether or not the request was sent over a secure TLS connection (i.e.https://orwss://).

即:req.secure指示请求是否经由安全 TLS 连接发送——对应https://(HTTP over TLS)或wss://(WebSocket over TLS)协议。它属于req对象的只读属性(在文档元数据中被标记为pageType: property),而非方法,因此用法是直接读取:

req.secure;

典型返回值与语义:

请求类型协议req.secure
普通 HTTP 请求http://false
加密 HTTP 请求https://true
加密 WebSocket 请求wss://true
未加密 WebSocket 请求ws://false

二、判定原理:从连接加密状态到req.secure

req.secure并非 Sails 独立发明的新概念,而是 Sails 底层的 Express 中间件/路由层为请求对象注入的标准属性。从实现上看,它的取值本质上等价于对请求协议req.protocol是否为https的简写判断:

  • 当 Node.js HTTP 服务器以 TLS(HTTPS)模式运行时,底层req.connection.encrypted为真,Express 据此推导出req.protocol === 'https'
  • 当请求来自加密 WebSocket 连接(wss://,由 Sails 的 socket 层承载)时,同样被视为安全连接,req.secure返回true
  • 其余情况(http://ws://)返回false

在 Sails 请求管道中,协议信息被多处消费。例如 lib/hooks/request/metadata.js 中的_mixinServerMetadata()会依据req.protocol推导默认端口并构造req.baseUrl

// Determine host port var defaultPort; if (req.protocol === 'https' || req.protocol === 'wss') { defaultPort = 443; } else { defaultPort = 80; } var hostPort = parseInt(host.split(/:/)[1], 10) || defaultPort; req.port = hostPort; // Determine appropriate baseUrl req.baseUrl = req.protocol + '://' + host;

可以看到,安全协议(https/wss)对应的默认端口是 443,非安全协议(http/ws)对应 80;同时req.baseUrl也会带上协议前缀。这与req.secure的判定逻辑同源——都是基于req.protocol是否属于加密协议。因此理解req.protocolreq.secure的联动关系,是正确使用后者的前提。可参考同目录下的 req.protocol 文档做对照阅读。

另外,在 lib/hooks/request/index.js 中,Sails 只为符合协议条件的请求注入 HTTP 相关语法糖:

// Only apply HTTP-focused middleware if it makes sense // (i.e. if this is an HTTP request) if (req.protocol === 'http' || req.protocol === 'https') { _mixinReqQualifiers(req, res); }

这说明req.protocol(以及它衍生出的req.secure)是 Sails 路由中间件区分"真正的 HTTP 请求"与虚拟请求、socket 请求的重要依据之一。

三、实战用法:在控制器与策略中判断安全连接

3.1 在控制器/动作中强制 HTTPS

最常见的场景是在动作(actions)或控制器方法中,对敏感操作强制要求安全连接:

// api/controllers/account/change-password.js module.exports = { friendlyName: 'Change password', description: 'Update the password for the logged-in user.', exits: { badRequest: { responseType: 'badRequest' }, }, fn: async function (changePasswordInputs) { if (!this.req.secure) { throw 'badRequest'; // 或执行 res.redirect('https://' + ...) } // ... 执行密码修改逻辑 return { success: true }; }, };

3.2 在策略(policies)中统一拦截明文请求

更优雅的做法是把协议检查下沉到 策略层,对所有挂载该策略的路由统一生效:

// api/policies/require-https.js module.exports = function requireHttps(req, res, next) { if (!req.secure) { return res.redirect('https://' + req.get('Host') + req.url); } return next(); };
// config/policies.js module.exports = { '*': false, 'checkout/*': 'require-https', };

这种方式无需在每个动作里重复编写判断,且便于统一调整策略。注意:req.get('Host')取到的是 Host 头中的主机名(不含协议),拼接时需按实际情况处理端口。

四、关键陷阱:反向代理 / 负载均衡器下的trust proxy配置

4.1 问题根源

当应用部署在 Nginx、HAProxy、AWS ELB 等反向代理之后时,Node.js 服务器实际收到的连接来自代理(通常是本机明文 HTTP),此时:

  • 服务器看到的底层连接未加密 →req.protocol会被推导为httpreq.secure === false
  • 真实的客户端协议信息(https)由代理通过X-Forwarded-Proto请求头传递给后端;
  • 若不信任该请求头,Sails/Express 会无视它,导致req.secure恒为false,进而引发强制跳转死循环、安全策略误判等问题。

这正是 lib/hooks/request/metadata.js 中注释所强调的:

We trust req.protocol to be set by Express when "trust proxy" is enabled.

也就是说:只有当trust proxy启用时,Express 才会参考X-Forwarded-Proto等头来推导协议,Sails 才会据此得到正确的req.secure

4.2 Sails 中的配置入口

Sails 的 HTTP 钩子在 lib/hooks/http/index.js 中声明了默认值并对非法取值做了校验:

// (this is passed in to Express as the "trust proxy" setting) trustProxy: false,

校验逻辑要求该值不能是0、空字符串、nullNaN,并在错误信息中提示:如果应用直接面向公网,应保持trustProxy: false

随后,在 lib/hooks/http/initialize.js 中,该配置被真正写入 Express 应用:

// Set Express "trust proxy" if appropriate. if (sails.config.http.trustProxy) { expressApp.set('trust proxy', sails.config.http.trustProxy); }

因此,若你的应用部署在可信的反向代理之后,应在 config/http.js 中显式开启:

// config/http.js module.exports.http = { trustProxy: true, // 信任反向代理传递的 X-Forwarded-* 头 middleware: { // ... 其他中间件配置 }, };

开启后,Express 会依据X-Forwarded-Proto推导req.protocolreq.secure随即返回正确的true

4.3 联动:安全 Cookie 与req.secure的配合

req.secure还与 会话(session) 的安全 Cookie 配置紧密相关。在 lib/hooks/session/index.js 中,Sails 会对sails.config.session.cookie.secure做严格的类型校验与提醒:

  • cookie.secure被指定但不是布尔值,直接抛出异常(必须是truefalse);
  • 若应用使用 HTTPS 且依赖反向代理,Sails 会提示你同时把sails.config.http.trustProxy设为true,否则 Express 无法获知真实的加密协议,req.secure可能为false,导致安全 Cookie 无法按预期工作;
  • cookie.secure已设为true,Sails 会提示该 Cookie 只会在https://(即req.secure === true)连接上被发送。

典型配置:

// config/session.js module.exports.session = { cookie: { secure: true, // 仅通过 HTTPS 发送会话 Cookie }, };

五、测试验证:req.protocolreq.secure的行为证据

Sails 仓库的单元测试 test/hooks/request/req.metadata.test.js 直接验证了基于req.protocol的协议推导行为。测试先构造req.protocol = 'https'(注释明确写着"we assume Express got this right",即把协议判定视为 Express 层已正确处理的前提),然后断言派生出的端口与 baseUrl:

it('should handle a simple HTTPS case with X-Forwarded-Host', function() { this.req.protocol = 'https'; // we assume Express got this right this.req.host = 'server.local'; this.req.headers.Host = 'server.local'; this.req.headers['X-Forwarded-Host'] = 'example.org'; mixinMetadata(this.req); assert.equal(this.req.port, 443); // https 默认端口 443 assert.equal(this.req.baseUrl, 'https://example.org'); // baseUrl 带 https 前缀 });

其中还覆盖了X-Forwarded-Host缺失、多值('example.org, server1.local',取第一项)、非标准端口、反向代理携带端口等边界情形,并从 lib/hooks/request/metadata.js 的trustProxy读取逻辑可见:只有trustProxy为真时,X-Forwarded-Host才会被采纳。这一测试佐证了req.secure体系的完整链路:底层 TLS 状态 /X-Forwarded-Protoreq.protocolreq.securereq.portreq.baseUrl

六、使用注意事项小结

  1. req.secure是派生属性而非原始信息:它的正确性取决于 Express 推导req.protocol时掌握的信息;直接面向公网时通常准确,处于代理之后时必须开启sails.config.http.trustProxy
  2. 不要手动解析X-Forwarded-Proto代替它:解析代理头存在被伪造的风险,应由trust proxy统一管理信任边界;若使用trustProxy: true的宽松信任策略,请确保只有可信代理能直连你的应用。
  3. WebSocket 场景同样适用wss://连接下req.secure同样为true,可在 socket 相关的动作 中复用协议判断逻辑。
  4. 与安全 Cookie 联动:启用cookie.secure时,务必确认部署链路中req.secure的真实取值,避免安全 Cookie 在代理环境下"永远发不出去"或"明文传输"。

相关参考

  • 属性定义:req.secure
  • 协议对照:req.protocol
  • 服务端元数据注入实现:lib/hooks/request/metadata.js
  • HTTP 钩子与trustProxy配置:lib/hooks/http/index.js、lib/hooks/http/initialize.js、sails.config.http
  • 会话安全 Cookie 校验与提示:lib/hooks/session/index.js、sails.config.session
  • 相关测试用例:test/hooks/request/req.metadata.test.js
  • 后端

【免费下载链接】sails

Realtime MVC Framework for Node.js

项目地址:https://gitcode.com/gh_mirrors/sa/sails
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询