我正在玩在 facebook Messenger 平台上开发一个聊天机器人。我浏览了 Facebook 文档,但找不到如何保护我webhook
免受随机呼叫的影响。
例如,如果用户可以使用我的机器人购买东西,那么知道某人的 userId 的攻击者可以通过调用我的 webhook 开始下未经授权的订单。
我对如何保护它有几个想法。
- 将我的 API 列入白名单,只允许来自 Facebook 的调用。
- 使用回发调用创建类似 CSRF 令牌的东西。
有任何想法吗?
我正在玩在 facebook Messenger 平台上开发一个聊天机器人。我浏览了 Facebook 文档,但找不到如何保护我webhook
免受随机呼叫的影响。
例如,如果用户可以使用我的机器人购买东西,那么知道某人的 userId 的攻击者可以通过调用我的 webhook 开始下未经授权的订单。
我对如何保护它有几个想法。
- 将我的 API 列入白名单,只允许来自 Facebook 的调用。
- 使用回发调用创建类似 CSRF 令牌的东西。
有任何想法吗?
Facebook 当然已经实现了一种机制,您可以通过该机制检查对回调 URL 的请求是否真实(其他一切都只是他们的疏忽)——请参阅https://developers.facebook.com/docs/graph-api /webhooks#receiveupdates:
HTTP 请求将包含一个
X-Hub-Signature
标头,该标头包含请求有效负载的 SHA1 签名,使用应用程序密钥作为密钥,并以sha1=
. 您的回调端点可以验证此签名以验证有效负载的完整性和来源请注意,计算是根据有效载荷的转义 unicode版本进行的,使用小写十六进制数字。如果您只是针对解码的字节进行计算,您最终会得到不同的签名。例如,字符串
äöå
应该转义为\u00e4\u00f6\u00e5
.
除了 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) {
// ...
}