3

我正在玩在 facebook Messenger 平台上开发一个聊天机器人。我浏览了 Facebook 文档,但找不到如何保护我webhook免受随机呼叫的影响。

例如,如果用户可以使用我的机器人购买东西,那么知道某人的 userId 的攻击者可以通过调用我的 webhook 开始下未经授权的订单。

我对如何保护它有几个想法。

  1. 将我的 API 列入白名单,只允许来自 Facebook 的调用。
  2. 使用回发调用创建类似 CSRF 令牌的东西。

有任何想法吗?

4

2 回答 2

9

Facebook 当然已经实现了一种机制,您可以通过该机制检查对回调 URL 的请求是否真实(其他一切都只是他们的疏忽)——请参阅https://developers.facebook.com/docs/graph-api /webhooks#receiveupdates

HTTP 请求将包含一个X-Hub-Signature标头,该标头包含请求有效负载的 SHA1 签名,使用应用程序密钥作为密钥,并以sha1=. 您的回调端点可以验证此签名以验证有效负载的完整性和来源

请注意,计算是根据有效载荷的转义 unicode版本进行的,使用小写十六进制数字。如果您只是针对解码的字节进行计算,您最终会得到不同的签名。例如,字符串äöå应该转义为\u00e4\u00f6\u00e5.

于 2016-04-14T11:35:31.457 回答
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) {
  // ...
}
于 2020-11-22T14:57:53.100 回答