L'API Google Pay restituisce i metodi di pagamento in un payload PaymentMethodToken firmato e criptato. I metodi di pagamento restituiti sono carte che
sono costituite da PAN o carte tokenizzate costituite da PAN del dispositivo e crittogrammi.
Il payload contiene un campo denominato protocolVersion che indica al destinatario del payload quali primitive crittografiche sono in uso e il formato previsto.
Questa guida fornisce informazioni su come generare una chiave pubblica per richiedere un token del metodo di pagamento criptato e firmato da Google e descrive in dettaglio i passaggi da seguire per verificare e decriptare il token.
Questa guida si applica solo a protocolVersion = ECv2.
Poiché ricevi direttamente i dati della carta di pagamento, assicurati che la tua app sia conforme allo standard PCI DSS e che i tuoi server dispongano dell'infrastruttura necessaria per gestire in sicurezza le credenziali di pagamento dell'utente prima di procedere.
I passaggi seguenti descrivono ciò che un integratore deve fare per utilizzare il payload dell'API Google Pay
ECv2 PaymentMethodToken:
- Recupera le chiavi di firma radice di Google.
- Verifica che la firma della chiave di firma intermedia sia valida per una qualsiasi delle chiavi di firma radice non scadute.
- Verifica che la chiave di firma intermedia del payload non sia scaduta.
- Verifica che la firma del payload sia valida in base alla chiave di firma intermedia.
- Decripta i contenuti del payload dopo aver verificato la firma.
- Verifica che il messaggio non sia scaduto. A questo scopo, devi verificare che l'ora corrente sia precedente al campo
messageExpirationnei contenuti decriptati. - Utilizza il metodo di pagamento nei contenuti decriptati e addebita l'importo.
Il codice campione nella nostra libreria Tink esegue i passaggi da 1 a 6.
Struttura del token del metodo di pagamento
Il messaggio restituito da Google nella risposta PaymentData è un oggetto JSON serializzato con codifica UTF-8 con le chiavi specificate nella tabella seguente:
| Nome | Tipo | Descrizione |
|---|---|---|
protocolVersion |
Stringa | Identifica lo schema di crittografia o firma con cui viene creato il messaggio. Consente al protocollo di evolversi nel tempo, se necessario. |
signature |
Stringa | Verifica che il messaggio provenga da Google. È codificata in base64 e creata con ECDSA dalla chiave di firma intermedia. |
intermediateSigningKey |
Oggetto | Un oggetto JSON contenente la chiave di firma intermedia di Google. Contiene
signedKey con keyValue, keyExpiration e
signatures. Viene serializzato per semplificare la procedura di verifica della firma della chiave di firma intermedia. |
signedMessage |
Stringa | Un oggetto JSON serializzato come stringa sicura per HTML che contiene encryptedMessage, ephemeralPublicKey e tag. Viene serializzato per semplificare la procedura di verifica della firma. |
Esempio
Di seguito è riportata una risposta del token del metodo di pagamento in JSON:
{ "protocolVersion":"ECv2", "signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d", "intermediateSigningKey":{ "signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}", "signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"] }, "signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}" }
Chiave di firma intermedia
intermediateSigningKey è un oggetto JSON serializzato con codifica UTF-8 che contiene i seguenti valori:
| Nome | Tipo | Descrizione |
|---|---|---|
signedKey |
Stringa | Un messaggio con codifica in base64 che contiene la descrizione del pagamento della chiave. |
signatures |
Stringa | Verifica che la chiave di firma intermedia provenga da Google. È codificata in base64 e creata con ECDSA. |
Chiave firmata
signedKey è un oggetto JSON serializzato con codifica UTF-8 che contiene i seguenti valori:
| Nome | Tipo | Descrizione |
|---|---|---|
keyValue |
Stringa | Una versione base64 della chiave codificata nel tipo ASN.1. SubjectPublicKeyInfo è definito nello standard X.509. |
keyExpiration |
Stringa | Data e ora di scadenza della chiave intermedia in millisecondi UTC dall'epoca. Gli integratori rifiutano qualsiasi chiave scaduta. |
Messaggio firmato
signedMessage è un oggetto JSON serializzato con codifica UTF-8 che contiene i seguenti valori:
| Nome | Tipo | Descrizione |
|---|---|---|
encryptedMessage |
Stringa | Un messaggio criptato con codifica base64 che contiene i dati di pagamento e alcuni campi di sicurezza aggiuntivi. |
ephemeralPublicKey |
Stringa | Una chiave pubblica temporanea con codifica Base64 associata alla chiave privata per criptare il messaggio in formato punto non compresso. Per saperne di più, consulta Formato della chiave pubblica di crittografia. |
tag |
Stringa | Un MAC con codifica base64 di encryptedMessage. |
Messaggio criptato
Il encryptedMessage decriptato è un oggetto JSON serializzato con codifica UTF-8. Il JSON contiene due livelli. Il livello esterno contiene metadati e campi inclusi per motivi di sicurezza, mentre il livello interno è un altro oggetto JSON che rappresenta la credenziale di pagamento effettiva.
Per maggiori dettagli su encryptedMessage, consulta le seguenti tabelle ed esempi di oggetti JSON:
| Nome | Tipo | Descrizione |
|---|---|---|
messageExpiration |
Stringa | Data e ora di scadenza del messaggio in millisecondi UTC dall'epoca. Gli integratori devono rifiutare qualsiasi messaggio scaduto. |
messageId |
Stringa | Un ID univoco che identifica il messaggio nel caso in cui debba essere revocato o individuato in un secondo momento. |
paymentMethod |
Stringa | Il tipo di credenziale di pagamento.
Al momento è supportato solo CARD.
|
paymentMethodDetails |
Oggetto | La credenziale di pagamento stessa. Il formato di questo oggetto è determinato da
paymentMethod ed è descritto nelle tabelle seguenti. |
Carta
Le seguenti proprietà costituiscono una credenziale di pagamento per il metodo di pagamento CARD:
| Nome | Tipo | Descrizione |
|---|---|---|
pan |
Stringa | Il numero di conto bancario personale addebitato. Questa stringa contiene solo cifre. |
expirationMonth |
Numero | Il mese di scadenza della carta, dove 1 rappresenta gennaio, 2 rappresenta febbraio e così via. |
expirationYear |
Numero | L'anno di scadenza della carta, composto da quattro cifre, ad esempio 2020. |
authMethod |
Stringa | Il metodo di autenticazione della transazione con carta. |
merchantTokenId |
Stringa | L'ID token commerciante della transazione con carta. Questo campo facoltativo viene restituito solo se sono soddisfatte tutte le seguenti condizioni:
|
PAN_ONLY
Il seguente snippet JSON è un esempio della encryptedMessage completa per un CARD paymentMethod
con un PAN_ONLY authMethod.
{ "paymentMethod": "CARD", "paymentMethodDetails": { "authMethod": "PAN_ONLY", "pan": "1111222233334444", "expirationMonth": 10, "expirationYear": 2025 }, "gatewayMerchantId": "some-merchant-id", "messageId": "some-message-id", "messageExpiration": "1759309000000" }
CRYPTOGRAM_3DS
Un CARD autenticato con l'utilizzo di un crittogramma 3-D Secure,
CRYPTOGRAM_3DS authMethod. Include i seguenti campi aggiuntivi:
| Nome | Tipo | Descrizione |
|---|---|---|
cryptogram |
Stringa | Un crittogramma 3-D Secure. |
eciIndicator |
Stringa | Questa stringa non è sempre presente. Viene restituito solo per le transazioni con token del dispositivo autenticato su Android (CRYPTOGRAM_3DS). Questo valore deve essere trasmesso lungo il flusso di elaborazione dei pagamenti. |
Il seguente snippet JSON è un esempio di encryptedMessage completo per un paymentMethod CARD con un authMethod CRYPTOGRAM_3DS:
{
"paymentMethod": "CARD",
"paymentMethodDetails": {
"authMethod": "CRYPTOGRAM_3DS",
"pan": "1111222233334444",
"expirationMonth": 10,
"expirationYear": 2025,
"cryptogram": "AAAAAA...",
"eciIndicator": "eci indicator",
"merchantTokenId": "merchant-token-id",
},
"messageId": "some-message-id",
"messageExpiration": "1759309000000"
}eciIndicator
Il circuito della carta potrebbe fornire il eciIndicator per le transazioni con token del dispositivo autenticato (CRYPTOGRAM_3DS).
Devi trasmettere il valore eciIndicator nella transazione di autorizzazione senza che venga modificato o impostato come hardcoded, altrimenti la transazione non andrà a buon fine. La tabella seguente descrive i valori di eciIndicator.
| Valore eciIndicator | Circuito della carta | Parte responsabile | authMethod |
|---|---|---|---|
""(empty) |
Mastercard | Commerciante/Acquirente | CRYPTOGRAM_3DS |
02 |
Mastercard | Emittente della carta | CRYPTOGRAM_3DS |
06 |
Mastercard | Commerciante/Acquirente | CRYPTOGRAM_3DS |
05 |
Visa | Emittente della carta | CRYPTOGRAM_3DS |
07 |
Visa | Commerciante/Acquirente | CRYPTOGRAM_3DS |
""(empty) |
Altre reti | Commerciante/Acquirente | CRYPTOGRAM_3DS |
Eventuali altri valori ECI per VISA e Mastercard non presenti in questa tabella non verranno restituiti.
Verifica della firma
Per verificare le firme, che includono le firme della chiave intermedia e del messaggio, sono necessari i seguenti elementi:
- L'algoritmo utilizzato per creare la firma
- La stringa di byte utilizzata per creare la firma
- La chiave pubblica corrispondente alla chiave privata utilizzata per creare la firma
- La firma stessa
L'algoritmo di firma
Google utilizza l'algoritmo ECDSA (Elliptic Curve Digital Signature Algorithm) per firmare i messaggi con i seguenti parametri: ECDSA su NIST P-256 con SHA-256 come funzione hash, come definito in FIPS 186-4.
La firma
La firma è inclusa nel livello più esterno del messaggio. È codificata con base64 in formato byte ASN.1. Per saperne di più su ASN.1, consulta l'Appendice A di IETF Tools. La firma è costituita dai numeri interi r e s ECDSA. Per ulteriori informazioni, consulta la sezione Algoritmo di generazione della firma.
Di seguito è riportato un esempio del formato di byte ASN.1 specificato, che è il formato standard prodotto dalle implementazioni ECDSA di Java Cryptography Extension (JCE).
ECDSA-Sig-Value :: = SEQUENCE {
r INTEGER,
s INTEGER
}Come creare la stringa di byte per la firma della chiave di firma intermedia
Per convalidare la firma della chiave di firma intermedia nel token del metodo di pagamento di esempio, crea
signedStringForIntermediateSigningKeySignature con la seguente formula:
signedStringForIntermediateSigningKeySignature = length_of_sender_id || sender_id || length_of_protocol_version || protocol_version || length_of_signed_key || signed_key
La notazione "||" indica la concatenazione. Ogni componente (sender_id, protocolVersion, signedKey) deve essere codificato in UTF-8. signedKey deve essere la stringa di intermediateSigningKey.signedKey.
La lunghezza in byte di ogni componente è di 4 byte in formato little-endian.
Esempio
Questo esempio utilizza il seguente token del metodo di pagamento di esempio:
{
"protocolVersion":"ECv2",
"signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
"intermediateSigningKey":{
"signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
"signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
},
"signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}sender_id è sempre Google e protocol_version è ECv2.
Se sender_id è Google, signedString viene visualizzato come mostrato nell'esempio seguente:
signedStringForIntermediateSigningKeySignature =
\x06\x00\x00\x00 || Google || | \x04\x00\x00\x00 || ECv2 || \xb5\x00\x00\x00 || {"keyExpiration":"1542323393147","keyValue":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\u003d\u003d"}Come verificare la firma su signedStringForIntermediateSigningKeySignature
L'algoritmo di verifica ECDSA standard viene utilizzato quando viene assemblata la stringa firmata per la firma della chiave di firma intermedia. Per il protocollo ECv2, devi eseguire l'iterazione di tutte le firme in intermediateSigningKey.signatures e provare a convalidare ciascuna con le chiavi di firma di Google non scadute in keys.json. Se almeno una convalida della firma funziona, considera la verifica completata. Utilizza
intermediateSigningKey.signedKey.keyValue in un secondo momento per verificare
signedStringForMessageSignature. Google consiglia vivamente di utilizzare una libreria crittografica esistente anziché il tuo codice di verifica.
Come creare la stringa di byte per la firma del messaggio
Per convalidare la firma nel token del metodo di pagamento di esempio, crea il signedStringForMessageSignature con la seguente formula:
signedStringForMessageSignature = length_of_sender_id || sender_id || length_of_recipient_id || recipient_id || length_of_protocolVersion || protocolVersion || length_of_signedMessage || signedMessage
La notazione "||" indica la concatenazione. Ogni componente (sender_id, recipient_id, protocolVersion, signedMessage) deve essere codificato in UTF-8. La lunghezza in byte di ogni componente è di 4 byte in formato little-endian. Quando crei la stringa di byte, non analizzare o modificare signedMessage. Ad esempio, non sostituire \u003d con il carattere =.
Esempio
Di seguito è riportato un esempio di token del metodo di pagamento:
{
"protocolVersion":"ECv2",
"signature":"MEQCIH6Q4OwQ0jAceFEkGF0JID6sJNXxOEi4r+mA7biRxqBQAiAondqoUpU/bdsrAOpZIsrHQS9nwiiNwOrr24RyPeHA0Q\u003d\u003d",
"intermediateSigningKey":{
"signedKey": "{\"keyExpiration\":\"1542323393147\",\"keyValue\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/1+3HBVSbdv+j7NaArdgMyoSAM43yRydzqdg1TxodSzA96Dj4Mc1EiKroxxunavVIvdxGnJeFViTzFvzFRxyCw\\u003d\\u003d\"}",
"signatures": ["MEYCIQCO2EIi48s8VTH+ilMEpoXLFfkxAwHjfPSCVED/QDSHmQIhALLJmrUlNAY8hDQRV/y1iKZGsWpeNmIP+z+tCQHQxP0v"]
},
"signedMessage":"{\"tag\":\"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\\u003d\",\"ephemeralPublicKey\":\"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\\u003d\",\"encryptedMessage\":\"mKOoXwi8OavZ\"}"
}sender_id è sempre Google e recipient_id è merchant:merchantId. merchantId corrisponde al valore trovato nella Console di Google Pay e Wallet per i commercianti con accesso in produzione.
Se sender_id è Google e recipient_id è merchant:12345, signedString viene visualizzato come nell'esempio seguente:
signedStringForMessageSignature =
\x06\x00\x00\x00 || Google || \x0e\x00\x00\x00 || merchant:12345 || | \x04\x00\x00\x00 || ECv2 || \xd2\x00\x00\x00 || {"tag":"jpGz1F1Bcoi/fCNxI9n7Qrsw7i7KHrGtTf3NrRclt+U\u003d","ephemeralPublicKey":"BJatyFvFPPD21l8/uLP46Ta1hsKHndf8Z+tAgk+DEPQgYTkhHy19cF3h/bXs0tWTmZtnNm+vlVrKbRU9K8+7cZs\u003d","encryptedMessage":"mKOoXwi8OavZ"}Come verificare la firma su signedStringForMessageSignature
L'algoritmo di verifica ECDSA standard viene utilizzato quando viene assemblata la stringa firmata. Il intermediateSigningKey.signedKey.keyValue verificato nel passaggio precedente viene utilizzato per verificare il signedMessage. Google consiglia vivamente di utilizzare una libreria crittografica esistente anziché il tuo codice di verifica.
Specifica dello schema di crittografia
Google utilizza l'Elliptic Curve Integrated Encryption Scheme (ECIES) per proteggere il token del metodo di pagamento restituito nella risposta dell'API Google Pay. Lo schema di crittografia utilizza i seguenti parametri:
| Parametro | Definizione |
|---|---|
| Metodo di incapsulamento chiave | ECIES-KEM, come definito in ISO 18033-2.
|
| Funzione di derivazione della chiave | Basato su HMAC con SHA-256 (
|
| Algoritmo crittografico simmetrico |
DEM2, come definito in ISO 18033-2 Algoritmo crittografico: AES-256-CTR con IV zero e senza spaziatura interna. |
| Algoritmo MAC | HMAC_SHA256 con una chiave a 256 bit derivata dalla funzione di derivazione della chiave. |
Formato della chiave pubblica di crittografia
La chiave pubblica di crittografia e il ephemeralPublicKey restituito nei payload di Google sono formattati con la rappresentazione base64 della chiave in formato punto non compresso. È composto dai seguenti due elementi:
- Un numero magico che specifica il formato (0x04).
- Due numeri interi di 32 byte che rappresentano le coordinate X e Y nella curva ellittica.
Questo formato è descritto in modo più dettagliato in "Public Key Cryptography For The Financial Services Industry: The Elliptic Curve Digital Signature Algorithm (ECDSA)", ANSI X9.62, 1998.
Utilizza OpenSSL per generare una chiave pubblica
Passaggio 1: genera una chiave privata
L'esempio seguente genera una chiave privata a curva ellittica adatta per l'utilizzo con NIST P-256 e la scrive in key.pem:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem
(Facoltativo) Visualizza le chiavi private e pubbliche
Utilizza il seguente comando per visualizzare sia la chiave privata che quella pubblica:
openssl ec -in key.pem -pubout -text -noout
Il comando produce un output simile al seguente:
read EC key
Private-Key: (256 bit)
priv:
08:f4:ae:16:be:22:48:86:90:a6:b8:e3:72:11:cf:
c8:3b:b6:35:71:5e:d2:f0:c1:a1:3a:4f:91:86:8a:
f5:d7
pub:
04:e7:68:5c:ff:bd:02:ae:3b:dd:29:c6:c2:0d:c9:
53:56:a2:36:9b:1d:f6:f1:f6:a2:09:ea:e0:fb:43:
b6:52:c6:6b:72:a3:f1:33:df:fa:36:90:34:fc:83:
4a:48:77:25:48:62:4b:42:b2:ae:b9:56:84:08:0d:
64:a1:d8:17:66
ASN1 OID: prime256v1
Passaggio 2: genera una chiave pubblica con codifica Base64
La chiave privata e quella pubblica generate nell'esempio del passaggio facoltativo precedente sono codificate in formato esadecimale. Per ottenere una chiave pubblica con codifica base64 in formato punto non compresso, utilizza il seguente comando:
openssl ec -in key.pem -pubout -text -noout 2> /dev/null | grep "pub:" -A5 | sed 1d | xxd -r -p | base64 | paste -sd "\0" - | tr -d '\n\r ' > publicKey.txt
Il comando produce un file publicKey.txt il cui contenuto, la versione base64 della chiave in formato punto non compresso, è simile al seguente:
BOdoXP+9Aq473SnGwg3JU1aiNpsd9vH2ognq4PtDtlLGa3Kj8TPf+jaQNPyDSkh3JUhiS0KyrrlWhAgNZKHYF2Y=
I contenuti del file non devono contenere spazi vuoti o ritorni a capo aggiuntivi. Per verificarlo, esegui questo comando in Linux o MacOS:
od -bc publicKey.txt
Passaggio 3: genera una chiave privata con codifica base64 in formato PKCS #8
La libreria Tink prevede che la chiave privata sia codificata in base64 nel formato PKCS #8. Utilizza il seguente comando per generare la chiave privata in questo formato dalla chiave privata generata nel primo passaggio:
openssl pkcs8 -topk8 -inform PEM -outform DER -in key.pem -nocrypt | base64 | paste -sd "\0" -
Il comando produce un output simile al seguente:
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWV4oK8c/MZkCLk4qSCNjW0Zm6H0CBCtSYxkXkC9FBHehRANCAAQPldOnhO2/oXjdJD1dwlFPiNs6fcdoRgFu3/Z0iKj24SjTGyLRGAtYWLGXBZcDdPj3T2bJRHRVhE8Bc2AjkT7n
Come decriptare il token del metodo di pagamento
Per decriptare il token:
- Utilizza la tua chiave privata e il
ephemeralPublicKeyfornito per ricavare una chiave condivisa di 512 bit che utilizza ECIES-KEM. Utilizza i seguenti parametri: - Curva ellittica: NIST P-256, nota anche in OpenSSL come prime256v1.
CheckMode,OldCofactorMode,SingleHashModeeCofactorModesono0.- Funzione di codifica: formato punto non compresso.
- Funzione di derivazione della chiave: HKDFwithSHA256, come descritto in RFC 5869, con il seguente parametro:
- Il salt non deve essere fornito. In base all'RFC, questo deve essere equivalente a un salt di 32 byte azzerati.
- Suddividi la chiave generata in due chiavi da 256 bit:
symmetricEncryptionKeyemacKey. Verifica che il campo
tagsia un MAC valido perencryptedMessage.Per generare il MAC previsto, utilizza HMAC (RFC 5869) con la funzione hash SHA256 e la
macKeyottenuta nel passaggio 2.Decripta
encryptedMessageutilizzando la modalità AES-256-CTR e quanto segue:- Un IV pari a zero.
- Senza spaziatura interna.
- Il valore
symmetricEncryptionKeyricavato nel passaggio 2.
Gestione delle chiavi
Chiavi di crittografia del commerciante
I commercianti generano una chiave pubblica in base alle specifiche descritte in Specifiche dello schema di crittografia.
Chiavi di firma radice di Google
Google pubblica l'insieme di chiavi pubbliche di firma radice attualmente valide, che possono essere recuperate da un URL pubblico. Le chiavi sono valide per il periodo di tempo indicato dalle intestazioni della cache HTTP restituite dall'URL. Vengono memorizzate nella cache fino alla scadenza, determinata dal campo keyExpiration. Quando un recupero scade, ti consigliamo di recuperare nuovamente le chiavi dall'URL pubblico per ricevere l'elenco corrente delle chiavi valide.
Eccezione per il protocollo ECv2: se non riesci a recuperare le chiavi da Google in fase di runtime, recupera la chiave keys.json dal nostro URL di produzione, salvala nel tuo sistema e aggiornala periodicamente manualmente. In circostanze normali, Google emette una nuova chiave di firma root per ECv2 cinque anni prima della scadenza della chiave con la data di scadenza più lunga. In caso di compromissione delle chiavi, Google
invia una notifica a tutti i commercianti tramite i dati di contatto forniti nel portale self-service per
richiedere un ricaricamento più rapido di keys.json. Per assicurarti di non perdere la rotazione regolare, consigliamo ai commercianti che scelgono di salvare le chiavi Google nei contenuti di keys.json di aggiornarle annualmente nell'ambito della propria rotazione annuale delle chiavi.
Le chiavi fornite tramite l'URL pubblico vengono mappate nel seguente formato:
{ "keys": [ { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"2000000000000" }, { "keyValue": "encoded public key", "protocolVersion": "ECv2" "keyExpiration":"3000000000000" } ] }
keyValue è una versione base64, non sottoposta a wrapping o padding, della chiave codificata nel tipo ASN.1 SubjectPublicKeyInfo definito nello standard X.509. In Java, la codifica ASN.1 a cui si fa riferimento è rappresentata dalla classe X509EncodedKeySpec.
Può essere ottenuto con ECPublicKey.getEncoded().
Gli URL per gli ambienti di test e di produzione sono forniti dai seguenti link:
- Test:
https://payments.developers.google.com/paymentmethodtoken/test/keys.json - Produzione:
https://payments.developers.google.com/paymentmethodtoken/keys.json
Rotazione delle chiavi
Se decripti un token del metodo di pagamento direttamente sui tuoi server con l'integrazione diretta, devi ruotare le chiavi ogni anno.
Per ruotare le chiavi di crittografia, completa i seguenti passaggi:
- Utilizza OpenSSL per generare una nuova coppia di chiavi.
- Apri la Google Pay & Wallet Console dopo aver eseguito l'accesso con l'Account Google che hai utilizzato in precedenza per registrarti come sviluppatore per Google Pay.
- Nella scheda API Google Pay, nel riquadro Integrazione diretta, fai clic su Gestisci accanto alla tua chiave pubblica esistente. Fai clic su Aggiungi un'altra chiave.
- Seleziona il campo di immissione di testo Chiave di crittografia pubblica e aggiungi la chiave pubblica appena generata con codifica Base64 in formato punto non compresso.
- Fai clic su Salva chiavi di crittografia.
Per garantire una rotazione delle chiavi senza problemi, supporta la decriptazione delle chiavi private nuove e precedenti durante la transizione delle chiavi.
Se utilizzi la libreria Tink per decriptare il token, utilizza il seguente codice Java per supportare più chiavi private:
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addRecipientPrivateKey(newPrivateKey) .addRecipientPrivateKey(oldPrivateKey);
Assicurati che il codice per la decriptazione sia stato implementato in produzione e monitora le decriptazioni riuscite.
Modifica la chiave pubblica utilizzata nel codice.
Sostituisci il valore dell'attributo
publicKeynella proprietàPaymentMethodTokenizationSpecificationparameters:const tokenizationSpecification = { "type": "DIRECT", "parameters": { "protocolVersion": "ECv2", "publicKey": "BOdoXP1aiNp.....kh3JUhiSZKHYF2Y=" } }
- Esegui il deployment del codice del passaggio 4 in produzione. Una volta eseguito il deployment del codice, le transazioni di crittografia e decriptazione utilizzano le nuove coppie di chiavi.
Conferma che la vecchia chiave pubblica non viene più utilizzata per criptare le transazioni.
- Rimuovi la vecchia chiave privata.
- Apri Google Pay & Wallet Console dopo aver eseguito l'accesso con l'Account Google che hai utilizzato in precedenza per registrarti come sviluppatore con Google Pay.
- Nella scheda API Google Pay, nel riquadro Integrazione diretta, fai clic su Gestisci accanto alla chiave pubblica esistente. Fai clic su Elimina accanto alla chiave pubblica precedente e poi su Salva chiavi di crittografia.
Google utilizza la chiave specificata nella proprietà publicKey all'interno dell'oggetto PaymentMethodTokenizationSpecification parameters, come mostrato nell'esempio seguente:
{
"protocolVersion": "ECv2",
"publicKey": "BOdoXP+9Aq473SnGwg3JU1..."
}Utilizza la libreria Tink per gestire la risposta criptata
Per eseguire la verifica della firma e la decrittografia dei messaggi, utilizza la libreria Tink paymentmethodtoken. Questa libreria è disponibile solo in Java. Per utilizzarla, segui questi passaggi:
Nel file
pom.xml, aggiungi l'app Tinkpaymentmethodtokencome dipendenza:<dependencies> <!-- other dependencies ... --> <dependency> <groupId>com.google.crypto.tink</groupId> <artifactId>apps-paymentmethodtoken</artifactId> <version>1.9.1</version> <!-- or latest version --> </dependency> </dependencies>All'avvio del server, esegui il precaricamento delle chiavi di firma di Google per renderle disponibili in memoria. In questo modo, l'utente non visualizza alcuna latenza di rete mentre il processo di decrittografia recupera le chiavi.
GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION.refreshInBackground();
Decripta il messaggio con il seguente codice, che presuppone che
paymentMethodTokensia archiviato nella variabileencryptedMessage, e sostituisci le sezioni in grassetto in base al tuo scenario.Per i test non di produzione, sostituisci
INSTANCE_PRODUCTIONconINSTANCE_TESTe, se l'integrazione non è attiva o non ha una chiave di crittografia configurata, sostituisci [YOUR MERCHANT ID] con12345678901234567890.- Attivo
- Integrazione DIRETTA abilitata
- Ha una chiave di crittografia configurata
non sostituire [YOUR MERCHANT ID].
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .fetchSenderVerifyingKeysWith( GooglePaymentsPublicKeysManager.INSTANCE_PRODUCTION) .recipientId("merchant:[YOUR MERCHANT ID]") // This guide applies only to protocolVersion = ECv2 .protocolVersion("ECv2") // Multiple private keys can be added to support graceful // key rotations. .addRecipientPrivateKey(PrivateKey1) .addRecipientPrivateKey(PrivateKey2) .build() .unseal(encryptedMessage);
Sostituisci
PrivateKey1con il valore della chiave privata appropriato che si associa al valore della chiave pubblica registrata con Google in Prepara le chiavi e registrati con Google. In un secondo momento, puoi aggiungere più valori di chiavi private quando ti viene richiesto di ruotare le chiavi con Google. Le variabili possono essere una stringa PKCS8 con codifica in base64 o un oggettoECPrivateKey. Per saperne di più su come generare una chiave privata PKCS8 con codifica base64, consulta Prepara le chiavi ed esegui la registrazione con Google.Se non riesci a chiamare un server di Google ogni volta che decripti le chiavi, decriptale con il seguente codice e sostituisci le sezioni in grassetto in base al tuo scenario.
String decryptedMessage = new PaymentMethodTokenRecipient.Builder() .addSenderVerifyingKey("ECv2 key fetched from test or production url") .recipientId("merchant:[YOUR MERCHANT ID]") // This guide applies only to protocolVersion = ECv2 .protocolVersion("ECv2") // Multiple private keys can be added to support graceful // key rotations. .addRecipientPrivateKey(PrivateKey1) .addRecipientPrivateKey(PrivateKey2) .build() .unseal(encryptedMessage);
La chiave attuale nell'ambiente di produzione è valida fino al 14/04/2038 in circostanze normali, ad eccezione delle compromissioni della chiave. In caso di compromissione delle chiavi, Google invia una notifica a tutti i commercianti tramite i dati di contatto forniti nel portale self-service per richiedere un ricaricamento più rapido di
keys.json.Lo snippet di codice gestisce i seguenti dettagli di sicurezza, in modo che tu possa concentrarti sull'utilizzo del payload:
- Chiavi di firma di Google recuperate e memorizzate nella cache
- Verifica della firma
- Decriptazione