2016-09-22 1 views
1

Ich habe viel zu lange daran gearbeitet. Ich suche nach einem Arbeitsbeispiel ab September 2016 ein Google idToken wieWie verifiziere ich ein Google IDToken in PHP?

eyJhbGciOiJSUzI1NiIsImtpZCI6IjZjNzgxOTQyZDg0OWJhMmVjZGE4Y2VkYjcyZDM0MzU3ZmM5NWIzMjcifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIxMDQ5MTQ4MTU2NTQ2LTk2YjFxcTJsNTJtODVtODB0ZHVoZHVma2RwODRtN2tuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTEyNTk4NDgzNjQ2MjY1OTYxNTQwIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF6cCI6IjEwNDkxNDgxNTY1NDYtdjJwZjRlbGhzOGNwcXBlcWZkMzU5am5nOWs5aW5kcTQuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6InRlc3R1c2VydGh4QGdtYWlsLmNvbSIsImlhdCI6MTQ3NDc1NDMzMiwiZXhwIjoxNDc0NzU3OTMyLCJuYW1lIjoiVGVzdCBVc2VyIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tU0dldkZZRDlaWFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQVBhWEhoUmtuX1hEaEhNLTEzeVMwTUtBcFNrZG1zVEdYdy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiVGVzdCIsImZhbWlseV9uYW1lIjoiVXNlciIsImxvY2FsZSI6ImVuIn0.btukbBvhek6w14CrBVTGs8X9_IXIHZKpV1NzJ3OgbGUfmoRMirNGzZiFAgrR7COTeDJTamxRzojxxmXx6EEkQqNQcbyN8dO0PTuNt9pujQjLbFw_HBhIFJQaJSR3-tYPN-UtHGQ5JAAySsvCPapXbxyiKzTyvGYRSU65LmyNuiGxe6RQe1zHjq2ABJ4IPRqKPuFupnGRPWYyBSTPU7XQvtfhgyqA0BWZUfmCIFyDxQhvMaXNLTs01gnGVhcUDWZLi9vuUiKUlz3-aSSbwdfCMAljhBHnjpYO6341k5-qmgKkWawv8DX_nMEzntsCMCr664rP4wFEbsRB5ledM9Pc9Q

Verwendung von Google empfohlenen Weg und ziehen „accounts.google.com/.well-known/openid-configuration“ für die jwks_uri für die Überprüfung und ziehen, dass „www.googleapis.com/oauth2/v3/certs“, einen entsprechenden Eintrag wodurch man für

{ 
    "kty": "RSA", 
    "alg": "RS256", 
    "use": "sig", 
    "kid": "6c781942d849ba2ecda8cedb72d34357fc95b327", 
    "n": "s1dt5wFFaYl-Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ-b-oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG_CfmewNVwBXPFx8-mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9-WAEZ1q8wq-I93Sfte95RaFjDqCH--Sh-8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ", 
    "e": "AQAB" 
    }

Überprüfung passiert, wenn ich das Token an https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=TOKEN passieren, aber das ist keine wirkliche Antwort, da sie don Ändere das nicht oft, aber wenn du jedes Mal einen zusätzlichen Web-Call machst, fragst du nur nach Ärger.

Kann mich also jemand auf ein funktionierendes Beispiel hinweisen? Ich habe phpseclib versucht, aber es überprüft nie. Ich habe wahrscheinlich zu diesem Zeitpunkt ungefähr 40 Stunden gesucht und bin am Ende meiner Weisheit.

Jede Hilfe wird geschätzt.

Mein entsprechender Code:

$modulus = ""; 
$exponent = ""; 
$token = $_POST['token']; 
$pieces = explode(".", $token); 
$header = json_decode(base64_decode(str_replace(['-','_'], ['+','/'], $pieces[0])), true); 
$alg = $header['alg']; 
$kid = $header['kid']; 
$payload = base64_decode(str_replace(['-','_'], ['+','/'], $pieces[1])); 
$signature = str_replace(['-','_'], ['+','/'], $pieces[2]); 
//$signature = base64_decode(str_replace(['-','_'], ['+','/'], $pieces[2])); 

if (testGoogleList($alg, $kid, $modulus, $exponent)) 
{ 

    echo "Found in list: kid=".$kid."\n"; 
    echo "n: (base64URL)".$modulus."\n"; 
    echo "e: (base64URL)".$exponent."\n"; 
    $modulus = str_replace(['-','_'], ['+','/'], $modulus); 
    $exponent = str_replace(['-','_'], ['+','/'], $exponent); 
    echo "n: (base64)".$modulus."\n"; 
    echo "e: (base64)".$exponent."\n"; 
    $rsa = new Crypt_RSA(); 
    $rsa->setHash("sha256"); 
    $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); 
    $modulus = new Math_BigInteger($modulus, 256); 
    $exponent = new Math_BigInteger($exponent, 256); 
    echo "n: (BigInteger)".$modulus."\n"; 
    echo "e: (BigInteger)".$exponent."\n"; 
    $rsa->loadKey(array('n' => $modulus, 'e' => $exponent)); 
    $rsa->setPublicKey(); 
    $pubKey = $rsa->getPublicKey(); 
    echo "Public Key from phpseclib\n".$pubKey."\n"; 
    echo "--First openSSL error check--\n"; 
    while ($msg = openssl_error_string()) 
     echo $msg . "<br />\n"; 
    echo "--After First Error Check, before Verify--\n"; 
    $res = $rsa->verify($pieces[0].".".$pieces[1], $signature); 
    while ($msg = openssl_error_string()) 
     echo $msg . "<br />\n"; 
    echo "--Verify result: ".var_export($res, true)."--\n"; 
} 

Ausgabe

Found in list: kid=6c781942d849ba2ecda8cedb72d34357fc95b327 
n: (base64URL)s1dt5wFFaYl-Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ-b-oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG_CfmewNVwBXPFx8-mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9-WAEZ1q8wq-I93Sfte95RaFjDqCH--Sh-8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ 
e: (base64URL)AQAB 
n: (base64)s1dt5wFFaYl+Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ+b+oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG/CfmewNVwBXPFx8+mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9+WAEZ1q8wq+I93Sfte95RaFjDqCH++Sh+8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ 
e: (base64)AQAB 
n: (BigInteger)18674717054764783973087488855176842456138281065703345249166514684640666364313492818979675328236363014396820758462507776710767978395332237045824933690552916871072924852353561300648679961653291310130667565640227949181785672954620248276915721938277908962537175894062430220752771265500386404609948390377043762106166027544443459977210114747088393335234720657330424186435226141073425445733987857419933850994487913462193466159335385639996611717486282518255208499657362420183528330692236194252505592468150318350852955051377118157817611947817677975817359347998935961426571802421142861030565807099600656362069178972477827638867161671399657071319083914500667014214521757304661303525496653078786180348831678824969667950119891369610525474165187687495455755684504105433077872587114630537058768184460798470456362909589578101896361255070801 
e: (BigInteger)1095844162 
Public Key from phpseclib 
-----BEGIN PUBLIC KEY----- 
MIIBeDANBgkqhkiG9w0BAQEFAAOCAWUAMIIBYAKCAVZzMWR0NXdGRmFZbCtCdDdZ 
YjdRZ1dFYXRMSmZ4d1dEaGJkNXl2bTJaNGQxUFJnTlZRYTlrd09BclFOb09KK2Ir 
b1puWExWRnNWQVNVWEVBdW1HZjFpcDVUVkNRbU1CS3FsY2hTRE51b1pmb1dkcEND 
WDdqeDRnTnVTNDNwUzZWcVYzUURqV25vWFJUSGFVaTVwWkVicEFtV3BPZUcvQ2Zt 
ZXdOVndCWFBGeDgrbXR2RWR0eElyc3BYNGF5WFRWaVI0dkhjN01oUWhVeGxsRmJv 
Y3hNakp5c0RRdVpWOXdOM01JMGxWdFFkZjUyU0tKd0YzbGh2V0E5K1dBRVoxcTh3 
cStJOTNTZnRlOTVSYUZqRHFDSCsrU2grOERqaEs0T3ZnSXRjRUdkNVFSSGpkTHZy 
YXlQd2FEUWJwTVJOMm4zQmtWV0l4S0p1YnRSaVNlV2Jhd0NrbFECBEFRQUI= 
-----END PUBLIC KEY----- 
--First openSSL error check-- 
--After First Error Check, before Verify-- 
error:0906D06C:PEM routines:PEM_read_bio:no start line
--Verify result: false--
+0

Könnten Sie einige Beispiele für Chiffretexte veröffentlichen, die der öffentliche Schlüssel entschlüsseln könnte? Ohne das ist es unmöglich, den Schlüssel zu testen. Könnten Sie vielleicht auch einen Link zu einer Dokumentation für Google Identity veröffentlichen? Ich habe eine Google-Suche gemacht, aber was ich gefunden habe, sprach nicht über RSA .. – neubert

+0

"Google-Identität" war nur das nächste Etikett, das ich dafür finden konnte. Besser, aber nicht existent wäre "google-token" oder "google-idtoken". Ich werde nach Unterlagen suchen. – DMT

+0

Die einzige Dokumentation, die ich finde, ist veraltet (daher die Frage an erster Stelle), aber es sollte erklären, wonach ich suche. (https://developers.google.com/identity/protocols/CrossClientAuth), (http://android-developers.blogspot.com/2016/01/using-google-sign-in-with-your-server.html), und (http://www.riskcompletefailure.com/2013/11/client-server-authentication-with-id.html) alle geben Stücke von, was ich suche, aber nichts verwendbares für meinen PHP-Service zZ. – DMT

Antwort

0

Das Problem ist, dass Sie nicht base64-Decodierung etwas relevant.

Das ist für mich gearbeitet (sagte mir, dass die Signatur gültig war):

<?php 
include('Crypt/RSA.php'); 

$data = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjZjNzgxOTQyZDg0OWJhMmVjZGE4Y2VkYjcyZDM0MzU3ZmM5NWIzMjcifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIxMDQ5MTQ4MTU2NTQ2LTk2YjFxcTJsNTJtODVtODB0ZHVoZHVma2RwODRtN2tuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTEyNTk4NDgzNjQ2MjY1OTYxNTQwIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF6cCI6IjEwNDkxNDgxNTY1NDYtdjJwZjRlbGhzOGNwcXBlcWZkMzU5am5nOWs5aW5kcTQuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6InRlc3R1c2VydGh4QGdtYWlsLmNvbSIsImlhdCI6MTQ3NDc1NDMzMiwiZXhwIjoxNDc0NzU3OTMyLCJuYW1lIjoiVGVzdCBVc2VyIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tU0dldkZZRDlaWFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQVBhWEhoUmtuX1hEaEhNLTEzeVMwTUtBcFNrZG1zVEdYdy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiVGVzdCIsImZhbWlseV9uYW1lIjoiVXNlciIsImxvY2FsZSI6ImVuIn0'; 
$signature = 'btukbBvhek6w14CrBVTGs8X9_IXIHZKpV1NzJ3OgbGUfmoRMirNGzZiFAgrR7COTeDJTamxRzojxxmXx6EEkQqNQcbyN8dO0PTuNt9pujQjLbFw_HBhIFJQaJSR3-tYPN-UtHGQ5JAAySsvCPapXbxyiKzTyvGYRSU65LmyNuiGxe6RQe1zHjq2ABJ4IPRqKPuFupnGRPWYyBSTPU7XQvtfhgyqA0BWZUfmCIFyDxQhvMaXNLTs01gnGVhcUDWZLi9vuUiKUlz3-aSSbwdfCMAljhBHnjpYO6341k5-qmgKkWawv8DX_nMEzntsCMCr664rP4wFEbsRB5ledM9Pc9Q'; 
$signature = str_replace(['-','_'], ['+','/'], $signature); 
$signature = base64_decode($signature); 

$n = 's1dt5wFFaYl-Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ-b-oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG_CfmewNVwBXPFx8-mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9-WAEZ1q8wq-I93Sfte95RaFjDqCH--Sh-8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ'; 
$n = str_replace(['-','_'], ['+','/'], $n); 
$n = base64_decode($n); 

$e = 'AQAB'; 
$e = base64_decode($e); 

$rsa = new Crypt_RSA(); 
$rsa->loadKey([ 
    'n' => new Math_BigInteger($n, 256), 
    'e' => new Math_BigInteger($e, 256) 
]); 

$rsa->setHash('sha256'); 
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); 

echo $rsa->verify($data, $signature) ? 
    'valid' : 
    'invalid'; 
+0

OMG. Also habe ich vergessen, einen base64_decode auf dem Mod und Exp zu machen, auch nachdem ich sie in meiner Ausgabe als solche gekennzeichnet habe. Seufzer. Ich wusste, dass es etwas Dummes wäre. Vielen Dank. – DMT

1

Also für jedermann hier von Suchmaschinen kommen: zu überprüfen

Ich habe versucht, eine Google-ID-Token zu verwenden, die meine Login-Daten waren:
Genaue
nicht spoofed
Able von einem back-End-Server
Computed mit Mathematik überprüft werden, damit ich Google nicht jedes Mal (Hinzufügen Latenz abfragen und ich weiß, dass die meisten sicherlich diesen Code lesen können, aber ich wollte es eingeben, um zu erklären, was für die nächste verärgerte Seele passiert .

Ihr erster Teil kann variieren, da ich von Android kam und von dort ziemlich geradlinig ist.

Mein Prozess war um das Token in Android zu fragen. (Es werden nur Unterschiede von Beispielen und relevante Stücke gezeigt)

 GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 
     .requestIdToken(getString(R.string.client_id)) 
     .requestEmail() 
     .build(); 

Erste das Token von der Tätigkeit Ergebnis (onActivityResult)

 GoogleSignInAccount acct = result.getSignInAccount(); 
    String idToken = acct.getIdToken();

Das Token aus 3 Teilen zusammengesetzt ist, die durch Punkte getrennt sind, in Form "$ Header. $ info. $ Signatur". Wir werden "$ header. $ Info" mit "$ signature" verifizieren, um dies zu tun.

Die $ Header enthält Informationen über die Verschlüsselung, zum Beispiel (nach der Decodierung):

{"alg":"RS256","kid":"6c781942d849ba2ecda8cedb72d34357fc95b327"}

So ist der verwendete Algorithmus ist "SHA-256, mit RSA-Verschlüsselung" und der Schlüssel-ID in dem Schlüsselspeicher ist 6c781942d849ba2ecda8cedb72d34357fc95b327. Wir werden das später verwenden.

Pass die gesamten Token an meinem Back-End-Server über HTTP

Dann das Token dekodieren den folgenden Code verwenden, genommen direkt aus der akzeptierten Antwort

include('Crypt/RSA.php'); //path to phpseclib 

$modulus = ""; 
$exponent = ""; 
$token = $_POST['token']; 
$pieces = explode(".", $token); 

$data = $pieces[0].".".$pieces[1]; 
$signature = base64_decode(str_replace(['-','_'], ['+','/'], $pieces[2])); 

$header = json_decode(base64_decode(str_replace(['-','_'], ['+','/'], $pieces[0])), true); 
$alg = $header['alg']; 
$kid = $header['kid']; 

if (testGoogleList($alg, $kid, $modulus, $exponent)) 
{ 
    $modulus = base64_decode(str_replace(['-','_'], ['+','/'], $modulus)); 
    $exponent = base64_decode(str_replace(['-','_'], ['+','/'], $exponent)); 

    $rsa = new Crypt_RSA(); 
    $rsa->loadKey([ 
     'n' => new Math_BigInteger($modulus, 256), 
     'e' => new Math_BigInteger($exponent, 256) 
    ]); 

    $rsa->setHash('sha256'); 
    $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); 

    if ($rsa->verify($data, $signature)) 
    { 
     echo "VALID!!!!"; 
    } else { 
     echo "NOT VALID :'("; 
    } 
} 

Der Grund, warum wir base64_decode(str_replace(['-','_'], ['+','/'], $VARIABLE)) weil diese tun ist werden in der Form base64URL dargestellt, wobei das '+' in ein '-' geändert wird und das '/' in ein '_' geändert wird. Also ändern wir es von base64URL> base64> uncodierten (einfachen) Text.

Was macht das?

  • Wir nehmen das Token von $ _POST (ich nannte es $ Token).
  • Dann teilen wir es in seine Teile.
  • Denken Sie daran, wir müssen den dritten Teil verwenden, um das Paar der ersten beiden zu entschlüsseln, getrennt durch einen Punkt ("."). ("$ signature" ist die kryptografische Signatur für "$ header. $ info")
  • Entschlüsseln Sie die Signatur vollständig, von base64URL bis zum unverschlüsselten Text. Da Google JSON zum Speichern der Schlüsselinformationen verwendet, deklariert json_decode den Header und erhält den Verschlüsselungstyp und die Schlüssel-ID.
  • Ich wickelte es in eine Funktion, aber meine Funktion testGoogleList funktioniert im Prinzip wie folgt aus:

    1. So gehen wir in den Algorithmus und der Schlüssel-ID.
    2. Ich teste meinen lokalen Cache von Schlüsseln, um zu sehen, ob der Schlüssel, den wir brauchen, bereits zwischengespeichert ist.
    3. Wenn nicht, fahren wir hier, sonst voraus 4.

      • Dann zu Schritt überspringen wir die Web-Hit und greifen Googles Open-ID-Konfigurationsseite an (https://accounts.google.com/.well-known/openid-configuration) mit get_file_contents() oder eine CURL Methode, wenn du kannst nicht. Ich musste CURL mit den Optionen "curl_setopt ($ ch, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE)" verwenden; in meiner CURL-Methode, da es HTTPS nicht richtig versuchte.
      • Diese Seite ist eine JSON-codierte Textdatei, also json_decode es.
      • Wir sie greifen den "jwks_uri" Schlüssel und greifen diese Seite wie wir oben.
      • Diese enthält eine Reihe von Schlüsseln, die Google derzeit für die Verifizierung öffentlicher Schlüssel verwendet. Ich json_decode und vorübergehend diese in einem Array speichern.
      • Kürzen Sie Ihren alten Cache und schreiben Sie den Satz neu. Vergiss nicht zu strömen() im Falle eines wirklich schlechten Timings.
      • Stellen Sie sicher, dass Ihr Schlüssel im neuen Satz ist.
    4. Wenn wir den Schlüssel in unserem Cache finden, extrahieren wir die „n“ (wir nennen dies das ‚Modul‘) und „e“ (‚Exponent‘) Stücke von ihm und diejenigen zurückzugeben.

  • Dann entschlüsseln wir die Modul und Exponent Stücke aus base64URL> base64> unverschlüsselt (plain) Text.

  • Erstellen Sie eine neue Instanz der Klasse Crypt_RSA.
  • Laden Sie die Nummern, die Sie gerade entschlüsselt haben, als neuen Schlüssel in die Klasse mit den Math_BigInteger-Typen, damit wir die Zahlen für Riesen berechnen können. (das zweite Argument ist Base, also ist Base 256 ein Byte, wenn wir mit BIG-Ganzzahlen arbeiten, verwenden Sie diese)
  • Setzen Sie unseren Hash- und Signaturmodus so, dass er dem entspricht, was wir von Google haben.
  • Führen Sie die Überprüfung durch, um sicherzustellen, dass wir einen gültigen Schlüssel haben.

Danach ist es an Ihnen, was Sie damit machen.

Danke noch einmal, neubert, für die Hilfe!

Verwandte Themen