i'm using safetynet api checking if device rooted or not , using below helpful code uses android verification api validate jwt signature:
https://github.com/scottyab/safetynethelper
and want validate on client side reduce overhead of web service , besides has limitation on 10k request per day.
so after decoding jws i'm getting below info
sample jws message response
xxxx.yyy.zzzz
header data
{"alg":"rs256","x5c":["<certificate1 string>","<certificate2 string>"]}
payload data
{"nonce":"<nounce>", "timestampms":1472794339527, "apkpackagename":"<apkpackagename>", "apkdigestsha256":"<sha digest string>", "ctsprofilematch":true, "extension":"<extension string>", "apkcertificatedigestsha256":["<apkcertificatedigestsha256 string>"],"basicintegrity":true}
signature in part if perform base64 decoding becomes unreadable below signature string received in jws last element
gw09rv1abbtd4er7f5ww_3tt1mprd5youmkpkwnrxjq8xw_cxlo4428dhtjdd8tbep-iv3nrvrwt2t4ph1usr2kj9budqjuxqzouhn93r2hfk-uakuyqyhp89_wowjscg4ysvhd4jc9s1hrzlngauosocomhn4szlzn5o8bxybdxkjhwwgard4bclhcwjzmxz5izfkhdiayenrq09ceqjrx_plqay8er_oai_2idzbnigfd2kmlk_ckaevjdxuc4bzjsilvriulrvp362wwhz4r1bhh8flmhr88nk99app2jkqd2l7lpv8y5f3fn3dkhj15czhr6zbitow1futeifg
now per google
"verify compatibility check response: extract ssl certificate chain jws message. validate ssl certificate chain , use ssl hostname matching verify leaf certificate issued hostname attest.android.com. use certificate verify signature of jws message."
i have cert string , signature how should go validating ssl certificate string , host name matching on second cert , how validate signature.
i need pointers on , code snipped helpful.
the way want validate jwt signature on device not secure. think next case:
the device rooted, malware application root privileges catches request google's safetynet , returns self-signed response.
when verify response own server service - response you've got wasn't provided google. if locally on device - same malware app catch request verify jwt signature , respond
true
.
anyway, can locally:
- you need api key google developers application.
- use android device verification api: android developers:
to use android device verification api:
create json message containing entire contents of jws message in following format:
{ "signedattestation": "<output of> getjwsresult()>" }
use http post request send message content-type of
"application/json"
following url: https://www.googleapis.com/androidcheck/v1/attestations/verify?key=<your api key>
the service validates integrity of message, , if message valid, returns json message following contents:
{ “isvalidsignature”: true }
so (code safetynet helper):
/** * * validates result android device verification api. * * note: validates provided jws (json web signature) message received actual safetynet service. * *not* verify payload data matches original compatibility check request. * post https://www.googleapis.com/androidcheck/v1/attestations/verify?key=<your api key> * * more info see {link https://developer.android.com/google/play/safetynet/start.html#verify-compat-check} * * created scottab on 27/05/2015. */ public class androiddeviceverifier { private static final string tag = androiddeviceverifier.class.getsimplename(); //used verifiy safety net response - 10,000 requests/day free private static final string google_verification_url = "https://www.googleapis.com/androidcheck/v1/attestations/verify?key="; private final string apikey; private final string signaturetoverify; private androiddeviceverifiercallback callback; public interface androiddeviceverifiercallback{ void error(string s); void success(boolean isvalidsignature); } public androiddeviceverifier(@nonnull string apikey, @nonnull string signaturetoverify) { this.apikey = apikey; this.signaturetoverify = signaturetoverify; } public void verify(androiddeviceverifiercallback androiddeviceverifiercallback){ callback = androiddeviceverifiercallback; androiddeviceverifiertask task = new androiddeviceverifiertask(); task.execute(); } /** * provide trust managers url connection. default uses system defaults plus googleapistrustmanager (ssl pinning) * @return array of trustmanager including system defaults plus googleapistrustmanager (ssl pinning) * @throws keystoreexception * @throws nosuchalgorithmexception */ protected trustmanager[] gettrustmanagers() throws keystoreexception, nosuchalgorithmexception { trustmanagerfactory trustmanagerfactory = trustmanagerfactory.getinstance(trustmanagerfactory.getdefaultalgorithm()); //init default system trustmanagers trustmanagerfactory.init((keystore)null); trustmanager[] defaulttrustmanagers = trustmanagerfactory.gettrustmanagers(); trustmanager[] trustmanagers = arrays.copyof(defaulttrustmanagers, defaulttrustmanagers.length + 1); //add our google apis pinning trustmanager security trustmanagers[defaulttrustmanagers.length] = new googleapistrustmanager(); return trustmanagers; } private class androiddeviceverifiertask extends asynctask<void, void, boolean>{ private exception error; @override protected boolean doinbackground(void... params) { //log.d(tag, "signaturetoverify:" + signaturetoverify); try { url verifyapiurl = new url(google_verification_url + apikey); sslcontext sslcontext = sslcontext.getinstance("tls"); sslcontext.init(null, gettrustmanagers(), null); httpsurlconnection urlconnection = (httpsurlconnection) verifyapiurl.openconnection(); urlconnection.setsslsocketfactory(sslcontext.getsocketfactory()); urlconnection.setrequestmethod("post"); urlconnection.setrequestproperty("content-type", "application/json"); //build post body { "signedattestation": "<output of getjwsresult()>" } string requestjsonbody = "{ \"signedattestation\": \""+signaturetoverify+"\"}"; byte[] outputinbytes = requestjsonbody.getbytes("utf-8"); outputstream os = urlconnection.getoutputstream(); os.write(outputinbytes); os.close(); urlconnection.connect(); //resp ={ “isvalidsignature”: true } inputstream = urlconnection.getinputstream(); stringbuilder sb = new stringbuilder(); bufferedreader rd = new bufferedreader(new inputstreamreader(is)); string line; while ((line = rd.readline()) != null) { sb.append(line); } string response = sb.tostring(); jsonobject responseroot = new jsonobject(response); if(responseroot.has("isvalidsignature")){ return responseroot.getboolean("isvalidsignature"); } }catch (exception e){ //something went wrong requesting validation of jws message error = e; log.e(tag, "problem validating jws message :" + e.getmessage(), e); return false; } return false; } @override protected void onpostexecute(boolean aboolean) { if(error!=null){ callback.error(error.getmessage()); }else { callback.success(aboolean); } } } }
Comments
Post a Comment