Rails (Ruby) で Slack からのリクエストを検証するコードを置いておくよ ^o^
こんにちは!ラブグラフインターンの arawi です。
最近 Slack から Rails アプリのリソース操作をするのにハマっています。
Slack からのリクエストを検証する処理は意外とシンプルなので、コードを置いておきます。
その前に!会社紹介
株式会社ラブグラフでは家族写真・七五三・カップルなどの全国出張撮影を展開しています。
開発チームは Ruby on Rails を中心に Web サイトや管理画面を自社で開発しています。
👇️👇️公式サイトをチェック!👇️👇️
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 から送られたものかを検証しています。
詳細については以下のドキュメントを読むとわかります。
でも・・・エイゴキライ!! な人が多いと思いますので(自分も)、解説を残しておきます!
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