- 后端
【免费下载链接】sails
Realtime MVC Framework for Node.js
导读
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.protocol与req.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会被推导为http→req.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、空字符串、null或NaN,并在错误信息中提示:如果应用直接面向公网,应保持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.protocol,req.secure随即返回正确的true。
4.3 联动:安全 Cookie 与req.secure的配合
req.secure还与 会话(session) 的安全 Cookie 配置紧密相关。在 lib/hooks/session/index.js 中,Sails 会对sails.config.session.cookie.secure做严格的类型校验与提醒:
- 若
cookie.secure被指定但不是布尔值,直接抛出异常(必须是true或false); - 若应用使用 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.protocol与req.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-Proto→req.protocol→req.secure、req.port、req.baseUrl。
六、使用注意事项小结
req.secure是派生属性而非原始信息:它的正确性取决于 Express 推导req.protocol时掌握的信息;直接面向公网时通常准确,处于代理之后时必须开启sails.config.http.trustProxy。- 不要手动解析
X-Forwarded-Proto代替它:解析代理头存在被伪造的风险,应由trust proxy统一管理信任边界;若使用trustProxy: true的宽松信任策略,请确保只有可信代理能直连你的应用。 - WebSocket 场景同样适用:
wss://连接下req.secure同样为true,可在 socket 相关的动作 中复用协议判断逻辑。 - 与安全 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
相关推荐
Sails `req.ip` 完全指南:获取请求客户端 IP 及反向代理场景下的正确配置
Sails req.ip 完全指南:获取请求客户端 IP 及反向代理场景下的正确配置 在 Sails(Realtime MVC Framework for No
后端Gulp 中的 Vinyl.isVinyl():判断 Vinyl 实例的正确姿势
Gulp 中的 Vinyl.isVinyl :判断 Vinyl 实例的正确姿势 Vinyl.isVinyl 是 vinyl https://link.gitco
构建工具CLIReflex Enterprise 认证部署到生产环境指南:HTTPS、回调 URL 与反向代理下的 OIDC 正确姿势
Reflex Enterprise 认证部署到生产环境指南:HTTPS、回调 URL 与反向代理下的 OIDC 正确姿势 reflex enterprise(v
后端前端Web框架
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考