Home | History | Annotate | Download | only in safetynet
      1 page.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>
     57 As with any data collected in large volume from in-the-field observation, there is a chance of
     58 both false positives and false negatives. We are presenting the data to the best of our
     59 understanding. We extensively test our detection mechanisms to ensure accuracy, and we are
     60 committed to improving those methods over time to ensure they continue to remain accurate.
     61 
     62 You agree to comply with all applicable law, regulation, and third party rights (including
     63 without limitation laws regarding the import or export of data or software, privacy, and local
     64 laws). You will not use the APIs to encourage or promote illegal activity or violation of third
     65 party rights. You will not violate any other terms of service with Google (or its affiliates).
     66 
     67 You acknowledge and understand that the SafetyNet API works by collecting hardware and software
     68 information, such as device and application data and the results of integrity checks, and sending
     69 that 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
     71 you use the APIs that it is your responsibility to provide any necessary notices or consents for the
     72 collection 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>
     97 protected 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>
    199 byte[] nonce = getRequestNonce(); // Should be at least 16 bytes in length.
    200 SafetyNet.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
    248 certificate 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>
    353 https&#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>