为访问服务器资源生成令牌

时间:2017-07-28 10:51:23

标签: android web-services authentication android-security

我正在尝试使用签名证书在运行时生成令牌,并验证服务器上的令牌以访问任何资源。我不想将令牌存储在XML文件中,因为它在APK的逆向工程后可用。

生成令牌的代码是

public String getToken() {
    Signature[] sigs;
    try {
        sigs = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;

        String token = sigs[0].toCharsString();
        return token;
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

问题是某些设备返回不同的令牌,即使apk是从同一证书生成的,也不知道它为某些设备返回不同令牌的原因。

我想要的只是生成一个可用于访问网络资源的令牌,我不想在apk中存储令牌,没有人可以通过反编译来获取令牌。

3 个答案:

答案 0 :(得分:1)

签名证书的指纹在所有设备上都是唯一的。您是否可以尝试使用此解决方案将指纹作为String并将其用作令牌。

https://stackoverflow.com/a/22506133/4586742

答案 1 :(得分:1)

您可以使用C或C ++存储令牌 并添加签名验证

public static String getSignature(Context context) {
try {
    PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES);
    Signature[] signatures = packageInfo.signatures;
    return signatures[0].toCharsString();
} catch(PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}
return null;

}

const char * app_signature = "singsing";
static int is_valid = 0;
void
Java_com_xxx_xxx_nativeInit(JNIEnv *env, jobject thiz, jobject context_object){
    jclass context_class = (*env)->GetObjectClass(env, context_object);

    //context.getPackageManager()
    jmethodID methodId = (*env)->GetMethodID(env, context_class, "getPackageManager", "()Landroid/content/pm/PackageManager;");
    jobject package_manager_object = (*env)->CallObjectMethod(env, context_object, methodId);
    if (package_manager_object == NULL) {
        return;
    }

    //context.getPackageName()
    methodId = (*env)->GetMethodID(env, context_class, "getPackageName", "()Ljava/lang/String;");
    jstring package_name_string = (jstring)(*env)->CallObjectMethod(env, context_object, methodId);
    if (package_name_string == NULL) {
        return ;
    }
    (*env)->DeleteLocalRef(env,context_class);

    //PackageManager.getPackageInfo(Sting, int)
    //public static final int GET_SIGNATURES= 0x00000040;
    jclass pack_manager_class = (*env)->GetObjectClass(env, package_manager_object);
    methodId = (*env)->GetMethodID(env, pack_manager_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    (*env)->DeleteLocalRef(env,pack_manager_class);
    jobject package_info_object = (*env)->CallObjectMethod(env, package_manager_object, methodId, package_name_string, 0x40);
    if (package_info_object == NULL) {
        return ;
    }
    (*env)->DeleteLocalRef(env,package_manager_object);

    //PackageInfo.signatures[0]
    jclass package_info_class = (*env)->GetObjectClass(env, package_info_object);
    jfieldID fieldId = (*env)->GetFieldID(env, package_info_class, "signatures", "[Landroid/content/pm/Signature;");
    (*env)->DeleteLocalRef(env,package_info_class);
    jobjectArray signature_object_array = (jobjectArray)(*env)->GetObjectField(env,package_info_object, fieldId);
    if (signature_object_array == NULL) {
        return ;
    }
    jobject signature_object = (*env)->GetObjectArrayElement(env,signature_object_array, 0);
    (*env)->DeleteLocalRef(env,package_info_object);
    jclass signature_class = (*env)->GetObjectClass(env, signature_object); 
    methodId = (*env)->GetMethodID(env, signature_class,  "toCharsString", "()Ljava/lang/String;");
    (*env)->DeleteLocalRef(env,signature_class);
    jstring signature_jstirng = (jstring) (*env)->CallObjectMethod(env, signature_object, methodId);
    const  char *sign=(*env)->GetStringUTFChars(env, signature_jstirng,NULL); 
    if (strcmp(sign,app_signature)==0 || strcmp(sign,app_j_s)==0) {
        is_valid= 1;
    } 
    return;
}

答案 2 :(得分:0)

@Om Infowave Developers,

我建议您使用Android Keystore System 生成KeyPair然后使用KeyPair加密令牌,以共享首选项存储令牌。每当您需要使用KeyPair的令牌解密令牌时。

  1. 这样每次都会获得唯一的令牌。
  2. 令牌已加密并受到保护。
  3. 每个设备的KeyPair都不同,因此更安全。
  4. 另外,我只是注意到您正在返回基于零索引的密钥。他们可能有机会在后续指数中找到关键。建议您记录Signature[] sigs中存储的所有密钥;

    希望得到这个帮助。