0
0

More than 3 years have passed since last update.

Slack APIでリクエストを検証する。を実装してみる。

Last updated at Posted at 2020-02-13

やりたいこと

HTTPリクエストが、Slackからのリクエストなのか確認する
Slackからのリクエストを検証する

AWS周り

API Gatewayを使っていたのでHTTPヘッダを編集

POST->メソッドリクエスト->HTTPリクエストヘッダー
スクリーンショット 2020-02-13 12.41.19.png

POST->統合リクエスト->HTTPヘッダー

スクリーンショット 2020-02-13 13.08.57.png

サーバー側コード

flaskで書いてます。

app = Flask(__name__)
@app.route("/", methods=["POST"])
def root():

    slack_signing_secret = b'MY_SLACK_SIGNING_SECRET'
    request_body = request.stream.read().decode()
    timestamp = request.headers['X-Slack-Request-Timestamp']
    if absolute_value(int(time.time()) - int(timestamp)) > 60 * 5:
        #タイムスタンプが5分以上ずれていたら、それはDDoS攻撃の可能性が高いので無視する。
        return
    sig_basestring = 'v0:' + timestamp + ':' + request_body
    my_signature = 'v0=' + hmac.new(
            slack_signing_secret,
            sig_basestring.encode("utf-8"),
            hashlib.sha256
            ).hexdigest()
    slack_signature = request.headers['X-Slack-Signature']
    if hmac.compare_digest(my_signature, slack_signature):
        print("request is ok")
    else:
        print("bad request")

ライブラリにありました

python-slackclientに関数がありました。ありがたい。

from slack import WebClient
client = WebClient(slack_bot_token)

app = Flask(__name__)
@app.route("/", methods=["POST"])
def root():

    slack_signing_secret = "MY_SLACK_SIGNING_SECRET"
    request_body = request.stream.read().decode()
    timestamp = request.headers['X-Slack-Request-Timestamp']
    signature = request.headers["X-Slack-Signature"]
    if absolute_value(int(time.time()) - int(timestamp)) > 60 * 5:
        #タイムスタンプが5分以上ずれていたら、それはDDoS攻撃の可能性が高いので無視する。
        return

    valification_flag = client.validate_slack_signature(
            signing_secret=slack_signing_secret,
            data=request_body,
            timestamp=timestamp,
            signature=signature
            )

    if valification_flag:
        print("request is ok")
    else:
        print("bad request")

困ったこと

もともとflask.request.formでペイロードを取得していたのですが、
flask.request.streamを使うとbyteになってしまいます。

そして、どちらかを使うとrequestの中身は空になります。
なので、今回はbyte to jsonを以下のように書きました。

import urllib.parse
dict_data = json.loads(urllib.parse.unquote_plus(request_body).split("=",1)[1])

むりやり

追記(2020.3.31)

先の項目でparseunquoteには以下の二種類ある。

urllib.parse.unquote()
urllib.parse.unquote_plus()

今回はunquote_plus()を使わないといけなかったので修正した。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0