1page.title=Checking Device Compatibility with SafetyNet 2 3@jd:body 4 5 6<div id="tb-wrapper"> 7<div id="tb"> 8 9 <h2>In this document</h2> 10 <ol> 11 <li><a href="#tos">Additional Terms of Service</a></li> 12 <li><a href="#connect-play">Connect to Play Services</a></li> 13 <li><a href="#cts-check">Requesting a Compatibility Check</a> 14 <ol> 15 <li><a href="#single-use-token">Obtain Single Use Token</a></li> 16 <li><a href="#compat-check-request">Send Compatibility Check Request</a></li> 17 <li><a href="#compat-check-response">Read Compatibility Check Response</a></li> 18 <li><a href="#verify-compat-check">Verify Compatibility Check Response</a></li> 19 </ol> 20 </li> 21 </ol> 22 23</div> 24</div> 25 26<p> 27 SafetyNet provides services for analyzing the configuration of a particular device, to make sure 28 that apps function properly on a particular device and that users have a great experience. 29</p> 30 31<p> 32 The service provides an API your app can use to analyze the device where it is installed. The API 33 uses software and hardware information on the device where your app is installed to create a 34 profile of that device. The service then attempts to match it to a list of device models that 35 have passed Android compatibility testing. This check can help you decide if the device is 36 configured in a way that is consistent with the Android platform specifications and has the 37 capabilities to run your app. 38</p> 39 40<p> 41 This document shows you how to use SafetyNet for analyzing a device and help you determine if 42 your app will function as expected on that device. 43</p> 44 45<h2 id="tos"> 46 Additional Terms of Service 47</h2> 48 49<p> 50 By accessing or using the SafetyNet APIs, you agree to the <a href= 51 "https://developers.google.com/terms/">Google APIs Terms of Service</a>, and to these Additional 52 Terms. Please read and understand all applicable terms and policies before accessing the APIs. 53</p> 54 55<div class="sdk-terms" onfocus="this.blur()" style="width:678px"> 56<h3 class="norule">SafetyNet Terms of Service</h3> 57As with any data collected in large volume from in-the-field observation, there is a chance of 58both false positives and false negatives. We are presenting the data to the best of our 59understanding. We extensively test our detection mechanisms to ensure accuracy, and we are 60committed to improving those methods over time to ensure they continue to remain accurate. 61 62You agree to comply with all applicable law, regulation, and third party rights (including 63without limitation laws regarding the import or export of data or software, privacy, and local 64laws). You will not use the APIs to encourage or promote illegal activity or violation of third 65party rights. You will not violate any other terms of service with Google (or its affiliates). 66 67You acknowledge and understand that the SafetyNet API works by collecting hardware and software 68information, such as device and application data and the results of integrity checks, and sending 69that data to Google for analysis. Pursuant to Section 3(d) of the 70<a href= "https://developers.google.com/terms/">Google APIs Terms of Service</a>, you agree that if 71you use the APIs that it is your responsibility to provide any necessary notices or consents for the 72collection and sharing of this data with Google. 73</div> 74 75<h2 id="connect-play"> 76 Connect to Google Play Services 77</h2> 78 79<p> 80 The SafetyNet API is part of Google Play services. To connect to the API, you need to create an 81 instance of the Google Play services API client. For details about using the client in your app, 82 see <a href="{@docRoot}google/auth/api-client.html#Starting">Accessing Google 83 APIs</a>. Once you have established a connection to Google Play services, you can use the Google 84 API client classes to connect to the SafetyNet API. 85</p> 86 87<p> 88 To connect to the API, in your activity's <a href= 89 "{@docRoot}reference/android/app/Activity.html#onCreate(android.os.Bundle)">onCreate()</a> 90 method, create an instance of Google API Client using <a href= 91 "{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html"> 92 {@code GoogleApiClient.Builder}</a>. Use the builder to add the SafetyNet API, as shown in the 93 following code example: 94</p> 95 96<pre> 97protected synchronized void buildGoogleApiClient() { 98 mGoogleApiClient = new GoogleApiClient.Builder(this) 99 .addApi(SafetyNet.API) 100 .addConnectionCallbacks(myMainActivity.this) 101 .build(); 102} 103</pre> 104 105<p class="note"> 106 <strong>Note:</strong> You can only call these methods after your app has established a connection to 107 Google Play services by receiving the <a href= 108 "{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"> 109 {@code onConnected()}</a> callback. For details about listening for a completed client connection, 110 see <a href="{@docRoot}google/auth/api-client.html#Starting">Accessing Google APIs</a>. 111</p> 112 113<h2 id="cts-check"> 114 Requesting a Compatibility Check 115</h2> 116 117<p> 118 A SafetyNet compatibility check allows your app to check if the device where it is running 119 matches the profile of a device that has passed Android compatibility testing. The compatibility 120 check creates a device profile by gathering information about the device hardware and software 121 characteristics, including the platform build. 122</p> 123 124<p> 125 Using the API to perform a check requires a few implementation steps in your app. Once you have 126 established a connection to Google Play services and requested the SafetyNet API from the Google 127 API client, your app can then perform the following steps to use the service: 128</p> 129 130<ul> 131 <li>Obtain a single use token 132 </li> 133 134 <li>Send the compatibility check request 135 </li> 136 137 <li>Read the response 138 </li> 139 140 <li>Validate the response 141 </li> 142</ul> 143 144<p> 145 For more information about Android compatibility testing, see <a href= 146 "https://source.android.com/compatibility/index.html" class="external-link"> 147 Android Compatibility</a> and the <a href= 148 "https://source.android.com/compatibility/cts-intro.html" class="external-link"> 149 Compatibility Testing Suite</a> (CTS). 150</p> 151 152<p> 153 SafetyNet checks use network resources, and so the speed of responses to requests can vary, 154 depending on a device's network connection status. The code described in this section should be 155 executed outside of your app's main execution thread, to avoid pauses and unresponsiveness in 156 your app user interface. For more information about using separate execution threads, see 157 <a href="{@docRoot}training/multiple-threads/index.html">Sending Operations 158 to Multiple Threads</a>. 159</p> 160 161<h3 id="single-use-token"> 162 Obtain a single use token 163</h3> 164 165<p> 166 The SafetyNet API uses security techniques to help you verify the integrity of the communications 167 between your app and the service. When you request a compatibility check, you must provide a 168 single use token in the form of a number used once, or <em>nonce</em>, as part of your request. A 169 nonce is a random token generated in a cryptographically secure manner. 170</p> 171 172<p> 173 You can obtain a nonce by generating one within your app each time you make a compatibility check 174 request. As a more secure option, you can obtain a nonce from your own server, using a secure 175 connection. 176</p> 177 178<p> 179 A nonce used with a SafetyNet request should be at least 16 bytes in length. After you make a 180 check request, the response from the SafetyNet service includes your nonce, so you can verify it 181 against the one you sent. As the name indicates, you should only use a nonce value once, for a 182 single check request. Use a different nonce for any subsequent check requests. For tips on using 183 cryptography functions, see <a href= 184 "{@docRoot}training/articles/security-tips.html#Crypto">Security Tips</a>. 185</p> 186 187<h3 id="compat-check-request"> 188 Send the compatibility check request 189</h3> 190 191<p> 192 After you have established a connection to Google Play services and created a nonce, you are 193 ready to make a compatibility check request. Since the response to your request may not be 194 immediate, you set up a callback listener to catch the response from the service, as shown in the 195 following code example: 196</p> 197 198<pre> 199byte[] nonce = getRequestNonce(); // Should be at least 16 bytes in length. 200SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce) 201 .setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() { 202 203 @Override 204 public void onResult(SafetyNetApi.AttestationResult result) { 205 Status status = result.getStatus(); 206 if (status.isSuccess()) { 207 // Indicates communication with the service was successful. 208 // result.getJwsResult() contains the result data 209 } else { 210 // An error occurred while communicating with the service 211 } 212 } 213}); 214</pre> 215 216<p> 217 The <a href= 218 "{@docRoot}reference/com/google/android/gms/common/api/Status.html#isSuccess()"> 219 {@code isSuccess()}</a> 220 method indicates whether or not communication with the service was successful, but does not 221 indicate if the device has passed the compatibility check. The next section discusses how to read 222 the check result and verify its integrity. 223</p> 224 225<h3 id="compat-check-response"> 226 Read the compatibility check response 227</h3> 228 229<p> 230 When your app communicates with SafetyNet, the service provides a response containing the result 231 and additional information to help you verify the integrity of the message. The result is 232 provided as a <a href= 233 "{@docRoot}reference/com/google/android/gms/safetynet/SafetyNetApi.html"> 234 {@code AttestationResult}</a> 235 object. Use the <a href= 236 "{@docRoot}reference/com/google/android/gms/safetynet/SafetyNetApi.AttestationResult.html#getJwsResult()"> 237{@code getJwsResult()}</a> method of this object to obtain the data of the request. The response is 238 formatted as a <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-36" class="external-link"> 239 JSON Web Signature</a> (JWS), the following JWS excerpt shows the format of the payload data: 240</p> 241 242<pre> 243{ 244"nonce": "R2Rra24fVm5xa2Mg", 245"timestampMs": 9860437986543, 246"apkPackageName": "com.package.name.of.requesting.app", 247"apkCertificateDigestSha256": ["base64 encoded, SHA-256 hash of the 248certificate used to sign requesting app"], 249"apkDigestSha256": "base64 encoded, SHA-256 hash of the app's APK", 250"ctsProfileMatch": true, 251} 252</pre> 253 254<p> 255 If the value of {@code ctsProfileMatch} is {@code true}, this indicates that the device 256 profile matches a device that has passed Android compatibility testing. If the output of the 257 <a href= 258 "{@docRoot}reference/com/google/android/gms/safetynet/SafetyNetApi.AttestationResult.html#getJwsResult()"> 259{@code getJwsResult()}</a> method is null or contains an {@code error:} field, then communication 260 with the service failed and should be retried. You should use an <a class="external-link" href= 261 "https://developers.google.com/api-client-library/java/google-http-java-client/backoff"> 262 exponential backoff</a> technique for retries, to avoid flooding the service with additional requests. 263</p> 264 265<h3 id="verify-compat-check"> 266 Verify the compatibility check response 267</h3> 268 269<p> 270 You should take steps to make sure the response received by your app actually came from the 271 SafetyNet service and matches the request data you provided. Follow these steps to verify the 272 origin of the JWS message: 273</p> 274 275<ul> 276 <li>Extract the SSL certificate chain from the JWS message. 277 </li> 278 279 <li>Validate the SSL certificate chain and use SSL hostname matching to verify that the leaf 280 certificate was issued to the hostname {@code attest.android.com}. 281 </li> 282 283 <li>Use the certificate to verify the signature of the JWS message. 284 </li> 285</ul> 286 287<p> 288 After completing this validation, you should also check the data of the JWS message to make sure 289 it matches your original request, including the nonce, timestamp, package name, and the SHA-256 290 hashes. You can perform these validation steps within your app, or as a more secure option, send 291 the entire JWS response to your own server for verification, via a secure connection. 292</p> 293 294<h4> 295 Validating the response with Google APIs 296</h4> 297 298<p> 299 Google provides an Android Device Verification API for validating the output of the SafetyNet 300 compatibility check. This API performs a validation check on the JWS message returned from the 301 SafetyNet service. 302</p> 303 304<p> 305 To enable access to the Android Device Verification API: 306</p> 307 308<ol> 309 <li>Go to the <a href="https://console.developers.google.com/" class="external-link"> 310 Google Developers Console</a>. 311 </li> 312 313 <li>Select a project, or create a new one. 314 </li> 315 316 <li>In the sidebar on the left, expand <strong>APIs & auth</strong>. 317 Next, click <strong>APIs</strong>. In the 318 list of APIs, make sure all of the APIs you are using show a status of <strong>ON</strong>. 319 </li> 320 321 <li>In the <strong>Browse APIs</strong> list, find the 322 <strong>Android Device Verification API</strong> and turn it 323 on. 324 </li> 325 326 <li>Obtain your API key by expanding <strong>APIs & auth</strong> and 327 clicking <strong>Credentials</strong>. 328 Record the <strong>API KEY</strong> (<em>not</em> the <em>Android Key</em>) value on this page for later use. 329 </li> 330</ol> 331 332<p> 333 After enabling this API for your project, you can call the verification service from your app or 334 server. You need the contents of the JWS message from the SafetyNet API and your API key to call 335 the verification API and get a result. 336</p> 337 338<p> 339 To use the Android Device Verification API: 340</p> 341 342<ol> 343 <li>Create a JSON message containing the entire contents of the JWS message in the following 344 format: 345<pre> 346{ "signedAttestation": "<output of getJwsResult()>" } 347</pre> 348 </li> 349 350 <li>Use an HTTP POST request to send the message with a Content-Type of {@code "application/json"} 351 to the following URL: 352<pre> 353https://www.googleapis.com/androidcheck/v1/attestations/verify?key=<your API key> 354</pre> 355 </li> 356 357 <li>The service validates the integrity of the message, and if the message is valid, it returns a 358 JSON message with the following contents: 359 360<pre> 361{ “isValidSignature”: true } 362</pre> 363 </li> 364</ol> 365 366<p class="note"> 367 <strong>Important:</strong> This use of the Android Device Verification API only validates that the 368 provided JWS message was received from the SafetyNet service. It <em>does not</em> verify that the 369 payload data matches your original compatibility check request. 370</p>