Skip to content

Commit 74c8f3e

Browse files
feat(security): add manual Slack request signature verification
1 parent 62de3df commit 74c8f3e

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

functions/slack/index.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
// [START functions_slack_setup]
1818
const functions = require('@google-cloud/functions-framework');
1919
const google = require('@googleapis/kgsearch');
20-
const {verifyRequestSignature} = require('@slack/events-api');
20+
const crypto = require('crypto')
2121

2222
// Get a reference to the Knowledge Graph Search component
2323
const kgsearch = google.kgsearch('v1');
@@ -93,12 +93,30 @@ const formatSlackMessage = (query, response) => {
9393
* @param {string} req.rawBody Raw body of webhook request to check signature against.
9494
*/
9595
const verifyWebhook = req => {
96-
const signature = {
97-
signingSecret: process.env.SLACK_SECRET,
98-
requestSignature: req.headers['x-slack-signature'],
99-
requestTimestamp: req.headers['x-slack-request-timestamp'],
100-
body: req.rawBody,
101-
};
96+
const slackSigningSecret = process.env.SLACK_SECRET;
97+
const requestSignature = req.headers['x-slack-signature'];
98+
const requestTimestamp = req.headers['x-slack-request-timestamp'];
99+
100+
if (!requestSignature || !requestTimestamp) {
101+
throw new Error('Missing slack signature or timestamp headers');
102+
}
103+
104+
// Prevent repeat seizures (5 minutes tolerance)
105+
const fiveMinutesAgo = Math.floor(Date.now() / 1000) - 300;
106+
if (parseInt(requestTime, 10) < fiveMinutesAgo) {
107+
throw new Error('Requested slack timestamp is too old');
108+
}
109+
110+
const basestring = `v0:${requestTimestamp}:${req.rawBody}`;
111+
const hmac = crypto.createHmac('sha256', slackSigningSecret);
112+
hmac.update(basestring, 'utf-8');
113+
const digest = `v0=${hmac.digest('hex')}`;
114+
115+
if (!crypto.timingSafeEqual(Buffer.from(digest, 'utf-8'), Buffer.from(requestSignature, 'utf8'))) {
116+
const error = new Error('slack invalid signature');
117+
error.code = 401;
118+
throw error;
119+
}
102120

103121
// This method throws an exception if an incoming request is invalid.
104122
verifyRequestSignature(signature);

0 commit comments

Comments
 (0)