Can Only Verify Test Webhook Signatures

Hi there,

I’m working on a Ruby on Rails application and trying to implement webhooks. So far, all test webhooks pass signature verification. However, the webhooks I’m listening to (refund.updated) that get triggered by API interactions fail to verify the signature.

Application ID: sandbox-sq0idb-ijUBhp4f2JVacvzFnKliRg

:wave: Looking at the logs I do see retry’s for the refund.updated event. Is the application responding with a 200 within 10 seconds of delivery?

Hey @Bryan-Square, I might not have been clear enough in my first post.

We can’t return 200, the signature is not verifiable from the webhook. All test events verify just fine but without changing any code, the real ones do not get verified correctly.

You should be able to respond with a 200 prior to verifying the signature.

Ok, but my question on the forum is because I can’t verify the signature and I’m looking for help there. If I respond with 200s when the signature is not verified, what will that do for me?

&

Hey @Bryan-Square forgot to ping you on this, not sure if you saw it.

In your logs I was seeing retry’s which means that we think you didn’t receive the webhook. We want to make sure you are correctly receiving them to next verify and validate the webhook. :slightly_smiling_face:

@Bryan-Square the request always responds with 2XX now. Can you help me debug why a test event signature verifies correctly but a real event from the sandbox does not?

This is what the verification code looks like which works for test events sent through the dashboard:

    # Validates HMAC-SHA1 signatures included in webhook notifications to ensure notifications came from Square
    def valid_square_signature?(body, signature)
      square_webhook_signature_key = ENV['SQUARE_WEBHOOK_SIGNATURE_KEY']

      if square_webhook_signature_key.nil?
        logger.warn "HandleSquareWebhook: Cannot verify webhook, missing signature key. Aborting."
        return false
      end

      # Combine your webhook notification URL and the JSON body of the incoming request into a single string
      string_to_sign = WEBHOOK_URL + body.gsub(/\s+/, "")

      # Generate the HMAC-SHA1 signature of the string, signed with your webhook signature key
      string_signature = Base64.strict_encode64(OpenSSL::HMAC.digest('sha1', square_webhook_signature_key, string_to_sign))

      # Hash the signatures a second time (to protect against timing attacks)
      # and compare them
      Digest::SHA1.base64digest(string_signature) == Digest::SHA1.base64digest(signature)
    end

A psuedo-algorithm to verify the signature of a webhook delivery is described below.

  1. Step 1: Extract the signature(s) from the request.
  2. Step 2: Compute the expected valid signature.
  3. Step 3: Compare the signatures.

That is an incredibly unhelpful response. I’ve explained that the signature verification works with the test events sent from Square. I’ve also provided the actual code used to verify.

@Bryan-Square just thought I’d check with you one more time as I have made adjustments based on your previous message.

With the changes it’s still validating just the test webhooks? Also recently we discovered an issue with the keys. The team recommends that apps use the raw bytes from the request rather than converting the object representation in your language back to bytes for signature validation. :slightly_smiling_face: