如何在AWS EB部署的Node.js服务器验证Hasura事件与动作请求来源
验证Hasura请求到Node.js端点的方法
要确保你的Node.js端点只接收来自Hasura的请求,主要有两种可靠的实现方式,下面分别给出具体方案和authCheckThisCameFromMyHasura方法的代码:
方案1:使用预共享API密钥(简单易实现)
这种方式适合快速搭建验证逻辑,核心是在Hasura的请求中添加自定义头部,Node.js端校验头部值是否匹配预设的密钥。
步骤:
在Hasura中配置请求头
- 无论是事件触发器还是自定义动作,在Hasura的配置里添加一个自定义请求头(比如
X-Hasura-Secret),值设为一个强随机字符串(比如32位UUID)。
- 无论是事件触发器还是自定义动作,在Hasura的配置里添加一个自定义请求头(比如
在AWS EB中设置环境变量
- 登录AWS Elastic Beanstalk控制台,找到你的应用环境,进入「配置」->「软件」,在「环境属性」里添加
HASURA_SECRET,值设为和Hasura中一致的密钥。
- 登录AWS Elastic Beanstalk控制台,找到你的应用环境,进入「配置」->「软件」,在「环境属性」里添加
实现验证方法
const express = require('express'); const app = express(); // 解析JSON格式的请求体 app.use(express.json()); // 验证请求是否来自Hasura的方法 function authCheckThisCameFromMyHasura(req) { // 从请求头获取传入的密钥 const incomingSecret = req.headers['x-hasura-secret']; // 从环境变量读取预设的合法密钥 const validSecret = process.env.HASURA_SECRET; // 校验:密钥存在且完全匹配 return incomingSecret && validSecret && incomingSecret === validSecret; } app.post('/some-event-or-action', (req, res) => { if(authCheckThisCameFromMyHasura(req)){ // 执行你的业务逻辑 res.status(200).json({ success: true }); } else { // 验证失败,返回403无权访问 res.status(403).json({ error: 'Unauthorized' }); } }); app.listen(process.env.PORT || 3000, () => { console.log('Server running'); });
方案2:使用Hasura请求签名(更安全)
Hasura支持用HMAC签名请求,签名基于请求体和密钥生成,密钥不会在请求中传输,能有效防止密钥泄露风险,安全性更高。
步骤:
在Hasura中配置签名密钥
- 在Hasura控制台的「Settings」->「API」->「Webhook/Action Signature」里,设置一个强随机字符串作为签名密钥,并启用签名功能。
在AWS EB中设置环境变量
- 添加
HASURA_SIGNATURE_SECRET环境变量,值设为Hasura中配置的签名密钥。
- 添加
实现验证方法
const express = require('express'); const crypto = require('crypto'); const app = express(); // 先获取原始请求体Buffer,不能提前解析JSON(签名基于原始内容生成) app.use(express.raw({ type: 'application/json' })); function authCheckThisCameFromMyHasura(req) { const signatureHeader = req.headers['x-hasura-signature']; const secret = process.env.HASURA_SIGNATURE_SECRET; if (!signatureHeader || !secret) { return false; } // Hasura签名格式为sha256=<哈希值>,拆分出哈希部分 const [algorithm, incomingHash] = signatureHeader.split('='); if (algorithm !== 'sha256') { return false; } // 用密钥和原始请求体生成HMAC哈希 const hmac = crypto.createHmac('sha256', secret); const computedHash = hmac.update(req.body).digest('hex'); // 用timingSafeEqual防止时序攻击,比较哈希值是否一致 return crypto.timingSafeEqual(Buffer.from(incomingHash), Buffer.from(computedHash)); } app.post('/some-event-or-action', (req, res) => { if(authCheckThisCameFromMyHasura(req)){ // 手动将原始请求体解析为JSON const body = JSON.parse(req.body); // 执行业务逻辑 res.status(200).json({ success: true }); } else { res.status(403).json({ error: 'Unauthorized' }); } }); app.listen(process.env.PORT || 3000, () => { console.log('Server running'); });
补充说明
- 环境变量也可以通过EB的
.ebextensions配置文件批量设置,比如创建config/01-environment-variables.config:option_settings: - namespace: aws:elasticbeanstalk:application:environment option_name: HASURA_SECRET value: your-secret-here - namespace: aws:elasticbeanstalk:application:environment option_name: HASURA_SIGNATURE_SECRET value: your-signature-secret-here - 若使用Hasura Cloud,可结合IP白名单进一步限制请求来源,但需注意Hasura Cloud的出口IP可能变动,需要定期更新白名单。
内容的提问来源于stack exchange,提问作者AndyW
相关产品推荐
相关产品推荐

