json 如何在Java中验证Instagram实时API x-hub-signature?

jvlzgdj9  于 2023-03-13  发布在  Java
关注(0)|答案(2)|浏览(129)

我正在使用Play框架为Instagram开发消费者实时API。但仍然无法正确执行x-hub-signature验证。那么,我们如何使用Java和Play框架执行Instagram x-hub-signature验证呢?
下面是我目前的代码:
1.在Play框架中,我使用以下方法获取JSON有效负载:

public static Result receiveInstaData(){
    JsonNode json = request().body().asJson();

    //obtain the x-hub-signature from the header
    //obtain the corresponding client secret

    VerificationResult verificationResult =  
        SubscriptionUtil.verifySubscriptionPostSignature(
            clientSecret, json.toString(), xHubSignature);

    if(verificationResult.isSuccess()){
    //do something
    }
 }

1.然后在SubscriptionUtil中,我使用以下代码执行验证:

public static VerificationResult verifySubscriptionPostSignature(String clientSecret, String rawJsonData, String xHubSignature) {
    SecretKeySpec keySpec;
    keySpec = new SecretKeySpec(clientSecret.getBytes("UTF-8"), HMAC_SHA1);

    Mac mac;
    mac = Mac.getInstance(HMAC_SHA1);
    mac.init(keySpec);

    byte[] result;
    result = mac.doFinal(rawJsonData.getBytes("UTF-8"));
    String encodedResult = Hex.encodeHexString(result);

    return new VerificationResult(encodedResult.equals(xHubSignature), encodedResult);
   }

我创建了一个独立的Python脚本,它复制了instagram-python的实现,对于相同的clientSecretjsonString,它们都产生了相同的结果。
假设我们需要一个原始的二进制数据来处理JSON请求,那么我需要创建一个自定义的BodyParser来将JSON请求解析为原始的二进制数据[5]
参考文献:
[1-4][http://pastebin.com/g4uuDwzn](http://pastebin.com/g4uuDwzn)(SO不允许我发布超过2个链接,所以我把所有的引用放在这里。链接包含Ruby,Python和PHP中的签名验证)
[5]论坛
[6]My独立python脚本:#!/usr/bin/环境语言

import sys
import hmac
import hashlib

hc_client_secret = "myclientsecret"
hc_raw_response = "[{\"subscription_id\":\"1\",\"object\":\"user\",\"object_id\":\"1234\",\"changed_aspect\":\"media\",\"time\":1297286541},{\"subscription_id\":\"2\",\"object\":\"tag\",\"object_id\":\"nofilter\",\"changed_aspect\":\"media\",\"time\":1297286541}]"

client_secret = hc_client_secret
raw_response = hc_raw_response

if len(sys.argv) != 3:
    print 'Usage verify_signature <client_secret> <raw_response>.\nSince the inputs are invalid, use the hardcoded value instead!'
else:
    client_secret = sys.argv[1]
    raw_response = sys.argv[2]  

print "client_secret = " + client_secret
print "raw_response = " + raw_response

digest = hmac.new(client_secret.encode('utf-8'), msg=raw_response.encode('utf-8'), digestmod=hashlib.sha1).hexdigest()
print digest
rlcwz9us

rlcwz9us1#

最后我设法找到了解决方案。对于Play框架中的控制器,我们需要使用BodyParser.Raw,这样我们就可以将有效负载请求提取为原始数据,即字节数组。
以下是Play Framework中控制器的代码:

@BodyParser.Of(BodyParser.Raw.class)
public static Result receiveRawInstaData(){
    Map<String, String[]> headers = request().headers();
    RawBuffer jsonRaw = request().body().asRaw();

    if(jsonRaw == null){
        logger.warn("jsonRaw is null. Something is wrong with the payload");
        return badRequest("Expecting serializable raw data");
    }

    String[] xHubSignature = headers.get(InstaSubscriptionUtils.HTTP_HEADER_X_HUB_SIGNATURE);
    if(xHubSignature == null){
        logger.error("Invalid POST. It does not contain {} in its header", InstaSubscriptionUtils.HTTP_HEADER_X_HUB_SIGNATURE);
        return badRequest("You are not Instagram!\n");
    }

    String json;
    byte[] jsonRawBytes;

    jsonRawBytes = jsonRaw.asBytes();
    json = new String(jsonRawBytes, StandardCharsets.UTF_8);

    try {
        String clientSecret = InstaSubscriptionUtils.getClientSecret(1);
        VerificationResult verificationResult = SubscriptionUtil.verifySubscriptionPostRequestSignature
                (clientSecret,jsonRawBytes, xHubSignature[0]);
        if(verificationResult.isSuccess()){
            logger.debug("Signature matches!. Received signature: {}, calculated signature: {}", xHubSignature[0], verificationResult.getCalculatedSignature());
        }else{
            logger.error("Signature doesn't match. Received signature: {}, calculated signature: {}", xHubSignature[0], verificationResult.getCalculatedSignature());
            return badRequest("Signature does not match!\n");
        }
    } catch (InstagramException e) {
        logger.error("Instagram exception.", e);
        return internalServerError("Internal server error. We will attend to this problem ASAP!");
    }

    logger.debug("Received xHubSignature: {}", xHubSignature[0]);
    logger.info("Sucessfully received json data: {}", json);

    return ok("OK!");
}

对于SubscriptionUtilverifySubscriptionPostRequestSignature方法的代码

public static VerificationResult verifySubscriptionPostRequestSignature(String clientSecret, byte[] rawJsonData, String xHubSignature) throws InstagramException{
    SecretKeySpec keySpec;
    keySpec = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), HMAC_SHA1);
    Mac mac;

    try {
        mac = Mac.getInstance(HMAC_SHA1);
        mac.init(keySpec);
        byte[] result = mac.doFinal(rawJsonData);
        String encodedResult = Hex.encodeHexString(result);

        return new VerificationResult(encodedResult.equals(xHubSignature), encodedResult);
    } catch (NoSuchAlgorithmException e) {
        throw new InstagramException("Invalid algorithm name!", e);
    } catch (InvalidKeyException e){
        throw new InstagramException("Invalid key: " + clientSecret, e);
    }
}

我在jInstagram中实现了这个解决方案,下面是源代码的链接:订阅实用程序

dzhpxtsq

dzhpxtsq2#

重要进口:
导入org.apache.commons.codec.binary.Hex文件;
导入javax.crypto.Mac;
导入javax.crypto.spec密钥规范;
另一个简单的例子:

public boolean isValidSignature(byte[] payload, String signature) throws NoSuchAlgorithmException, InvalidKeyException {

    signature = signature.replace("sha256=", "");

    Mac sha256_HMAC = Mac.getInstance(HMAC_SHA_256);
    SecretKeySpec secretKeySpec = new SecretKeySpec("youSecret".getBytes(), HMAC_SHA_256);
    sha256_HMAC.init(secretKeySpec);

    byte[] hash = sha256_HMAC.doFinal(payload);
    String message = Hex.encodeHexString(hash);
    boolean isValid = message.equals(signature);

    System.out.println(String.format("Signature is valid: %b [payload: %s] [signature: %s]", isValid, new String(payload, Charset.defaultCharset()), signature));
    return isValid;
}

相关问题