我在facebook messenger平台上开发聊天机器人。我查看了Facebook文档,无法找到如何保护webhook
免受随机通话的影响。
例如,如果用户可以使用我的机器人购买东西,那么知道某人的userId的攻击者可以通过拨打我的webhook来开始下载未经授权的订单。
我有几个关于如何保护这个的想法。
1)将我的api白名单只用于来自facebook的电话 2)创造一些东西 就像带回发电话的CSRF令牌一样。
有什么想法吗?
答案 0 :(得分:6)
Facebook当然已经实施了一种机制,您可以通过该机制检查对您的回调网址发出的请求是否真实(其他一切都只是疏忽) - 请参阅https://developers.facebook.com/docs/graph-api/webhooks#receiveupdates:
HTTP请求将包含
X-Hub-Signature
标头,其中包含请求负载的SHA1签名,使用app secret作为密钥,并以sha1=
为前缀。您的回调端点可以验证此签名以验证有效负载的完整性和来源请注意,计算是在有效负载的转义的unicode 版本上进行的,并使用小写十六进制数字。如果您只是根据解码的字节进行计算,最终会得到不同的签名。例如,字符串
äöå
应转义为\u00e4\u00f6\u00e5
。
答案 1 :(得分:0)
除了CBroe的答案外,下面的代码片段还表示将签名验证实现为NestJS保护。
// src/common/guards/signature-verification.guard.ts
@Injectable()
export class SignatureVerificationGuard implements CanActivate {
constructor(private readonly configService: ConfigService) {}
canActivate(context: ExecutionContext): boolean {
const {
rawBody,
headers: { 'x-hub-signature': signature },
} = context.switchToHttp().getRequest();
const { sha1 } = parse(signature);
if (!sha1) return false;
const appSecret = this.configService.get('MESSENGER_APP_SECRET');
const digest = createHmac('sha1', appSecret).update(rawBody).digest('hex');
const hashBufferFromBody = Buffer.from(`sha1=${digest}`, 'utf-8');
const bufferFromSignature = Buffer.from(signature, 'utf-8');
if (hashBufferFromBody.length !== bufferFromSignature.length)
return false;
return timingSafeEqual(hashBufferFromBody, bufferFromSignature);
}
}
// src/modules/webhook/webhook.controller.ts
@UseGuards(SignatureVerificationGuard)
@Post()
@HttpCode(HttpStatus.OK)
handleWebhook(@Body() data) {
// ...
}