Skip to content

Webhook Security - Unable to verify signature when payload contains an emoji? #3567

Closed
@bitbound

Description

@bitbound

What article on docs.github.com is affected?

https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks#securing-your-secret-token

What part(s) of the article would you like to see updated?

Below is the verification method I made for processing webhook events (.NET Core backend). It works for the test payload that gets sent when creating the webhook, and it works in my local tests.

However, it failed when receiving one of the real events. The only thing I could think that was significantly different is that the failed payload contained an emoji (from the tier description).

Is there something special that needs to be done when the payload contains an emoji?

Additional information

Verification Method

        private async Task<(bool signaturesMatch, string payloadString)> VerifySignature()
        {
            using var sr = new StreamReader(Request.Body);
            var payloadString = await sr.ReadToEndAsync();

            var signature = Request.Headers["X-Hub-Signature-256"].ToString();
            var secret = _config["WebhookSecret"];
            var key = Encoding.ASCII.GetBytes(secret);
            var payloadBytes = Encoding.ASCII.GetBytes(payloadString);

            using var hasher = new HMACSHA256(key);
            var hash = hasher.ComputeHash(payloadBytes);

            var hashString = string.Join(string.Empty, Array.ConvertAll(hash, b => b.ToString("x2")));

            return ($"sha256={hashString}".ConstantTimeCompare(signature), payloadString);
        }

Test Payload

Header:
X-Hub-Signature-256: sha256=09f0b80427cf91b9e9fed1d4df498e4ee7a018fca94dcf3fb61816e1391205d3

Body (minified in real test):

{
  "zen": "Design for failure.",
  "hook_id": 279464316,
  "hook": {
    "type": "SponsorsListing",
    "id": 279464316,
    "name": "web",
    "active": true,
    "events": [
      "*"
    ],
    "config": {
      "content_type": "json",
      "secret": "********",
      "url": "https://remotely.one/api/sponsors",
      "insecure_ssl": "0"
    },
    "updated_at": "2021-02-04T05:56:56Z",
    "created_at": "2021-02-04T05:56:56Z",
    "sponsors_listing_node_id": "MDE1OlNwb25zb3JzTGlzdGluZzY3OTM="
  },
  "sender": {
    "login": "lucent-sea",
    "id": 20995508,
    "node_id": "MDQ6VXNlcjIwOTk1NTA4",
    "avatar_url": "https://avatars.githubusercontent.com/u/20995508?v=4",
    "gravatar_id": "",
    "url": "https://api.github.com/users/lucent-sea",
    "html_url": "https://github.com/lucent-sea",
    "followers_url": "https://api.github.com/users/lucent-sea/followers",
    "following_url": "https://api.github.com/users/lucent-sea/following{/other_user}",
    "gists_url": "https://api.github.com/users/lucent-sea/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/lucent-sea/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/lucent-sea/subscriptions",
    "organizations_url": "https://api.github.com/users/lucent-sea/orgs",
    "repos_url": "https://api.github.com/users/lucent-sea/repos",
    "events_url": "https://api.github.com/users/lucent-sea/events{/privacy}",
    "received_events_url": "https://api.github.com/users/lucent-sea/received_events",
    "type": "User",
    "site_admin": false
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    triageDo not begin working on this issue until triaged by the team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions