Home » Android » android – Is api key needed in SafetyNet attestation?

android – Is api key needed in SafetyNet attestation?

Posted by: admin June 15, 2020 Leave a comment

Questions:

I’ve successfully created backend service and Android client for SafetyNet attestation.
When I send jws token to my server and try to validate it’s certificate it turns out that there is no certificate that signed it.

Should I add api key to my Android app?

My attestation result:

eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlFaURDQ0EzQ2dBd0lCQWdJSWNkK3ZTTGZWdWxrd0RRWUpLb1pJaHZjTkFRRUxCUUF3U1RFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa2R2YjJkc1pTQkpibU14SlRBakJnTlZCQU1USEVkdmIyZHNaU0JKYm5SbGNtNWxkQ0JCZFhSb2IzSnBkSGtnUnpJd0hoY05NVFl3TnpFeU1UVTBNelUwV2hjTk1UY3dOekV4TURBd01EQXdXakJzTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVXTUJRR0ExVUVCd3dOVFc5MWJuUmhhVzRnVm1sbGR6RVRNQkVHQTFVRUNnd0tSMjl2WjJ4bElFbHVZekViTUJrR0ExVUVBd3dTWVhSMFpYTjBMbUZ1WkhKdmFXUXVZMjl0TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3WEtyS0ZRRlBTckthS252NG9MSUhXNlVVMEk2STV2Q1FERFJOUlg2NWQrMVJLUWg0aDNoUHlTQ21MR2thREg0Q3Rud1lCdmRhWmZHUnVJVWx4K21zRjlkbU8rZzR0U2tSaXdrRzBxZ1VVN3docDk2ZHJoZkFrdDdPc2RzUWhmQWlTcmljdDlrTTRISElOVFVadjU0bXhkQmI0SkVBSlAvWlBDL2h5alAwRnlwNFlWVkdGN3RrQ09zUTVzYlB3cTBrbVJ0citobG41TXYwN1oxdkQwTG1MMU8yQy9qQUVCWGlhV3IzTjltenRXK2w3dEllOW1yY3FvUTB1UXdDWTd6YWdjb1czeFRmVExKVGdGTU5ZU0RtaDBEV2NZZUhidjNHQUtTR0hCSWZIWlQranhhZTlwam5pSi8zY3VmOWhVcUZPTGV3blI0TGdiTzNtSlc4a0dtWVFJREFRQUJvNElCVHpDQ0FVc3dIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUhBd0VHQ0NzR0FRVUZCd01DTUIwR0ExVWRFUVFXTUJTQ0VtRjBkR1Z6ZEM1aGJtUnliMmxrTG1OdmJUQm9CZ2dyQmdFRkJRY0JBUVJjTUZvd0t3WUlLd1lCQlFVSE1BS0dIMmgwZEhBNkx5OXdhMmt1WjI5dloyeGxMbU52YlM5SFNVRkhNaTVqY25Rd0t3WUlLd1lCQlFVSE1BR0dIMmgwZEhBNkx5OWpiR2xsYm5Sek1TNW5iMjluYkdVdVkyOXRMMjlqYzNBd0hRWURWUjBPQkJZRUZON1FsYndMa3BYbUNQbmxLS3FFdDdvc0JpYW5NQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVTdDBHRmh1ODltaTFkdldCdHJ0aUdycGFnUzh3SVFZRFZSMGdCQm93R0RBTUJnb3JCZ0VFQWRaNUFnVUJNQWdHQm1lQkRBRUNBakF3QmdOVkhSOEVLVEFuTUNXZ0k2QWhoaDlvZEhSd09pOHZjR3RwTG1kdmIyZHNaUzVqYjIwdlIwbEJSekl1WTNKc01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQnV4UEpqeE9GcjlqOEJUT0swbGhNNy8zVUN3d2RjSTFFZExmRGx4NmJCWW53SmVPUThKdC9Vd1VkcTFGTWRMM2gydkVTYVFkUVdYQTVCWE9YenI1TXV2V0xYaldKRjRsb0E4VzBTVDQyUDd6MWsyT29qb3JsNXZabkhjY08vZzhFd0ZpRlVINCsydXF1NVFzWmpVZGxMS2FFUWhJZTcvU2x2Qk41eHlZd0RaMlp0R00rdlVnVlFkbXpaV0puTGNHZFVSUGN3N2tlOWlNTFZKcXUrR0Z4c1lJSXYwMW1EQlVlblNUNFRsYWlEUG1nUmwzN3lCQWpUNGVaQlBIRzBGUzhna3FKZzAzMnhjNFdPNE1WMk1ZeEN0NWVzSllaOU04Y09QRFVjOEVYOUlwbC9FT1IrL25Mb2NRSEhIazhJQlhsbDVGM2lnN1RpOGFCNTJUMFdRaEIrIiwiTUlJRDhEQ0NBdGlnQXdJQkFnSURBanFTTUEwR0NTcUdTSWIzRFFFQkN3VUFNRUl4Q3pBSkJnTlZCQVlUQWxWVE1SWXdGQVlEVlFRS0V3MUhaVzlVY25WemRDQkpibU11TVJzd0dRWURWUVFERXhKSFpXOVVjblZ6ZENCSGJHOWlZV3dnUTBFd0hoY05NVFV3TkRBeE1EQXdNREF3V2hjTk1UY3hNak14TWpNMU9UVTVXakJKTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNoTUtSMjl2WjJ4bElFbHVZekVsTUNNR0ExVUVBeE1jUjI5dloyeGxJRWx1ZEdWeWJtVjBJRUYxZEdodmNtbDBlU0JITWpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSndxQkhkYzJGQ1JPZ2FqZ3VEWVVFaThpVC94R1hBYWlFWis0SS9GOFluT0llNWEvbUVOdHpKRWlhQjBDMU5QVmFUT2dtS1Y3dXRaWDhiaEJZQVN4RjZVUDd4YlNEajBVL2NrNXZ1UjZSWEV6L1JURGZSSy9KOVUzbjIrb0d0dmg4RFFVQjhvTUFOQTJnaHpVV3gvL3pvOHB6Y0dqcjFMRVFUcmZTVGU1dm44TVhIN2xOVmc4eTVLcjBMU3krckVhaHF5ekZQZEZVdUxIOGdaWVIvTm5hZytZeXVFTldsbGhNZ1p4VVlpK0ZPVnZ1T0FTaERHS3V5Nmx5QVJ4em1aRUFTZzhHRjZsU1dNVGxKMTRyYnRDTW9VL000aWFyTk96MFlEbDVjRGZzQ3gzbnV2UlRQUHVqNXh0OTcwSlNYQ0RUV0puWjM3RGhGNWlSNDN4YStPY21rQ0F3RUFBYU9CNXpDQjVEQWZCZ05WSFNNRUdEQVdnQlRBZXBob2pZbjdxd1ZrREJGOXFuMWx1TXJNVGpBZEJnTlZIUTRFRmdRVVN0MEdGaHU4OW1pMWR2V0J0cnRpR3JwYWdTOHdEZ1lEVlIwUEFRSC9CQVFEQWdFR01DNEdDQ3NHQVFVRkJ3RUJCQ0l3SURBZUJnZ3JCZ0VGQlFjd0FZWVNhSFIwY0RvdkwyY3VjM2x0WTJRdVkyOXRNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3TlFZRFZSMGZCQzR3TERBcW9DaWdKb1lrYUhSMGNEb3ZMMmN1YzNsdFkySXVZMjl0TDJOeWJITXZaM1JuYkc5aVlXd3VZM0pzTUJjR0ExVWRJQVFRTUE0d0RBWUtLd1lCQkFIV2VRSUZBVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQ0U0RXA0Qi9FQlpEWGdLdDEwS0E5TENPMHE2ejZ4RjlrSVFZZmVlUUZmdEpmNmlaQlpHN2VzbldQRGNZQ1pxMng1SWdCelV6Q2VRb1kzSU50T0F5bkllWXhCdDJpV2ZCVUZpd0U2b1RHaHN5cGI3cUVaVk1TR05KNlpsZElEZk0vaXBwVVJhVlM2bmVTWUxBRUhEMExQUHN2Q1FrMEU2c3BkbGVIbTJTd2Flc1NEV0IrZVhrbkdWcHpZZWtRVkEvTGxlbGtWRVNXQTZNQ2FHc2VxUVNwU2Z6bWhDWGZWVURCdmRtV0Y5ZlpPR3JYVzJsT1VoMW1Fd3BXanFOMHl2S25GVUV2L1RtRk5XQXJDYnRGNG1tazJ4Y3BNeTQ4R2FPWk9OOW11SUFzMG5INUFxcTNWdUR4M0NRUms2KzBOdFpsbXd1OVJZMjNuSE1BY0lTd1NIR0ZnPT0iXX0.eyJub25jZSI6IlVFMTViamRaVUVNdk4ybFJNRU5UVTJwQ1VXdE1Rak51VEU1WWRtOXZabnBPUm14WkwzcEhibXRWV21oS1ZrSkJTa3R1S3pkWFJHbDBUVnBzYkZORFppOWFMMjlGZUVKa2NEVnllQzlwUTFWUlluVlVlV2M5UFE9PSIsInRpbWVzdGFtcE1zIjoxNDkwNzg3MTQ3MzYxLCJhcGtQYWNrYWdlTmFtZSI6ImNvbS5leGFtcGxlLnNhbXBsZSIsImFwa0RpZ2VzdFNoYTI1NiI6ImtXVWZ3ZlpCSU9ib2UzRGtMM2RkeTFBbm1VdjM3cDFVYlduZ1Fkd1gwZHM9IiwiY3RzUHJvZmlsZU1hdGNoIjp0cnVlLCJleHRlbnNpb24iOiJDUVlZdUQyUmRqQVkiLCJhcGtDZXJ0aWZpY2F0ZURpZ2VzdFNoYTI1NiI6WyJ3ZU93UTZLUWdFZGx2bXJIV0VCRDlyZm96YnF6ZWU0ZlpPT2FXclpoc2NvPSJdLCJiYXNpY0ludGVncml0eSI6dHJ1ZX0.JXOvgIx0PufdyJ72Vo-FvTb_6Dwj7gcSxlXWHt8siVrgK2eMQA3V_eYbXS7NYkNUEXLLMNIfm8qEIwJQGYLUKE9GyaHjjuFt_YOkQMOzC8hh9VpIekS8bc_eRfvVajXzrFSRAigOnfVBrMGrVVpxsqtjqz1Y9ochGHwrjO2b8oZyw06HjzsnuT9YpLXakBg1azOYx9KP-_XkDaKW6_Lkfn6Rmo8hpatadIF5qn54W_UkXvvsG7d4P8h_7uvO66rRhK1OXg3Qhazta3B_XFtiLcmusaqmglopEW1hI07FAvrqzemuY-_4EcvReLKfo84rl_BuJmLFVtQtDyAHtzngxw
How to&Answers:

You are required to use API key with the latest version of Google Play Services.

See documentation on new SafetyNetClient::attest(byte[], String) method.


As a side note I highly recommend to set the verification quota to minimal value of 1 for a key you generate for your Android app here:

https://console.developers.google.com/projectselector/apis/api/androidcheck.googleapis.com/quotas

This (almost, off by 1 error ;)) stops an attacker from using a key which can be retrieved from your client code like so:

curl --data '{"signedAttestation": "eyJhbGciOiJSUzI1NiIsIng1YyI6WyJNSUlFaURDQ0EzQ2dBd0lCQWdJSWNkK3ZTTGZWdWxrd0RRWUpLb1pJaHZjTkFRRUxCUUF3U1RFTE1Ba0dBMVVFQmhNQ1ZWTXhFekFSQmdOVkJBb1RDa2R2YjJkc1pTQkpibU14SlRBakJnTlZCQU1USEVkdmIyZHNaU0JKYm5SbGNtNWxkQ0JCZFhSb2IzSnBkSGtnUnpJd0hoY05NVFl3TnpFeU1UVTBNelUwV2hjTk1UY3dOekV4TURBd01EQXdXakJzTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNBd0tRMkZzYVdadmNtNXBZVEVXTUJRR0ExVUVCd3dOVFc5MWJuUmhhVzRnVm1sbGR6RVRNQkVHQTFVRUNnd0tSMjl2WjJ4bElFbHVZekViTUJrR0ExVUVBd3dTWVhSMFpYTjBMbUZ1WkhKdmFXUXVZMjl0TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF3WEtyS0ZRRlBTckthS252NG9MSUhXNlVVMEk2STV2Q1FERFJOUlg2NWQrMVJLUWg0aDNoUHlTQ21MR2thREg0Q3Rud1lCdmRhWmZHUnVJVWx4K21zRjlkbU8rZzR0U2tSaXdrRzBxZ1VVN3docDk2ZHJoZkFrdDdPc2RzUWhmQWlTcmljdDlrTTRISElOVFVadjU0bXhkQmI0SkVBSlAvWlBDL2h5alAwRnlwNFlWVkdGN3RrQ09zUTVzYlB3cTBrbVJ0citobG41TXYwN1oxdkQwTG1MMU8yQy9qQUVCWGlhV3IzTjltenRXK2w3dEllOW1yY3FvUTB1UXdDWTd6YWdjb1czeFRmVExKVGdGTU5ZU0RtaDBEV2NZZUhidjNHQUtTR0hCSWZIWlQranhhZTlwam5pSi8zY3VmOWhVcUZPTGV3blI0TGdiTzNtSlc4a0dtWVFJREFRQUJvNElCVHpDQ0FVc3dIUVlEVlIwbEJCWXdGQVlJS3dZQkJRVUhBd0VHQ0NzR0FRVUZCd01DTUIwR0ExVWRFUVFXTUJTQ0VtRjBkR1Z6ZEM1aGJtUnliMmxrTG1OdmJUQm9CZ2dyQmdFRkJRY0JBUVJjTUZvd0t3WUlLd1lCQlFVSE1BS0dIMmgwZEhBNkx5OXdhMmt1WjI5dloyeGxMbU52YlM5SFNVRkhNaTVqY25Rd0t3WUlLd1lCQlFVSE1BR0dIMmgwZEhBNkx5OWpiR2xsYm5Sek1TNW5iMjluYkdVdVkyOXRMMjlqYzNBd0hRWURWUjBPQkJZRUZON1FsYndMa3BYbUNQbmxLS3FFdDdvc0JpYW5NQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVTdDBHRmh1ODltaTFkdldCdHJ0aUdycGFnUzh3SVFZRFZSMGdCQm93R0RBTUJnb3JCZ0VFQWRaNUFnVUJNQWdHQm1lQkRBRUNBakF3QmdOVkhSOEVLVEFuTUNXZ0k2QWhoaDlvZEhSd09pOHZjR3RwTG1kdmIyZHNaUzVqYjIwdlIwbEJSekl1WTNKc01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQnV4UEpqeE9GcjlqOEJUT0swbGhNNy8zVUN3d2RjSTFFZExmRGx4NmJCWW53SmVPUThKdC9Vd1VkcTFGTWRMM2gydkVTYVFkUVdYQTVCWE9YenI1TXV2V0xYaldKRjRsb0E4VzBTVDQyUDd6MWsyT29qb3JsNXZabkhjY08vZzhFd0ZpRlVINCsydXF1NVFzWmpVZGxMS2FFUWhJZTcvU2x2Qk41eHlZd0RaMlp0R00rdlVnVlFkbXpaV0puTGNHZFVSUGN3N2tlOWlNTFZKcXUrR0Z4c1lJSXYwMW1EQlVlblNUNFRsYWlEUG1nUmwzN3lCQWpUNGVaQlBIRzBGUzhna3FKZzAzMnhjNFdPNE1WMk1ZeEN0NWVzSllaOU04Y09QRFVjOEVYOUlwbC9FT1IrL25Mb2NRSEhIazhJQlhsbDVGM2lnN1RpOGFCNTJUMFdRaEIrIiwiTUlJRDhEQ0NBdGlnQXdJQkFnSURBanFTTUEwR0NTcUdTSWIzRFFFQkN3VUFNRUl4Q3pBSkJnTlZCQVlUQWxWVE1SWXdGQVlEVlFRS0V3MUhaVzlVY25WemRDQkpibU11TVJzd0dRWURWUVFERXhKSFpXOVVjblZ6ZENCSGJHOWlZV3dnUTBFd0hoY05NVFV3TkRBeE1EQXdNREF3V2hjTk1UY3hNak14TWpNMU9UVTVXakJKTVFzd0NRWURWUVFHRXdKVlV6RVRNQkVHQTFVRUNoTUtSMjl2WjJ4bElFbHVZekVsTUNNR0ExVUVBeE1jUjI5dloyeGxJRWx1ZEdWeWJtVjBJRUYxZEdodmNtbDBlU0JITWpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSndxQkhkYzJGQ1JPZ2FqZ3VEWVVFaThpVC94R1hBYWlFWis0SS9GOFluT0llNWEvbUVOdHpKRWlhQjBDMU5QVmFUT2dtS1Y3dXRaWDhiaEJZQVN4RjZVUDd4YlNEajBVL2NrNXZ1UjZSWEV6L1JURGZSSy9KOVUzbjIrb0d0dmg4RFFVQjhvTUFOQTJnaHpVV3gvL3pvOHB6Y0dqcjFMRVFUcmZTVGU1dm44TVhIN2xOVmc4eTVLcjBMU3krckVhaHF5ekZQZEZVdUxIOGdaWVIvTm5hZytZeXVFTldsbGhNZ1p4VVlpK0ZPVnZ1T0FTaERHS3V5Nmx5QVJ4em1aRUFTZzhHRjZsU1dNVGxKMTRyYnRDTW9VL000aWFyTk96MFlEbDVjRGZzQ3gzbnV2UlRQUHVqNXh0OTcwSlNYQ0RUV0puWjM3RGhGNWlSNDN4YStPY21rQ0F3RUFBYU9CNXpDQjVEQWZCZ05WSFNNRUdEQVdnQlRBZXBob2pZbjdxd1ZrREJGOXFuMWx1TXJNVGpBZEJnTlZIUTRFRmdRVVN0MEdGaHU4OW1pMWR2V0J0cnRpR3JwYWdTOHdEZ1lEVlIwUEFRSC9CQVFEQWdFR01DNEdDQ3NHQVFVRkJ3RUJCQ0l3SURBZUJnZ3JCZ0VGQlFjd0FZWVNhSFIwY0RvdkwyY3VjM2x0WTJRdVkyOXRNQklHQTFVZEV3RUIvd1FJTUFZQkFmOENBUUF3TlFZRFZSMGZCQzR3TERBcW9DaWdKb1lrYUhSMGNEb3ZMMmN1YzNsdFkySXVZMjl0TDJOeWJITXZaM1JuYkc5aVlXd3VZM0pzTUJjR0ExVWRJQVFRTUE0d0RBWUtLd1lCQkFIV2VRSUZBVEFOQmdrcWhraUc5dzBCQVFzRkFBT0NBUUVBQ0U0RXA0Qi9FQlpEWGdLdDEwS0E5TENPMHE2ejZ4RjlrSVFZZmVlUUZmdEpmNmlaQlpHN2VzbldQRGNZQ1pxMng1SWdCelV6Q2VRb1kzSU50T0F5bkllWXhCdDJpV2ZCVUZpd0U2b1RHaHN5cGI3cUVaVk1TR05KNlpsZElEZk0vaXBwVVJhVlM2bmVTWUxBRUhEMExQUHN2Q1FrMEU2c3BkbGVIbTJTd2Flc1NEV0IrZVhrbkdWcHpZZWtRVkEvTGxlbGtWRVNXQTZNQ2FHc2VxUVNwU2Z6bWhDWGZWVURCdmRtV0Y5ZlpPR3JYVzJsT1VoMW1Fd3BXanFOMHl2S25GVUV2L1RtRk5XQXJDYnRGNG1tazJ4Y3BNeTQ4R2FPWk9OOW11SUFzMG5INUFxcTNWdUR4M0NRUms2KzBOdFpsbXd1OVJZMjNuSE1BY0lTd1NIR0ZnPT0iXX0.eyJub25jZSI6IlVFMTViamRaVUVNdk4ybFJNRU5UVTJwQ1VXdE1Rak51VEU1WWRtOXZabnBPUm14WkwzcEhibXRWV21oS1ZrSkJTa3R1S3pkWFJHbDBUVnBzYkZORFppOWFMMjlGZUVKa2NEVnllQzlwUTFWUlluVlVlV2M5UFE9PSIsInRpbWVzdGFtcE1zIjoxNDkwNzg3MTQ3MzYxLCJhcGtQYWNrYWdlTmFtZSI6ImNvbS5leGFtcGxlLnNhbXBsZSIsImFwa0RpZ2VzdFNoYTI1NiI6ImtXVWZ3ZlpCSU9ib2UzRGtMM2RkeTFBbm1VdjM3cDFVYlduZ1Fkd1gwZHM9IiwiY3RzUHJvZmlsZU1hdGNoIjp0cnVlLCJleHRlbnNpb24iOiJDUVlZdUQyUmRqQVkiLCJhcGtDZXJ0aWZpY2F0ZURpZ2VzdFNoYTI1NiI6WyJ3ZU93UTZLUWdFZGx2bXJIV0VCRDlyZm96YnF6ZWU0ZlpPT2FXclpoc2NvPSJdLCJiYXNpY0ludGVncml0eSI6dHJ1ZX0.JXOvgIx0PufdyJ72Vo-FvTb_6Dwj7gcSxlXWHt8siVrgK2eMQA3V_eYbXS7NYkNUEXLLMNIfm8qEIwJQGYLUKE9GyaHjjuFt_YOkQMOzC8hh9VpIekS8bc_eRfvVajXzrFSRAigOnfVBrMGrVVpxsqtjqz1Y9ochGHwrjO2b8oZyw06HjzsnuT9YpLXakBg1azOYx9KP-_XkDaKW6_Lkfn6Rmo8hpatadIF5qn54W_UkXvvsG7d4P8h_7uvO66rRhK1OXg3Qhazta3B_XFtiLcmusaqmglopEW1hI07FAvrqzemuY-_4EcvReLKfo84rl_BuJmLFVtQtDyAHtzngxw"}' -H "Content-Type: application/json" -H "X-Android-Package: com.example" -H "X-Android-Cert: 1111111111111111111111111111111111111111" -X POST "https://www.googleapis.com/androidcheck/v1/attestations/verify?key=AIzaSyCmid3BBzBO0idOTNNRH-7RjCrA3xhvAho"

Substitute X-Android-Package, X-Android-Cert and key values to test on your API key with android app restriction.

Answer:

I think you missed some details, based on the documentation – Validating the response with Google APIs:

Note: You need an API key to access the Android Device Verification API, and the API is rate-limited. For these reasons, you should use the API only for testing during the initial development stage. You shouldn’t use this verification API in a production scenario.

Try adding the API key and check if the behavior change.

Hope this helps.

Answer:

You can validate the response yourself. Here’s some code that will help you interpret the JWT response:

https://github.com/scottyab/safetynethelper/blob/master/safetynetlib/src/main/java/com/scottyab/safetynet/SafetyNetHelper.java

You’ll want to validate the signing on your backend. Google does let you know what you need to check, if you’re not using their easy service:

Verify the compatibility check response

You should take steps to make
sure that the compatibility check response actually came from the
SafetyNet service and includes data that matches your request data.

Caution: You should send the entire JWS response to your own server,
using a secure connection, for verification. We don’t recommend that
you perform the verification directly in your app because, in that
case, there is no guarantee that the verification logic itself hasn’t
been modified.

Follow these steps to verify the origin of the JWS message:

  1. Extract the SSL certificate chain from the JWS message.
  2. Validate the
    SSL certificate chain and use SSL hostname matching to verify that the
    leaf certificate was issued to the hostname attest.android.com.
  3. Use
    the certificate to verify the signature of the JWS message.
  4. Check the
    data of the JWS message to make sure it matches the data within your
    original request. In particular, make sure that the nonce, timestamp,
    package name, and the SHA-256 hashes match.

From: https://developer.android.com/training/safetynet/attestation.html