2013-09-08 2 views
1

Я работаю с Facebook и анализирует подписанный запрос в сервлете Java с использованием декодера Sun Base64. Я получаю сбои подписи, хотя подпись выглядит почти. Я не могу понять, почему это не соответствует точно, и я считаю, что это проблема с моим кодом. Минимальный код, чтобы увидеть, что я делаю:Facebook подписанный запрос декодирования hash не соответствует точно

BASE64Decoder decoder = new BASE64Decoder(); 
String[] parts = request.getParameter("signed_request").split("\\.", 2); 
String signature = new String(decoder.decodeBuffer(parts[0]), "UTF-8"); 
String rawData = new String(decoder.decodeBuffer(parts[1]), "UTF-8"); 

if (!isSignedRequestValid(request, obj, signature, parts[1])) 
... 

    private boolean isSignedRequestValid(HttpServletRequest request, JSONObject obj, String signature, String data) throws IOException 
    { 

      String expectedSignature = generateSha256Signature(data, FacebookAppSecretKey); 

      if (!signature.equals(expectedSignature)) 
      { 
       log("Facebook signatures do not match, expected: " + expectedSignature + ", received: " + signature); 
       return false; 
      } 
     } 


    private String generateSha256Signature(String data, String key) throws Exception 
    { 
     java.net.URLDecoder decoder = new java.net.URLDecoder(); 
     data = decoder.decode(data, "UTF-8"); // mostly here for testing, doesn't seem to make a difference 
     SecretKeySpec secretKey = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256"); 
     Mac mac = Mac.getInstance("HmacSHA256"); 
     mac.init(secretKey); 
     byte[] hmacData = mac.doFinal(data.getBytes("UTF-8")); 
     return new String(hmacData); 
    } 

Я бегу в две проблемы ... во-первых, ожидаемые против представленные подписи 32 против 33 байта. Но если я сравниваю только первые 32 байта, иногда они равны, но когда он не соответствует, он не соответствует точно одному биту. Например, распечатав индексы и значения один из примеров:

index 14 : [15] , [15] 
index 15 : [71] , [71] 
index 16 : [-10] , [-26] <-- note the different here, which is 16, or one bit 
index 17 : [28] , [28] 
index 18 : [60] , [60] 

Я новичок в разборе Facebook запросы, так что я должен верить, что есть что-то я пропустил в коде, но я не вижу его, и играли с ним достаточно долго, чтобы нуждаться в помощи. И я не вижу ответа нигде в Интернете. Спасибо!

+0

Вы не можете анализировать суровые байты (такие как SHA-хеши) как UTF8. – SLaks

+0

Я не думаю, что это было так. Я изменил все байтовые массивы, просто используя decoder.decodeBuffer(), возвращает массив байтов и сравнивает это с hmacData, который является байтовым массивом. Оказывается, они имеют разную длину, 32 против 33. Тот, который я генерирую из метода сгенерированной подписи, составляет 32 байта. Тот, который я получаю из facebook в подписанном запросе, составляет 33 байта. Это заставляет меня задаться вопросом, имеет ли функция декодера ошибка. Кроме того, он зависит от данных. Если я запускаю его несколько раз, иногда он сравнивается правильно (сравнивая первые 32 байта), иногда нет. Так что что-то в данных, кажется, имеет значение. – user1676075

+0

Интересно, связано ли это с преобразованием пространства в +? – user1676075

ответ

2

Кажется, есть две проблемы: во-первых, декодирование предоставленной Facebook-сигнатуры декодируется до 33 байт вместо 32. Поэтому я просто использую первые 32 байта (на самом деле не важно, что это последнее. .. просто функция заполнения, я думаю).

Другой проблемой была кодировка URL + в -. Использование URLDecoder для декодирования подписи Facebook перед декодированием базы 64 не решило проблему. Вместо этого я сделал следующее:

BASE64Decoder decoder = new BASE64Decoder(); 
    String[] parts = request.getParameter("signed_request").split("\\.", 2); 
    String rawSig = parts[0]; 
    rawSig = rawSig.replaceAll("\\-", "\\+"); 
    byte[] signature = decoder.decodeBuffer(rawSig); 

и этого было достаточно, чтобы первые 32 бита теперь всегда соответствовали вычисленной сигнатуре. Мне показалось странным, что кодировка URL была выполнена таким образом, что URLDecoder.decode() не исправил ее. Было бы любопытно, есть ли у кого-нибудь понимание этой причины.

0

Видимо, вы также должны суб _ стать /

Найдено вещь on Wikipedia:

модифицированные Base64 для вариантов URL существует, где '+' и '/' символов стандартного Base64 являются соответственно, заменены на «-» и «_»,