如何验证Slack API请求



我有一个slack应用程序,它正在发送到一个用typescript编写的服务,该服务正在将消息转发到我的python脚本,我正在尝试验证请求。但是,由于某些原因,验证总是失败。打字脚本相关代码:

const rp = require('request-promise');
var qs = require('querystring')

export const handler = async (event: any, context: Context, callback: Callback): Promise<any> => {
const options = {
method: method,
uri: some_url,
body: qs.parse(event.body),
headers: {
signature: event.headers['X-Slack-Signature'],
timestamp: event.headers['X-Slack-Request-Timestamp']
},
json: true
};
return rp(options);

python代码(基于本文(:

def authenticate_message(self, request: Request) -> bool:
slack_signing_secret = bytes(SLACK_SIGNING_SECRET, 'utf-8')
slack_signature = request.headers['signature']
slack_timestamp = request.headers['timestamp']
request_body = json.loads(request.body)['payload']
basestring = f"v0:{slack_timestamp}:{request_body}".encode('utf-8')
my_signature = 'v0=' + hmac.new(slack_signing_secret, basestring, hashlib.sha256).hexdigest()
return hmac.compare_digest(my_signature, slack_signature))

我很确定问题出在我取尸体的方式上,但尝试了几种选择,仍然没有成功。

有什么想法吗?

谢谢,Nir。

我遇到了同样的问题。我的解决方案是分析负载,将"/"替换为%2F,将":"替换为%3A。Slack文档中没有明确说明,但如果你看到这个例子,它就是这样显示的:

'v0:1531420618:token=xyzz0WbapA4vBCDEFasx0q6G&team_id=T1DC2JH3J&team_domain=testteamnow&channel_id=G8PSS9T3V&channel_name=foobar&user_id=U2CERLKJA&user_name=roadrunner&command=%2Fwebhook-collect&text=&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT1DC2JH3J%2F397700885554%2F96rGlfmibIGlgcZRskXaIFfN&trigger_id=398738663015.47445629121.803a0bc887a14d10d2c447fce8b6703c'

您可以看到commandresponse_url已被解析。

我设法在Python中实现了这一点。我看到你在Typescript中问,但我希望这个python脚本有帮助:

@app.route('/slack-validation', methods=['GET', 'POST']) 
def slack_secutiry():
headers = request.headers
timestamp = request.headers['X-Slack-Request-Timestamp'] 
slack_payload = request.form
dict_slack = slack_payload.to_dict()
### This is the key that solved the issue for me, where urllib.parse.quote(val, safe='')] ###
payload= "&".join(['='.join([key, urllib.parse.quote(val, safe='')]) for key, val in dict_slack.items()])  
### compose the message:
sig_basestring = 'v0:' + timestamp + ':' + payload
sig_basestring = sig_basestring.encode('utf-8')
### secret
signing_secret = slack_signing_secret.encode('utf-8') # I had an env variable declared with slack_signing_secret

my_signature = 'v0=' + hmac.new(signing_secret, sig_basestring, hashlib.sha256).hexdigest()
print('my signature: ')
print(my_signature)

return '', 200

检查请求验证功能是如何在Bolt框架中实现的可能会很有用:

https://github.com/slackapi/bolt-python/blob/4e0709f0578080833f9aeab984a778be81a30178/slack_bolt/middleware/request_verification/request_verification.py

请注意,它是作为中间件实现的,在实例化应用程序时默认启用(请参见属性request_verification_enabled(。

如果你想手动验证请求,你可以检查这种行为和/或改变它:

app = App(
token=SLACK_BOT_TOKEN,
signing_secret=SLACK_SIGNING_SECRET,
request_verification_enabled=False
)

以下解决方案解决了slack 的签名秘密验证问题

#!/usr/bin/env python3
import hashlib
import hmac
import base64

def verify_slack_request(event: dict, slack_signing_secret: str) -> bool:
"""Verify slack requests.
Borrowed from https://janikarhunen.fi/verify-slack-requests-in-aws-lambda-and-python.html
- Removed optional args
- Checks isBase64Encoded
:param event: standard event handler
:param slack_signing_secret: slack secret for the slash command
:return: True if verification worked
"""
slack_signature = event['headers']['x-slack-signature']
slack_time = event['headers']['x-slack-request-timestamp']
body = event['body']
if event['isBase64Encoded']:
body = base64.b64decode(body).decode("utf-8")
""" Form the basestring as stated in the Slack API docs. We need to make a bytestring"""
base_string = f'v0:{slack_time}:{body}'.encode('utf-8')
""" Make the Signing Secret a bytestring too. """
slack_signing_secret = bytes(slack_signing_secret, 'utf-8')
""" Create a new HMAC 'signature', and return the string presentation."""
my_signature = 'v0=' + hmac.new(
slack_signing_secret, base_string, hashlib.sha256
).hexdigest()
''' Compare the the Slack provided signature to ours.
If they are equal, the request should be verified successfully.
Log the unsuccessful requests for further analysis
(along with another relevant info about the request).'''
result = hmac.compare_digest(my_signature, slack_signature)
if not result:
logger.error('Verification failed. my_signature: ')
logger.error(f'{my_signature} != {slack_signature}')
return result

if __name__ == '__main__':
# add correct params here
print(verify_slack_request({}, None))

借款来源:https://gist.github.com/nitrocode/288bb104893698011720d108e9841b1f

学分:https://gist.github.com/nitrocode

在这上面浪费了一个小时。。。Slack文档具有误导性。

他们说要使用原始请求体,但它是base64编码的,所以你需要先解码它。

请参阅下面的解决方案。

import hmac
import base64
signing_secret = bytes("{{SLACK_SIGNING_SECRET}}", "utf-8")
slack_timestamp = event["headers"]["x-slack-request-timestamp"]
# Slack docs are misleading here. We are told to use the raw request body,
# but actually needs to be cleaned from base64.
body = str(base64.b64decode(event["body"]), "UTF-8")
basestring = f"v0:{slack_timestamp}:{body}".encode("utf-8")
# Add the v0= to the front to form the full signature
signature = "v0=" + hmac.new( signing_secret, msg=basestring, digestmod=hashlib.sha256 ).hexdigest()
# Use hmac's compare_digest for increased security.
if hmac.compare_digest(event["headers"]["x-slack-signature"], signature):
...

最新更新