2015-07-17 5 views
9

Ich versuche, ein sicheres Zeichen für ReCaptcha V2 zu erzeugen, wie hier beschrieben: https://developers.google.com/recaptcha/docs/secure_tokenWie generiere ich ein Google ReCaptcha V2 Secure Token mit PHP?

Leider hat mein erzeugt stoken nicht gültig ist, und ich kann nicht einen Weg finden, um zu überprüfen, warum es nicht funktioniert . Es gibt ein funktionierendes Java-Beispiel (STokenUtils.java), , aber ich kann es nicht in PHP übersetzen.

public static function generateSecurityToken($secretKey){ 
    $stoken = array(
     'session_id' => session_id(), 
     'ts_ms' => round(microtime(true)*1000) 
    ); 
    $secretKey = self::pkcs5_pad(hash('sha1', $secretKey), 16); 
    $stoken_json = json_encode($stoken); 
    $stoken_crypt = self::encrypt(self::pkcs5_pad($stoken_json, 16), $secretKey); 
    return $stoken_crypt; 
} 

public static function encrypt($sStr, $sKey) { 
    return base64_encode(
     mcrypt_encrypt(
      MCRYPT_RIJNDAEL_128, 
      base64_decode($sKey), 
      $sStr, 
      MCRYPT_MODE_ECB 
     ) 
    ); 
} 

public static function pkcs5_pad ($text, $blocksize) { 
    $pad = $blocksize - (strlen($text) % $blocksize); 
    return $text . str_repeat(chr($pad), $pad); 
} 

Kann jemand ein funktionierendes PHP-Beispiel zur Verfügung stellen oder auf offensichtliche Fehler in meinem Code hinweisen?

+2

ich über die Verwendung der ECB-Modus äußern würde, aber [es stellt sich heraus, dass Google die Implementierung tut dies auch] (https://github.com/google/recaptcha- Java/Ausgaben/1). Seufzer. –

+0

@alingex Wenn Sie eine funktionierende Lösung erhalten, können Sie den PHP-Code posten? Vielen Dank, weil Sie eine gute Frage gestellt haben! –

+1

@mikey_w siehe meine Antwort [# 31684672] (http:// Stackoverflow.com/a/31684672/3991313) unten für eine Drop-in-Lösung – slushie

Antwort

10

eine Reihe von Problemen in Ihrem Code Es gibt keine. Zuerst wird Ihr Wert als ein aufgefüllter SHA1-Hash berechnet, wenn die Implementierung die ersten sechzehn Bytes des SHA1-Hash erfordert.

Zweitens versuchen Sie, eine Base64-Decodierung des geheimen Schlüssels durchzuführen, die hier nicht gültig ist. Das zweite Argument zu mcrypt_encrypt() sollte $sKey sein, nicht base64_decode($sKey).

Schließlich, wie in x77686d Antwort erklärt, sollten Sie eine "URL-safe" base64 verwenden. Das ist eine Variante von base64, die nicht gepolstert ist und die Zeichen + oder / nicht verwendet. Stattdessen werden die Zeichen - und _ an ihren Stellen verwendet.

ReCaptchas sichere Token sind ein bisschen Schmerz, ehrlich gesagt. Sie sind unsicher und der Algorithmus ist nicht dokumentiert. Ich war in der gleichen Position wie Sie und brauchte eine Implementierung, also ich wrote one und veröffentlichte es auf Packagist as "slushie/recaptcha-secure-token".Ich würde empfehlen, es zu benutzen und/oder beizutragen, schon allein wegen des Mangels an alternativen Implementierungen dieses Algorithmus.

+0

Danke, das hat mein Problem gelöst. :) – alingex

+0

Ihre Implementierung ist sehr hilfreich, vielen Dank! – Hexodus

1

Google's STokenUtils.java examplecom.google.common.io.BaseEncoding.base64url() verwendet (siehe BaseEncoding) und ihre Codierung verwendet '-' und '_' anstelle von '+' und '/' bezeichnet.

PHP base64_encode macht diese Substitutionen nicht. Siehe https://gist.github.com/nathggns/6652997 für eine base64url_encode, aber Sie werden sehen, dass es einfach '+' in '-', '/' in '_' ändert und triming nach '=' abbildet.

Sie könnten andere anderen Probleme haben, aber ich feste gerade jetzt das gleiche Problem (ERROR: Invalid stoken) in einer Java-Version eines homegrown Base64 Encoder, indem Sie diese:

encoded = encoded.replace('+','-').replace('/','_').replace("=",""); 

Als festes Ziel, versuchen und Codierung verschlüsselt diese Aufgabe:

{"session_id":"1","ts_ms":1437712654577} 

mit diesem geheimen Schlüssel

6Lc0MgoTAAAAAAXFM388zn66iPtjOdQgREfZAgqZ 

und sehen Sie, wenn Sie diese erhalten: (! Beachten Sie, dass in der Mitte unterstreichen)

XlPyYFtyfzmsf5rnRIzyuZ4MZo5GoCSxNcI_wAeOqb18zCxhSM5cYxU8fFerrdcC 

BTW, einfach mit, dass eine sichere Token als Service-Leistung einen anderen Fehler erzeugen soll: ERROR: Stoken expired. Machen Sie das zu einem Schrägstrich und Sie sind zurück zu ERROR: Invalid stoken!

Siehe auch base64url auf https://en.wikipedia.org/wiki/Base64

+0

Vielen Dank für Ihre Antwort! Können Sie mir den geheimen Schlüssel zur Verfügung stellen, den Sie verwendet haben, um das Beispiel zu generieren, das Sie angegeben haben, damit ich die Ergebnisse vergleichen kann? – alingex

+0

Jetzt nicht-so geheimer Schlüssel hinzugefügt! :) – x77686d

+0

Ich stehe vor genau diesem Problem. @ x77686d kannst du den PHP-Code klären, der benutzt wurde, um das Token zu erstellen, das in deiner Antwort generiert wurde? Mit anderen Worten: Wie passt die von Ihnen empfohlene Funktion base64_encode in das Gesamtbild? Vielen Dank! –

1

Versuchen Sie folgendes:

public static function generateSecurityToken($secretKey){ 
    $stoken = array(
     'session_id' => session_id(), 
     'ts_ms' => round(microtime(true)*1000) 
    ); 


    $stoken_json = json_encode($stoken); 
    $stoken_json = str_replace('+', '-', $stoken_json); 
    $stoken_json = str_replace('/', '_', $stoken_json); 
    $stoken_json = str_replace('=', '', $stoken_json); 

    $secretKey = pack('H*', substr(hash('sha1', $secretKey), 0, 32)); 

    $stoken_crypt = self::encrypt(self::pkcs5_pad($stoken_json, 16), $secretKey); 
    return $stoken_crypt; 
} 

public static function encrypt($sStr, $sKey) { 
    $json = base64_encode(
     mcrypt_encrypt(
      MCRYPT_RIJNDAEL_128, 
      $sKey, 
      $sStr, 
      MCRYPT_MODE_ECB 
     ) 
    ); 
    $sStr = str_replace('+', '-', $json); 
    $sStr = str_replace('/', '_', $sStr); 
    $sStr = str_replace('=', '', $sStr); 
    return $sStr; 
} 
+0

wie kann ich das verwenden? Vielen Dank – AMB