Edited at

Slackのbot用Webサーバーの不正利用を防止する

Slackでbotを作成するには、Slackからのメッセージを受け取れるようにするため、インターネット上にwebサーバーを公開する必要があります。

URLを特定されないかぎりは、勝手に他者に利用されるようなことは基本的には無いはずですが、万が一にも勝手にbotの機能を使われることがないように対策する必要があります。

公式ドキュメントを見た限りでは、Slack側のIPが公開されていないようなのでIP制限で不正アクセスを防止する方法は無いようです。

以前はVerification Tokenという機能で正当なリクエストかどうかをチェックする機能がありましたが、今は非推奨になったようです。 ( https://api.slack.com/docs/token-types#verification )

代わりに以下のページにて、SlackからのHTTPリクエストが正当なものであることを検証するための機能が紹介されています。

ざっくりと仕組みを説明すると以下が成立すれば正当なリクエストとみなすというものです。



  • 利用する情報


    • SigningSecret値 (BotのSlackAppの設定画面で取得できる秘密の文字列)

    • SlackからのHTTPリクエストにつけられたX-Slack-Request-Timestamp HTTPヘッダーの値

    • SlackからのHTTPリクエストにつけられたX-Slack-Signature HTTPヘッダーの値




  • 以下の両方の条件が成立すること



    • X-Slack-Request-Timestampの値の時刻が現在時刻より一定時間(5分とか)以内であること

    • 以下が真になること



  signature = "v0=" + HMAC-SHA256ハッシュ化(

"v0:" + `X-Slack-Request-Timestamp`の値 + ":" + リクエストのボディ,
SiginingSecret値
)

// タイミング攻撃を防止する等号判定をすること。pythonなら `hmac.compare()`をつかう
signature == `X-Slack-Signature`の値

上記は処理のイメージを掴むための説明ですので、実際の実装方法は前述の公式文書を参照してください。

この検証方法は、HTTPリクエストの情報だけで行うことができるので、Botサーバーそのものでなくても、そのサーバーの前段のApacheなどのProxyサーバーで検証だけを行うようにすることもできそうです。

そこで、動作保証なしですが、nginx + luaを使った検証実装を以下で作ってみました。

https://gist.github.com/namutaka/861ec6b55ec9f9c22a95ff5584e463e8

会社などでBotを活用する場合は、上記をBotゲートウェイとして検証だけを集中的に行うようにすると、安心して誰でもBotを手軽に実装できる環境が作れるかもしれません。

なお、Signing Secretの値は外部に漏れてしまわないように管理する必要があるのは当然ですが、会社において社員や退職者が自宅からアクセスしたりすることもできてしまうので、定期的に再生成して入れ替えた方がいいかもしれません。

関連記事: