2017-02-15 7 views
1

Я реализующий SafetyNet API, основанный на Google SafetyNet sample и SafetyNet HelperSafetyNet: Имя пакета всегда возвращает нулевой

Вот мой рабочий код. Первая часть обработка коды я использовал в SafetyNetSampleFragment:

import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.support.v4.app.FragmentActivity; 
import android.util.Base64; 
import android.util.Log; 

import com.google.android.gms.common.ConnectionResult; 
import com.google.android.gms.common.api.GoogleApiClient; 
import com.google.android.gms.common.api.ResultCallback; 
import com.google.android.gms.common.api.Status; 
import com.google.android.gms.safetynet.SafetyNet; 
import com.google.android.gms.safetynet.SafetyNetApi; 

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.security.SecureRandom; 
import java.util.Random; 


public class SafetyNetVerifier implements GoogleApiClient.OnConnectionFailedListener { 

    private final Random mRandom = new SecureRandom(); 
    private String mResult; 
    private GoogleApiClient mGoogleApiClient; 

    private FragmentActivity activity; 

    public SafetyNetVerifier(FragmentActivity activity) { 
     this.activity = activity; 
     buildGoogleApiClient(); 
     sendSafetyNetRequest(); 
    } 

    private byte[] getRequestNonce(String data) { 
     ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); 
     byte[] bytes = new byte[24]; 
     mRandom.nextBytes(bytes); 
     try { 
      byteStream.write(bytes); 
      byteStream.write(data.getBytes()); 
     } catch (IOException e) { 
      return null; 
     } 

     return byteStream.toByteArray(); 
    } 

    protected synchronized void buildGoogleApiClient() { 
     mGoogleApiClient = new GoogleApiClient.Builder(activity) 
       .addApi(SafetyNet.API) 
       .enableAutoManage(activity, this) 
       .build(); 
    } 

    private void sendSafetyNetRequest() { 
     Log.e("hqthao", "Sending SafetyNet API request."); 

     String nonceData = "Safety Net Sample: " + System.currentTimeMillis(); 
     byte[] nonce = getRequestNonce(nonceData); 

     SafetyNet.SafetyNetApi.attest(mGoogleApiClient, nonce) 
       .setResultCallback(new ResultCallback<SafetyNetApi.AttestationResult>() { 

        @Override 
        public void onResult(SafetyNetApi.AttestationResult result) { 
         Status status = result.getStatus(); 
         if (status.isSuccess()) { 
          mResult = result.getJwsResult(); 
          Log.e("hqthao", "Success! SafetyNet result:\n" + mResult + "\n"); 
          SafetyNetResponse response = parseJsonWebSignature(mResult); 
          Log.e("hqthao", response.toString()); 
         } 
        } 
       }); 
    } 

    @Nullable 
    private SafetyNetResponse parseJsonWebSignature(String jwsResult) { 
     if (jwsResult == null) { 
      return null; 
     } 
     //the JWT (JSON WEB TOKEN) is just a 3 base64 encoded parts concatenated by a . character 
     final String[] jwtParts = jwsResult.split("\\."); 

     if (jwtParts.length == 3) { 
      //we're only really interested in the body/payload 
      String decodedPayload = new String(Base64.decode(jwtParts[1], Base64.DEFAULT)); 

      return SafetyNetResponse.parse(decodedPayload); 
     } else { 
      return null; 
     } 
    } 

    @Override 
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 
     Log.e("hqthao", "Error connecting to Google Play Services." + connectionResult.getErrorMessage()); 
    } 

} 

Вот модель SafetyNetResponse я скопировал из SafetyNetResponse:

import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.util.Log; 

import org.json.JSONArray; 
import org.json.JSONException; 
import org.json.JSONObject; 

import java.util.Arrays; 

public class SafetyNetResponse { 

    private static final String TAG = SafetyNetResponse.class.getSimpleName(); 
    private String nonce; 
    private long timestampMs; 
    private String apkPackageName; 
    private String[] apkCertificateDigestSha256; 
    private String apkDigestSha256; 
    private boolean ctsProfileMatch; 
    private boolean basicIntegrity; 

    //forces the parse() 
    private SafetyNetResponse() { 
    } 

    /** 
    * @return BASE64 encoded 
    */ 
    public String getNonce() { 
     return nonce; 
    } 

    public long getTimestampMs() { 
     return timestampMs; 
    } 

    /** 
    * @return com.package.name.of.requesting.app 
    */ 
    public String getApkPackageName() { 
     return apkPackageName; 
    } 

    /** 
    * SHA-256 hash of the certificate used to sign requesting app 
    * 
    * @return BASE64 encoded 
    */ 
    public String[] getApkCertificateDigestSha256() { 
     return apkCertificateDigestSha256; 
    } 

    /** 
    * SHA-256 hash of the app's APK 
    * 
    * @return BASE64 encoded 
    */ 
    public String getApkDigestSha256() { 
     return apkDigestSha256; 
    } 


    /** 
    * If the value of "ctsProfileMatch" is true, then the profile of the device running your app matches the profile of a device that has passed Android compatibility testing. 
    * 
    * @return 
    */ 
    public boolean isCtsProfileMatch() { 
     return ctsProfileMatch; 
    } 

    /** 
    * If the value of "basicIntegrity" is true, then the device running your app likely wasn't tampered with, but the device has not necessarily passed Android compatibility testing. 
    * 
    * @return 
    */ 
    public boolean isBasicIntegrity() { 
     return basicIntegrity; 
    } 

    /** 
    * Parse the JSON string into populated SafetyNetResponse object 
    * 
    * @param decodedJWTPayload JSON String (always a json string according to JWT spec) 
    * @return populated SafetyNetResponse 
    */ 
    @Nullable 
    public static SafetyNetResponse parse(@NonNull String decodedJWTPayload) { 

     Log.d(TAG, "decodedJWTPayload json:" + decodedJWTPayload); 

     SafetyNetResponse response = new SafetyNetResponse(); 
     try { 
      JSONObject root = new JSONObject(decodedJWTPayload); 
      if (root.has("nonce")) { 
       response.nonce = root.getString("nonce"); 
      } 

      if (root.has("apkCertificateDigestSha256")) { 
       JSONArray jsonArray = root.getJSONArray("apkCertificateDigestSha256"); 
       if (jsonArray != null) { 
        String[] certDigests = new String[jsonArray.length()]; 
        for (int i = 0; i < jsonArray.length(); i++) { 
         certDigests[i] = jsonArray.getString(i); 
        } 
        response.apkCertificateDigestSha256 = certDigests; 
       } 
      } 

      if (root.has("apkDigestSha256")) { 
       response.apkDigestSha256 = root.getString("apkDigestSha256"); 
      } 

      if (root.has("apkPackageName")) { 
       response.apkPackageName = root.getString("apkPackageName"); 
      } 

      if (root.has("basicIntegrity")) { 
       response.basicIntegrity = root.getBoolean("basicIntegrity"); 
      } 

      if (root.has("ctsProfileMatch")) { 
       response.ctsProfileMatch = root.getBoolean("ctsProfileMatch"); 
      } 

      if (root.has("timestampMs")) { 
       response.timestampMs = root.getLong("timestampMs"); 
      } 

      return response; 
     } catch (JSONException e) { 
      Log.e(TAG, "problem parsing decodedJWTPayload:" + e.getMessage(), e); 
     } 
     return null; 
    } 


    @Override 
    public String toString() { 
     return "SafetyNetResponse{" + 
       "nonce='" + nonce + '\'' + 
       ", timestampMs=" + timestampMs + 
       ", apkPackageName='" + apkPackageName + '\'' + 
       ", apkCertificateDigestSha256=" + Arrays.toString(apkCertificateDigestSha256) + 
       ", apkDigestSha256='" + apkDigestSha256 + '\'' + 
       ", ctsProfileMatch=" + ctsProfileMatch + 
       ", basicIntegrity=" + basicIntegrity + 
       '}'; 
    } 
} 

Мы можем легко позвонить выше работоспособному коду, вызвав эту строку коды внутри деятельности:

new SafetyNetVerifier(this); 

результат:

SafetyNetResponse{ 
nonce='Xc4dSnAjAqf9KWDZokwK2TdBw9Td+ZILU2FmZXR5IE5ldCBTYW1wbGU6IDE0ODcxODQyMjYwNjc=', 
timestampMs=1487184225994, 
apkPackageName='null', 
apkCertificateDigestSha256=[], 
apkDigestSha256='null', 
ctsProfileMatch=false, 
basicIntegrity=false 
} 

Как правильно проверять временную метку. Я думаю, что у меня есть успешный ответ safetynet. Но я не знаю, почему apkPackageName всегда null и другие поля, как я показал, пустые. Пожалуйста, помогите мне.

+1

Возможно, вы захотите проверить документацию о [Проверка совместимости устройств с SafetyNet -Отчет ответа на проверку совместимости] (https://developer.android.com/training/safetynet/index.html#compat-check-response): Поля «apkPackageName», «apkCertificateDigestSha256'» и «' apkDigestSha256' »предоставляют информацию об APK, которую вы можете использовать для проверки подлинности вызывающего приложения. Эти поля отсутствуют, если API не может достоверно определить информацию APK. Наличие результата «null» означает, что вызов службы не завершился успешно. –

ответ

2

В вашем объекте SafetyNetResponse вы заметите, что basicIntegrity является ложным. Это говорит о том, что обнаружена какая-то система, подделывающая другую модификацию (одним из примеров является укоренение).

Это дает представление о том, почему информационные поля APK отсутствуют. Как описано в documentation:

В apkPackageName, apkCertificateDigestSha256 и apkDigestSha256 поля предоставляют информацию о APK, которую можно использовать для проверки идентичности приложения вызова. Эти поля отсутствуют, если API не может достоверно определить информацию APK.

Ваш код выглядит правильно. Вы можете проверить это, протестировав на немодифицированном устройстве, на котором установлена ​​одобренная версия Android, - тогда необходимо добавить отсутствующую информацию.

+0

спасибо. Я пробовал выше код для нормального устройства, и он работает: D он должен проверить этот api раньше на обычном устройстве: D –

Смежные вопросы