Slack “Slash Commands” can be a very useful tool to write a CLI to interact with other applications that you manage.
In short the contract works something like this; from within a slack channel that the commands are available you would type:
/my-command [text arguments]
Seems simple enough, however you need to implement a REST endpoint that Slack will invoke every time one of these commands is issued in a qualified channel by a user in your slack account. You can read more about this here: https://api.slack.com/slash-commands
I’m not going to go into the details about how to implement such a service but I am going to cover some ideas around security.
How Slack identifies each command request
So what happens when you get one of these POSTs from Slack with regards to the user/principal’s identity? You receive the following bits of information related to identity:
- A “signed secret” via “X-Slack-Signature” header OR shared secret “token” that identifies the request as coming from Slack, this is NOT a token unique to the user invoking the command, but simply identifying the “Slack service” based on a shared secret/signing secret and verification algorithm. (see here)
- The user’s identifier “user_id” and some other identifiers for the team, account and channel
- That’s about it
Beyond that there is nothing to really “authenticate” the actual user is actually who Slack says it is, other than the trust relationship you have with Slack and that Slack itself is properly authenticating the user sitting in front of their Slack client and its not someone else.
So depending on the sensitivity of what your “slash commands” can do, this will test your level of comfort with this relationship between your system and the Slack service. In my use case the “slash commands” I was creating could actually manipulate some state of the backend system (for example re-initialize a cluster, interrogate state, read system metrics, manage cluster nodes or mutate certain data attributes), so for me… security was very important.
I needed to be able to further verify that the user Slack said was the real user… was really that user! So how can this be tackled?
Securing slash commands with MFA and Sessions
First off, you have at least some baseline of security assuming your “slash command” source is originating from a Slack account where the users are authenticated by Slack or some other trust arrangement with your organization via something like SAML etc. Secondly you can validate this by checking the “signed secret”/”token” that is sent on each request to verify its coming from Slack and not another party. However in order to validate and identify the user invoking the “sensitive” slash command, (and bind them to ACLs on your backend) you could do the following:
#1: Require the user to initialize a valid session
Slack “slash commands” have no concept of a “session” but you could implement a contract for this that you implement on your backend as follows:
/my-command session -initialize -mfa [totp code]
Where the “[totp code]” is a six digit TOTP code (time based one time password) the user generates via an MFA app/device such as Google Authenticator. This code is unique and generated from the current time + a unique user specific MFA shared secret key that both the user and the backend application possess. When your backend receives this POST you can parse the “text” arguments and validate the passed MFA code against your own TOTP validation routine that is bound to a shared MFA secret bound to the “user_id” that slack sends in the POST. If this validates you then know that the user has access to this shared secret as well which gives you some additional assurance that they are who slack says they are.
After validation you can then generate a unique one-time session establishment token and send it to the user’s configured MFA target device (email or SMS/text etc). You have this relationship configured in your backend’s ACL system.
#2: Require the user to establish the session
At this point the user would receive the session establishment token via email or SMS, they then proceed to “establish” the session via a second command, such as:
/my-command session -establish [token] -mfa [totp code]
In this command they specify the session token received and secondly pass another new generated TOTP code from their MFA code generating app/device.
Once slack POSTs this command, the backend validates BOTH the session token as well as the latest TOTP code against their “user_id”. If both check out the user now has an established “session” with your backend bound to their identity and all the ACLs mapped to them in your system.
You should also think about other attributes of your “session”, such as maximum number of commands that can be issued per session, or session life, timeout etc. All of which would require re-establishment of a new session when met.
#3: User proceeds to issue actual sensitive commands
Now that the user has a established session on the backend, they can issue the sensitive operation over Slack, however they still need to always pass a new TOTP code.
/my-command sensitiveop -arg1 x -arg2 y -mfa [totp code]
In this scenario the backend would receive the POST for “sensitiveop” from Slack, validate the “user_id” has a valid session, and if so, secondly validate their passed TOTP code again, then 3rd ensure the “user_id” has the proper ACL to invoke “sensitiveop” and if all is legit, proceed with executing the “sensitiveop” on behalf of the user.
Arguably once a session is established you may want to make it optional to require further commands to continually pass the -mfa [totp code]. This is personal choice based on your security requirements.
The fact that the user has an pre-existing established session which already required a TOTP code to gain in the first place gives a decent level of assurance that subsequent POSTs from slack w/ that “user_id” are still that user. But if you really don’t trust that, you can continue to require additional TOTP codes on every subsequent sensitive command that is invoked. Session only? MFA TOTP code only? Or both?
Its up to you.
Usage in the real world
I’ve used the general model described above in a real world scenario for a Slack Slash Command implementation that worked similar to the below diagram. The diagram below shows the security mechanism described as well as a lot of other capabilities that give you some idea of the power you can achieve, and secure, with Slack slash commands. Its really quite a useful tool to enhance certain DevOps capabilities.
You just need to be careful with it and secure it!