真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何理解Android敏感數(shù)據(jù)泄露

本篇內(nèi)容主要講解“如何理解Android敏感數(shù)據(jù)泄露”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“如何理解Android敏感數(shù)據(jù)泄露”吧!

公司主營(yíng)業(yè)務(wù):網(wǎng)站設(shè)計(jì)制作、成都網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。成都創(chuàng)新互聯(lián)公司推出含山免費(fèi)做網(wǎng)站回饋大家。

 1.事件始末

一個(gè)平淡的午后,我還悠哉悠哉的敲著代碼品著茶。突然服務(wù)端同事告訴我,關(guān)注接口正在被機(jī)械式調(diào)用,懷疑是有人在使用腳本刷接口(目的主要是從平臺(tái)導(dǎo)流)。

納尼?不會(huì)吧,因?yàn)閾?jù)我所知接口請(qǐng)求是做了加密處理的,除非知道加密的密鑰和加密方式,不然是不會(huì)調(diào)用成功的,一定是你感覺(jué)錯(cuò)了。然而當(dāng)服務(wù)端同事把接口調(diào)用日志發(fā)給我看時(shí),徹底否定了我的僥幸心理。

接口調(diào)用頻率固定為1s 一次

被關(guān)注者的id每次調(diào)用依次加一(目前業(yè)務(wù)上用戶id的生成是按照注冊(cè)時(shí)間依次遞增的)

加密的密鑰始終使用固定的一個(gè)(正常的是在固定的幾個(gè)密鑰中每次會(huì)隨機(jī)使用一個(gè))

綜合以上三點(diǎn)就可以斷定,肯定是存在刷接口的行為了。

2.事件分析

既然上述刷接口的行為成立,也就意味著密鑰和加密方式被對(duì)方知道了,原因無(wú)非是以下兩點(diǎn):

  1. 內(nèi)部人員泄露

  2. apk被破解

經(jīng)過(guò)確認(rèn)基本排除了第一點(diǎn),那就只剩下apk被破解了,可是apk發(fā)布出去的包是進(jìn)行過(guò)加固和混淆處理的,難道對(duì)方脫殼了?不管三七二十一,自己先來(lái)反編譯試試。于是乎從最近發(fā)布的版本一個(gè)一個(gè)去反編譯,最后在反編譯到較早前的一個(gè)版本時(shí)發(fā)現(xiàn),保存密鑰和加密的工具類(lèi)居然源碼完全暴露了。

如何理解Android敏感數(shù)據(jù)泄露

炸了鍋了,排查了一下這個(gè)版本居然未加固過(guò)就發(fā)布出去了,而且這個(gè)加密工具類(lèi)未被混淆。雖然還不太清楚對(duì)方是不是按照這種方式獲取的密鑰和加密算法,但無(wú)疑這是客戶端存在的一個(gè)安全漏洞。

3.事件處理

既然已經(jīng)發(fā)現(xiàn)了上述問(wèn)題,那就要想辦法解決。首先不考慮加固,如何盡最大可能保證客戶端中的敏感數(shù)據(jù)不泄露?另一方面即使對(duì)方想要破解,也要想辦法設(shè)障,增大破解難度。想到這里基本就大致確定了一個(gè)思路:使用NDK,將敏感數(shù)據(jù)和加密方式放到native層,因?yàn)镃++代碼編譯后生成的so庫(kù)是一個(gè)二進(jìn)制文件,這無(wú)疑會(huì)增加破解的難度。利用這個(gè)特性,可以將客戶端的敏感數(shù)據(jù)寫(xiě)在C++代碼中,從而增強(qiáng)應(yīng)用的安全性。  說(shuō)干就干吧!!!

1.首先創(chuàng)建了加密工具類(lèi):

public class HttpKeyUtil {     static {         System.loadLibrary("jniSecret");     }     //根據(jù)隨機(jī)值去獲取密鑰     public static native String getHttpSecretKey(int index);     //將待加密的數(shù)據(jù)傳入,返回加密后的結(jié)果     public static native String getSecretValue(byte[] bytes); }

2.生成相應(yīng)的頭文件:

#include  #ifndef _Included_com_test_util_HttpKeyUtil #define _Included_com_test_util_HttpKeyUtil #ifdef __cplusplus extern "C" { #endif JNIEXPORT jstring JNICALL Java_com_esky_common_component_util_HttpKeyUtil_getHttpSecretKey         (JNIEnv *, jclass, jint);          JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue         (JNIEnv *, jclass, jbyteArray);  #ifdef __cplusplus } #endif #endif

3.編寫(xiě)相應(yīng)的cpp文件:

在相應(yīng)的Module中創(chuàng)建jni目錄,將com_test_util_HttpKeyUtil.h拷貝進(jìn)來(lái),然后再創(chuàng)建com_test_util_HttpKeyUtil.cpp文件

如何理解Android敏感數(shù)據(jù)泄露

#include  #include  #include  #include "com_test_util_HttpKeyUtil.h"  extern "C" const char *KEY1 = "密鑰1"; const char *KEY2 = "密鑰2"; const char *KEY3 = "密鑰3"; const char *UNKNOWN = "unknown";  jstring toMd5(JNIEnv *pEnv, jbyteArray pArray);  extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getHttpSecretKey         (JNIEnv *env, jclass cls, jint index) {     if (隨機(jī)數(shù)條件1) {         return env->NewStringUTF(KEY1);     } else if (隨機(jī)數(shù)條件2) {         return env->NewStringUTF(KEY2);     } else if (隨機(jī)數(shù)條件3) {         return env->NewStringUTF(KEY3);     } else {         return env->NewStringUTF(UNKNOWN);     } }  extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue         (JNIEnv *env, jclass cls, jbyteArray jbyteArray1) {         //加密算法各有不同,這里我就用md5做個(gè)示范         return toMd5(env, jbyteArray1); }  //md5 jstring toMd5(JNIEnv *env, jbyteArray source) {     // MessageDigest     jclass classMessageDigest = env->FindClass("java/security/MessageDigest");     // MessageDigest.getInstance()     jmethodID midGetInstance = env->GetStaticMethodID(classMessageDigest, "getInstance",                                                       "(Ljava/lang/String;)Ljava/security/MessageDigest;");     // MessageDigest object     jobject objMessageDigest = env->CallStaticObjectMethod(classMessageDigest, midGetInstance,                                                            env->NewStringUTF("md5"));      jmethodID midUpdate = env->GetMethodID(classMessageDigest, "update", "([B)V");     env->CallVoidMethod(objMessageDigest, midUpdate, source);      // Digest     jmethodID midDigest = env->GetMethodID(classMessageDigest, "digest", "()[B");     jbyteArray objArraySign = (jbyteArray) env->CallObjectMethod(objMessageDigest, midDigest);      jsize intArrayLength = env->GetArrayLength(objArraySign);     jbyte *byte_array_elements = env->GetByteArrayElements(objArraySign, NULL);     size_t length = (size_t) intArrayLength * 2 + 1;     char *char_result = (char *) malloc(length);     memset(char_result, 0, length);     toHexStr((const char *) byte_array_elements, char_result, intArrayLength);     // 在末尾補(bǔ)\0     *(char_result + intArrayLength * 2) = '\0';     jstring stringResult = env->NewStringUTF(char_result);     // release     env->ReleaseByteArrayElements(objArraySign, byte_array_elements, JNI_ABORT);     // 指針     free(char_result);     return stringResult; }  //轉(zhuǎn)換為16進(jìn)制字符串 void toHexStr(const char *source, char *dest, int sourceLen) {     short i;     char highByte, lowByte;     for (i = 0; i < sourceLen; i++) {         highByte = source[i] >> 4;         lowByte = (char) (source[i] & 0x0f);         highByte += 0x30;         if (highByte > 0x39) {             dest[i * 2] = (char) (highByte + 0x07);         } else {             dest[i * 2] = highByte;         }         lowByte += 0x30;         if (lowByte > 0x39) {             dest[i * 2 + 1] = (char) (lowByte + 0x07);         } else {             dest[i * 2 + 1] = lowByte;         }     } }

4.事件就此結(jié)束?

到這里就此結(jié)束了?too yuang too  simple!!!雖然將密鑰和加密算法寫(xiě)在了c++中,貌似好像是比較安全了。但是但是萬(wàn)一別人反編譯后,拿到c++代碼最終生成的so庫(kù),然后直接調(diào)用so庫(kù)里的方法去獲取密鑰并調(diào)用加密方法怎么破?看來(lái)我們還是要加一步身份校驗(yàn)才行:即在native層對(duì)應(yīng)用的包名、簽名進(jìn)行鑒權(quán)校驗(yàn),校驗(yàn)通過(guò)才返回正確結(jié)果。下面就是獲取apk包名和簽名校驗(yàn)的代碼:

const char *PACKAGE_NAME = "你的ApplicationId"; //(簽名的md5值自己可以寫(xiě)方法獲取,或者用簽名工具直接獲取,一般對(duì)接微信sdk的時(shí)候也會(huì)要應(yīng)用簽名的MD5值) const char *SIGN_MD5 = "你的應(yīng)用簽名的MD5值注意是大寫(xiě)";  //獲取Application實(shí)例 jobject getApplication(JNIEnv *env) {     jobject application = NULL;     //這里是你的Application的類(lèi)路徑,混淆時(shí)注意不要混淆該類(lèi)和該類(lèi)獲取實(shí)例的方法比如getInstance     jclass baseapplication_clz = env->FindClass("com/test/component/BaseApplication");     if (baseapplication_clz != NULL) {         jmethodID currentApplication = env->GetStaticMethodID(                 baseapplication_clz, "getInstance",                 "()Lcom/test/component/BaseApplication;");         if (currentApplication != NULL) {             application = env->CallStaticObjectMethod(baseapplication_clz, currentApplication);         }         env->DeleteLocalRef(baseapplication_clz);     }     return application; }   bool isRight = false; //獲取應(yīng)用簽名的MD5值并判斷是否與本應(yīng)用的一致 jboolean getSignature(JNIEnv *env) {     LOGD("getSignature isRight: %d", isRight ? 1 : 0);     if (!isRight) {//避免每次都進(jìn)行校驗(yàn)浪費(fèi)資源,只要第一次校驗(yàn)通過(guò)后,后邊就不在進(jìn)行校驗(yàn)         jobject context = getApplication(env);         // 獲得Context類(lèi)         jclass cls = env->FindClass("android/content/Context");         // 得到getPackageManager方法的ID         jmethodID mid = env->GetMethodID(cls, "getPackageManager",                                          "()Landroid/content/pm/PackageManager;");          // 獲得應(yīng)用包的管理器         jobject pm = env->CallObjectMethod(context, mid);          // 得到getPackageName方法的ID         mid = env->GetMethodID(cls, "getPackageName", "()Ljava/lang/String;");         // 獲得當(dāng)前應(yīng)用包名         jstring packageName = (jstring) env->CallObjectMethod(context, mid);         const char *c_pack_name = env->GetStringUTFChars(packageName, NULL);          // 比較包名,若不一致,直接return包名         if (strcmp(c_pack_name, PACKAGE_NAME) != 0) {             return false;         }         // 獲得PackageManager類(lèi)         cls = env->GetObjectClass(pm);         // 得到getPackageInfo方法的ID         mid = env->GetMethodID(cls, "getPackageInfo",                                "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");         // 獲得應(yīng)用包的信息         jobject packageInfo = env->CallObjectMethod(pm, mid, packageName,                                                     0x40); //GET_SIGNATURES = 64;         // 獲得PackageInfo 類(lèi)         cls = env->GetObjectClass(packageInfo);         // 獲得簽名數(shù)組屬性的ID         jfieldID fid = env->GetFieldID(cls, "signatures", "[Landroid/content/pm/Signature;");         // 得到簽名數(shù)組         jobjectArray signatures = (jobjectArray) env->GetObjectField(packageInfo, fid);         // 得到簽名         jobject signature = env->GetObjectArrayElement(signatures, 0);          // 獲得Signature類(lèi)         cls = env->GetObjectClass(signature);         mid = env->GetMethodID(cls, "toByteArray", "()[B");         // 當(dāng)前應(yīng)用簽名信息         jbyteArray signatureByteArray = (jbyteArray) env->CallObjectMethod(signature, mid);         //轉(zhuǎn)成jstring         jstring str = toMd5(env, signatureByteArray);         char *c_msg = (char *) env->GetStringUTFChars(str, 0);         LOGD("getSignature release sign md5: %s", c_msg);         isRight = strcmp(c_msg, SIGN_MD5) == 0;         return isRight;     }     return isRight; }   //有了校驗(yàn)的方法,所以我們要對(duì)第3步中,獲取密鑰和加密方法的進(jìn)行修改,添加校驗(yàn)的邏輯 extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getHttpSecretKey         (JNIEnv *env, jclass cls, jint index) {     if (getSignature(env)){//校驗(yàn)通過(guò)       if (隨機(jī)數(shù)條件1) {         return env->NewStringUTF(KEY1);       } else if (隨機(jī)數(shù)條件2) {         return env->NewStringUTF(KEY2);       } else if (隨機(jī)數(shù)條件3) {         return env->NewStringUTF(KEY3);       } else {         return env->NewStringUTF(UNKNOWN);       }     }else {         return env->NewStringUTF(UNKNOWN);     } }  extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue         (JNIEnv *env, jclass cls, jbyteArray jbyteArray1) {         //加密算法各有不同,這里我就用md5做個(gè)示范     if (getSignature(env)){//校驗(yàn)通過(guò)        return toMd5(env, jbyteArray1);     }else {         return env->NewStringUTF(UNKNOWN);     } }  作者:AirSj 鏈接:https://juejin.im/post/6862732328406351879 來(lái)源:掘金 著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

到此,相信大家對(duì)“如何理解Android敏感數(shù)據(jù)泄露”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


文章標(biāo)題:如何理解Android敏感數(shù)據(jù)泄露
網(wǎng)站URL:http://weahome.cn/article/ipggoi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部