Rails (Ruby) で Slack からのリクエストを検証するコードを置いておくよ ^o^

2024/10/31に公開

こんにちは!ラブグラフインターンの arawi です。
最近 Slack から Rails アプリのリソース操作をするのにハマっています。
Slack からのリクエストを検証する処理は意外とシンプルなので、コードを置いておきます。

その前に!会社紹介

株式会社ラブグラフでは家族写真・七五三・カップルなどの全国出張撮影を展開しています。
開発チームは Ruby on Rails を中心に Web サイトや管理画面を自社で開発しています。

👇️👇️公式サイトをチェック!👇️👇️

https://lovegraph.me/

TL;DR

これが Slack からのリクエスト検証コードです!

module Slack
  class Verifier
    # @param [ActionDispatch::Request] request 検証するHTTPリクエスト
    # @return [Boolean] 成功した場合は true を、失敗した場合は false を返します
    def self.call(request)
      slack_signature = request.headers['X-Slack-Signature']
      slack_timestamp = request.headers['X-Slack-Request-Timestamp']

      time_diff = (Time.now.to_i - slack_timestamp.to_i).abs
      return false if time_diff > 60 * 5

      sig_base_string = "v0:#{slack_timestamp}:#{request.body.read}"
      signature = OpenSSL::HMAC.hexdigest('SHA256', ENV['SLACK_SIGNING_SECRET'], sig_base_string)
      computed_signature = "v0=#{signature}"

      computed_signature == slack_signature
    end
  end
end

何をしてるのか

リクエストが本当に想定する Slack App から送られたものかを検証しています。
詳細については以下のドキュメントを読むとわかります。

https://api.slack.com/authentication/verifying-requests-from-slack

でも・・・エイゴキライ!! な人が多いと思いますので(自分も)、解説を残しておきます!

1. リクエストからサインとタイムスタンプを取得

リクエストヘッダから取ってくるだけです。

slack_signature = request.headers['X-Slack-Signature']
slack_timestamp = request.headers['X-Slack-Request-Timestamp']

2. タイムスタンプのチェック

ドキュメントに推奨されている通り、5分以上前のリクエストだったら拒否します。

time_diff = (Time.now.to_i - slack_timestamp.to_i).abs
return false if time_diff > 60 * 5

3. Slack App の Signing Secret を使ってサインを計算し、リクエストのものと比較

ここが大本命。タイムスタンプとリクエストボディをくっつけて SHA256 でハッシュ化し、リクエストに含まれるサインと比較します。

sig_base_string = "v0:#{slack_timestamp}:#{request.body.read}"
signature = OpenSSL::HMAC.hexdigest('SHA256', ENV['SLACK_SIGNING_SECRET'], sig_base_string)
computed_signature = "v0=#{signature}"

computed_signature == slack_signature # 戻り値

SLACK_SIGNING_SECRET は Slack App の管理画面に書かれているやつで、ここでは環境変数に保存しています。

以上!シンプルですね!
これで安心!Slack 怖くない!

おわりに

一度作ってしまえば簡単です。
環境変数さえ設定すればコピペでも動くと思いますので、ぜひご活用ください😃

【インターン募集!】
ラブグラフでは学生インターンを募集中⚡⚡
Ruby on Rails を中心にたくさんの開発経験を積むことができます。
僕も Web 開発未経験でしたが、今では DB 設計から UI 実装まで幅広くできるようになりました!

学生のみなさん、ぜひご応募ください!

ラブグラフのエンジニアブログ

Discussion