Facebook实时更新:在C#中验证X-Hub-Signature SHA1签名

时间:2010-12-08 17:43:34

标签: c# asp.net facebook real-time

当Facebook发送实时更新时,它们在HTTP标头中包含X-Hub-Signature。根据他们的文档(http://developers.facebook.com/docs/api/realtime),他们使用SHA1和应用程序密钥作为密钥。我试着像这样验证签名:

public void MyAction() {
  string signature = request.Headers["X-Hub-Signature"];
  request.InputStream.Position = 0;
  StreamReader reader = new StreamReader(request.InputStream);
  string json = reader.ReadToEnd();

  var hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(json), UTF8Encoding.UTF8.GetBytes("MySecret"));
  var hmacBase64 = ToUrlBase64String(hmac);

  bool isValid = signature.Split('=')[1] == hmacBase64;

}


    private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) {
        using (var hmacAlgorithm = new System.Security.Cryptography.HMACSHA1(keyBody)) {
            hmacAlgorithm.ComputeHash(dataToSign);
            return hmacAlgorithm.Hash;
        }
    }

    private static string ToUrlBase64String(byte[] Input) {
        return Convert.ToBase64String(Input).Replace("=", String.Empty)
                                            .Replace('+', '-')
                                            .Replace('/', '_');
    }

但我似乎无法让这一点得到验证。对我做错了什么的想法?

提前致谢。

2 个答案:

答案 0 :(得分:8)

如果有人需要此信息:

Kelvin提供的可能有用,但看起来非常麻烦。 您只需使用ConvertToHexadecimal函数,而不是使用ToUrlBase64String函数。

请参阅下面的完整更新代码:

public void MyAction() {
    string signature = request.Headers["X-Hub-Signature"];
    request.InputStream.Position = 0;
    StreamReader reader = new StreamReader(request.InputStream);
    string json = reader.ReadToEnd();

    var hmac = SignWithHmac(UTF8Encoding.UTF8.GetBytes(json), UTF8Encoding.UTF8.GetBytes("MySecret"));
    var hmacHex = ConvertToHexadecimal(hmac);

    bool isValid = signature.Split('=')[1] == hmacHex ;

}


private static byte[] SignWithHmac(byte[] dataToSign, byte[] keyBody) {
    using (var hmacAlgorithm = new System.Security.Cryptography.HMACSHA1(keyBody)) {
        return hmacAlgorithm.ComputeHash(dataToSign);
    }
}

private static string ConvertToHexadecimal(IEnumerable<byte> bytes)
{
    var builder = new StringBuilder();
    foreach (var b in bytes)
    {
        builder.Append(b.ToString("x2"));
    }

    return builder.ToString();
 }

答案 1 :(得分:1)

以下代码将为您解决问题:

     public String hmacSha1(String keyString, byte[] in) throws GeneralSecurityException {
        Mac hmac = Mac.getInstance("HmacSHA1");
        int keySize = keyString.length();
        byte[] keyBytes = new byte[keySize];

        for (int i = 0; i < keyString.length(); i++) {
          keyBytes[i] = (byte) keyString.charAt(i);
        }

        Key key = new SecretKeySpec(keyBytes, "HmacSHA1");
        hmac.init(key);
        hmac.update(in);
        byte[] bb = hmac.doFinal();

        StringBuilder v = new StringBuilder();
        for (int i = 0; i < bb.length; i++) {
          int ch = bb[i];
          int d1 = (ch >> 4) & 0xf;
          int d2 = (ch) & 0xf;

          if (d1 < 10) {
            v.append((char) ('0' + d1));
          } else {
            v.append((char) ('a' + d1 - 10));
          }

          if (d2 < 10) {
            v.append((char) ('0' + d2));
          } else {
            v.append((char) ('a' + d2 - 10));
          }
        }
        return v.toString();
      }

  public String callback(HttpServletRequest request) throws IOException {
    InputStream in = request.getInputStream();
    StringBuilder builder = new StringBuilder();
    byte[] buffer = new byte[1024];
    while (in.read(buffer) > 0) {
      builder.append(new String(buffer));
    }
    String signature = request.getHeader("X-Hub-Signature");
    try {
      String signed = subscriptionService.hmacSha1("YOUR_SECRET", builder.toString().getBytes());
      if (signature.startsWith("sha1=") && signature.substring(4).equals(signed)) {
        // process the update
        ....
      }
    } catch (GeneralSecurityException ex) {
      log.warn(ex.getMessage());
    }

    return null;
  }