やりたいこと
HTTPリクエストが、Slackからのリクエストなのか確認する
Slackからのリクエストを検証する
AWS周り
API Gatewayを使っていたのでHTTPヘッダを編集
POST->メソッドリクエスト->HTTPリクエストヘッダー
POST->統合リクエスト->HTTPヘッダー
サーバー側コード
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)
先の項目でparse
のunquote
には以下の二種類ある。
urllib.parse.unquote()
urllib.parse.unquote_plus()
今回はunquote_plus()を使わないといけなかったので修正した。