如何验证Slack API请求?

时间:2020-10-13 18:38:07

标签: python typescript slack-api

我有一个松弛的应用程序,该应用程序正在发送到用打字稿编写的服务,该服务会将消息转发到我的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代码(基于此article):

  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))

我很确定问题是我采取身体的方式,但是尝试了几种选择,但仍然没有运气。

有什么想法吗?

谢谢, 尼尔。

1 个答案:

答案 0 :(得分:0)

我遇到了同样的问题。我的解决方案是解析有效负载以将 '/' 替换为 %2F,将 ':' 替换为 %3A。它在 Slack doc 中没有明确显示,但如果您看到示例,它就是这样显示的:

'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