Skip to main content

How to validate Cloudinary webhooks signature?

Comments

10 comments

  • Rayee Roded

    in javascript, is the response body the JSON.stringify string of the body?!

    I am following these steps and getting a different signature than what's in the `x-cld-signature` header.

     
    calling the following also resolved with false
     
    await cloudinary.utils.verifyNotificationSignature(
        JSON.stringify(req.body),
        req.headers['x-cld-timestamp'],
        req.headers['x-cld-signature'])
     
    Any idea what's wrong?!
    0
  • Erwin Lukas

    Hi Rayee,

    The req.body should be a string (of JSON), so it should look like this:

    cloudinary.utils.verifyNotificationSignature(
        req.body,
        req.headers['x-cld-timestamp'],
        req.headers['x-cld-signature'])

    So your signed payload should look like this:

    <string of JSON from your body><timestamp>

    Let me know if that doesn't work.

    0
  • Rayee Roded

    It does not work. the `req.body` is an Object - so it needs to be stringified, which is what you are also doing on your unit tests:

    https://github.com/cloudinary/cloudinary_npm/blob/2e5b3f4c6f9d0c0e79f174e211abc61964e8e941/test/utils/utils_spec.js#L1464

     

     

     

     

    0
  • Erwin Lukas

    Hi Rayee,

    I assumed you are using express, and if you have something like this on your app, then yes, the body will be parsed as JSON object instead of JSON string:

    app.use(express.json());

    If that's the case, then you are correct, it needs to be stringify using:

    JSON.stringify(req.body).

    However, I do noticed there might be a bug in verifyNotificationSignature:

    if (timestamp < Date.now() - valid_for) {
    return false;
    }

    Since Date.now() returns in milliseconds, the above condition would always be true, which resulted in return false for verifyNotificationSignature method as you observed.
    I will reach out to our SDK team on this finding for the fix.

    In the meantime, as a workaround, please use either one of the following:

    • Patch cloudinary_npm on your environment from:
      timestamp < Date.now() - valid_for
      to:
      timestamp < Date.now()/1000 - valid_for
    • Use cloudinary.utils.webhook_signature method to generate the signature and compare the 2 hashes
    • Compute SHA1 Hash yourself and compare the 2 hashes

    You can check the following code that I use to analyze and verify my analysis above: https://replit.com/@leptians/verifyNotificationSignature#index.js

    0
  • Rayee Roded

    Thanks for your response.

    I actually already saw that bug with the Date and submitted a PR here: https://github.com/cloudinary/cloudinary_npm/pull/515

    Besides that issue, it seems the signature itself that I get on

    req.headers['x-cld-signature']

    is different than what I get from webhook_signature call (which is actually identical to the way I create it using crypto)

    Not sure it makes a difference but I use a preset with notificaiton_url and not setting the notification_url directly on the upload call

    0
  • Erwin Lukas

    Hi Rayee,

    Thanks for the PR, our SDK team is reviewing it.

    Regarding the signature in the header does not match with webhook_signature, that's interesting, because on my testing (with the code I shared earlier), the signatures are all identical in these 3 aspects:

    • req.headers['x-cld-signature']
    • webhook_signature
    • manual SHA1 crypto

    The only thing that could be different is that your account and your app are using different signature algorithm. Reviewing the account associated with your profile, your cloud is using SHA1. Can you confirm if you are also using SHA1 on your app?

    Using the notification_url in the preset should not make a different, but can you share your upload preset name so I can duplicate on my environment and double-check on this?

    0
  • Erwin Lukas

    Hi Rayee,

    I just tested signature of an upload with upload preset, I can confirm the signature in the headers matches with using webhook_signature as well as manual SHA1 crypto.

    Can you share your code so I can take a look at it?

    0
  • Rayee Roded

    Looks like the current issue is indeed due to signing the upload with sha256 with an account setup of sha1- causing the signature in the header to be sha1.

    I am considering whether I should just use sha1 when creating the signature or change account settings. Will let you know on a private message

    0
  • Erwin Lukas

    Hi Rayee,

    Sounds good. Let's continue our discussion in the private ticket since seems like this is very specific to how your account is setup.

    0
  • Erwin Lukas

    Just quick update regarding verifyNotificationSignature, the issue has been fixed in v1.27.0. Thanks Rayee for the PR 

    0

Please sign in to leave a comment.