• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&lt;SafetyNetApi.AttestationResult&gt;() {
202
203    &#64;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 &amp; 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 &amp; 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": "&lt;output of getJwsResult()&gt;" }
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&#58;&#47;&#47;www.googleapis.com/androidcheck/v1/attestations/verify?key=&lt;your API key&gt;
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>