Skip to content

task: make the hmac auth plugin even more flexible #51

Closed
@GrantBirki

Description

@GrantBirki

Right now, the lib/hooks/plugins/auth/hmac.rb HMAC auth plugin can support a wide range of providers, but it could be even more flexible in the sense that it could support nearly every HMAC style auth provider. For example, right now it works with GitHub, shopify, etc providers quite well. However, other providers have different types of formats for how they provide the payload, timestamp, where it is in the headers, etc. Here is an example directly from tailscale's docs on how they do HMAC signing for webhooks:

You can verify whether an event was signed by the [webhook secret](https://tailscale.com/kb/1213/webhooks#webhook-secret) that was shared between you and Tailscale. Note this doesn't necessarily mean that an event was sent from Tailscale. Rather, it means an event was sent from an entity that has knowledge of the secret shared between you and Tailscale.

A event sent from Tailscale contains a Tailscale-Webhook-Signature header. The Tailscale-Webhook-Signature header includes a timestamp and a signature:


Tailscale-Webhook-Signature:t=1663781880,v1=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
The timestamp, prefixed by t=, is the epoch time in seconds when the event occurred. The signature, prefixed by v1=, is a hash-based message authentication code (HMAC) using SHA-256. The only supported scheme for the signature is v1.

Most modern programming languages provide libraries for computing and comparing HMACs. The following flow describes how to verify a signature.

Parse the event timestamp and signature from the Tailscale-Webhook-Signature header.

Using the , character as the separator, split the Tailscale-Webhook-Signature data into a list of elements. Then, using the = character, split each element to get two key-value pairs. The first key is t, with the event timestamp as its value. The second key is v1, with the event signature as its value.

Compare the event timestamp (the value for t) with the current time. For example, if your verification process acts on events as soon as they are received, and if the event time is more than 5 minutes prior to the current time, you might consider the event as a replay attack.

Create a string, string_to_sign, to sign by concatenating:

The timestamp (the value of t) represented as a string.
The . character.
The decoded event request body. Note this is in the request itself, not in the Tailscale-Webhook-Signature header. The request body contains the encoded [events payload](https://tailscale.com/kb/1213/webhooks#events-payload), you need to decode the request body for signing purposes.
Compute the signature of string_to_sign.

Create an HMAC with the SHA256 hash function. Use your webhook secret for the signing key, and use string_to_sign as the message to sign.

Use an HMAC compare function to compare the signature in the Tailscale-Webhook-Signature header (the value of v1) with the signature you created in the previous step. If they are not identical, that indicates the event's payload was not signed by your webhook's secret, and the event should not be considered an event sent from Tailscale.

As you can see, the existing HMAC auth library that this project provides is quite robust, but we should investigate ways to expose some of the internal HMAC components to make them more reusable for writing custom hmac style auth plugins or even make it so that our HMAC auth style core plugin is highly flexible and can support this tailscale provider and even more in the future.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions