5

I'm using Mandrill to send emails with PHP. I've registered a webhook so I can handle any hard bounces in my application as well as in Mandrill. The difficulty I'm having is generating the X-Mandrill-Signature header to authenticate the request.

Mandrill has documentation about how to do it here but I'm failing to get it right.

Here's the POST parameters sent to me from Mandrill:

mandrill_events: [{"type":"whitelist","action":"add","entry":{"email":"example.webhook@mandrillapp.com","detail":"example details","created_at":"2014-01-15 12:03:19"},"ts":1452869880},{"type":"whitelist","action":"remove","entry":{"email":"example.webhook@mandrillapp.com","detail":"example details","created_at":"2014-01-15 12:03:19"},"ts":1452869880}]

I'm decoding the parameter into an array using json_decode(stripslashes($_POST['mandrill_events']), true) and then passing the array into the function as described in the help article:

function generateSignature($webhook_key, $url, $params) {
    $signed_data = $url;
    ksort($params);
    foreach ($params as $key => $value) {
        $signed_data .= $key;
        $signed_data .= $value;
    }

    return base64_encode(hash_hmac('sha1', $signed_data, $webhook_key, true));
}

Using this I end up with

"http://requestb.in/ylyl00yl0Array1Array"

for $signed_data. I've tried a lot of variations of recursively iterating through the array key and values but to no avail.

Has anyone successfully used the example provided by Mandrill? Any help would be appreciated.

Thanks! David

1 Answers1

4

You should be verifying the POST parameters sent by Mandrill, not the events JSON, i.e. generateSignature($key, $url, $_POST)

George Steel
  • 96
  • 1
  • 2
  • Hey @george-steel, the `mandrill_events` data is the only `POST` parameter sent by Mandrill. – David Ashford Jan 18 '16 at 10:04
  • 1
    Sure, but in your question it looks like you are decoding `$_POST['mandrill_events']` and passing the decoded array to `generateSignature` when you should be verifying the `$_POST` array, i.e. `ksort($_POST); $signature = generateSignature($key, $url, $_POST); return $request->getHeader('X-Mandrill-Signature') === $signature;` – George Steel Jan 19 '16 at 11:00
  • Ah, that solves it. Thanks very much George! FYI for anyone else, I also had to use `stripslashes($signed_data)` in the `generateSignature` function before performing the `base64_encode` operation. – David Ashford Jan 20 '16 at 10:30
  • Just a quick note to mention that WordPress (un)helpfully uses wp_slash() to slashify $_POST. Fix is to back up $_POST before requiring WordPress files or to use wp_unslash(). – Brian C Jul 26 '18 at 01:28
  • @DavidAshford could you post your completed working example, I am having an issue with signatures not matching sometimes and thought your stripslashes may hold the key – ctrlbrk Jul 19 '20 at 20:21