Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I want to know how to verify Java for Validating payloads from webhooks #1376

Closed
nieanlei opened this issue Feb 18, 2022 · 6 comments
Closed

Comments

@nieanlei
Copy link

Is there any Java API?

how to decrypt payload

public String gitHubHook(@RequestBody String payload, @RequestHeader("X-GITHUB-EVENT") String event,
        @RequestHeader("X-Hub-Signature-256") String signature) throws IOException {

}

@gsmet
Copy link
Contributor

gsmet commented Feb 18, 2022

If you are developing a GitHub bot, I would suggest you have a look to my Quarkus GitHub App project, which handles all the boilerplate for you: https://github.com/quarkiverse/quarkus-github-app .
It doesn't require any prior Quarkus knowledge and is extensively documented.

If you prefer doing things all by yourself, just have a look at the payload checker there: https://github.com/quarkiverse/quarkus-github-app/blob/main/runtime/src/main/java/io/quarkiverse/githubapp/runtime/signing/PayloadSignatureChecker.java . It's Apache licensed so feel free to borrow it.

If your question was about parsing the payload itself, the GitHub API offers GitHub#parseEventPayload() which will return the appropriate GHEventPayload instance.

@nieanlei
Copy link
Author

If you are developing a GitHub bot, I would suggest you have a look to my Quarkus GitHub App project, which handles all the boilerplate for you: https://github.com/quarkiverse/quarkus-github-app . It doesn't require any prior Quarkus knowledge and is extensively documented.

If you prefer doing things all by yourself, just have a look at the payload checker there: https://github.com/quarkiverse/quarkus-github-app/blob/main/runtime/src/main/java/io/quarkiverse/githubapp/runtime/signing/PayloadSignatureChecker.java . It's Apache licensed so feel free to borrow it.

If your question was about parsing the payload itself, the GitHub API offers GitHub#parseEventPayload() which will return the appropriate GHEventPayload instance.

Thinks

@nieanlei
Copy link
Author

If you are developing a GitHub bot, I would suggest you have a look to my Quarkus GitHub App project, which handles all the boilerplate for you: https://github.com/quarkiverse/quarkus-github-app . It doesn't require any prior Quarkus knowledge and is extensively documented.

If you prefer doing things all by yourself, just have a look at the payload checker there: https://github.com/quarkiverse/quarkus-github-app/blob/main/runtime/src/main/java/io/quarkiverse/githubapp/runtime/signing/PayloadSignatureChecker.java . It's Apache licensed so feel free to borrow it.

If your question was about parsing the payload itself, the GitHub API offers GitHub#parseEventPayload() which will return the appropriate GHEventPayload instance.

I can match it with your demo data

I can't match the correct signature with,GitHub sent sender.
payload-signature-checker.txt

eg: this txt is :payload-signature-checker.json ,GitHub sent it to me push event json

my webhooks-secret: webhooksSecret

image

image

image

GitHub sent it to me : 99c04af1c3897c1d0bb9870cb4b8237701e1aacb8c0bc6f15fdbf00a36772276,

I use demo : b00dc3bc916f8e95a7542c88656dde45fc24d7c3d3727c464338509aba17ba2d

why

@gsmet
Copy link
Contributor

gsmet commented Feb 23, 2022

I can't really say. I know it works for me with Quarkus GitHub App.

One important point though: you need to provide the JSON exactly as is. If you are using something like smee.io to redirect the payload to your computer, smee.io actually changes the payload before sending it to you. It's a well known bug of smee.io (see probot/smee.io#78 for instance but there are a few others related).

I have no idea if you're doing that though.

In the case of Quarkus GitHub App, I disable the signature checking in development mode when using smee.io and only enable it in production.

@nieanlei
Copy link
Author

package github.test.play;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SecretKeyTest {

private static String webhookSecret = "webhooks";

private static final String SIGNATURE_PREFIX = "sha1=";
private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";



public boolean validateSignature(String signatureHeader, String body, String encoding) throws UnsupportedEncodingException {
    byte[] payload = body.getBytes(encoding == null ? "UTF-8" : encoding);
    if (webhookSecret == null || webhookSecret.equals("")) {
        return true;
    }

    if (!StringUtils.startsWith(signatureHeader, SIGNATURE_PREFIX)) {
        return false;
    }
    byte[] signature;
    try {
        signature = Hex.decodeHex(signatureHeader.substring(SIGNATURE_PREFIX.length()).toCharArray());
    } catch (DecoderException e) {
        return false;
    }
    return MessageDigest.isEqual(signature, getExpectedSignature(payload));
}

private byte[] getExpectedSignature(byte[] payload) {
   SecretKeySpec key = new SecretKeySpec(webhookSecret.getBytes(), HMAC_SHA1_ALGORITHM);
    Mac hmac;
    try {
        hmac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
        hmac.init(key);
    } catch (NoSuchAlgorithmException e) {
        throw new IllegalStateException("Hmac SHA1 must be supported", e);
    } catch (InvalidKeyException e) {
        throw new IllegalStateException("Hmac SHA1 must be compatible to Hmac SHA1 Secret Key", e);
    }
    return hmac.doFinal(payload);
}

}

@nieanlei
Copy link
Author

@RequestMapping(value = "/open/git/github/hook")
public String playload(  HttpServletRequest req) throws IOException {
    SecretKeyTest secretKeySpec =new SecretKeyTest();
    try (BufferedReader reader = req.getReader()) {
        String body = Joiner.on("\n").join(CharStreams.readLines(reader));
        secretKeySpec.validateSignature(req.getHeader("X-Hub-Signature"), body, req.getCharacterEncoding());
    }
    return "sucess";

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants