Android漏洞掃描工具Code Arbiter
目前Android應(yīng)用代碼漏洞掃描工具種類繁多,效果良莠不齊,這些工具有一個共同的特點,都是在應(yīng)用打包完成后對應(yīng)用進行解包掃描。這種掃描有非常明顯的缺點,掃描周期較長,不能向開發(fā)者實時反饋代碼中存在的安全問題,并且對于問題代碼的定位需要手動搜索匹配源碼,這樣就更不利于開發(fā)者對問題代碼進行及時的修改。Code Arbiter正是為解決上述兩個問題而開發(fā)的,專門對Android Studio中的源碼進行安全掃描。
1 背景介紹
為實現(xiàn)對Android Studio中的源碼進行掃描,最方便的方式便是將掃描工具以IDE插件的形式進行工作。此時一個很自然的想法便是從頭構(gòu)建一個Android Studio插件,但是進行仔細(xì)的評估后會發(fā)現(xiàn),這樣做難度并不小:
工作量大,許多知識需要學(xué)習(xí),如IDE開放API接口、插件UI構(gòu)建等,同時許多底層模塊需要從頭構(gòu)建;
插件的穩(wěn)定性、檢測問題的準(zhǔn)確性上都不一定能夠達到已有開源工具的效果。
因此我們轉(zhuǎn)而考慮在已有漏洞檢測插件的基礎(chǔ)上進行擴展,以滿足需求。經(jīng)過調(diào)研,最終入圍的兩款檢測插件是PMD和FindBugs,其中PMD是對Java源碼進行掃描,而FindBugs則是對Java源碼編譯后的class文件進行掃描??紤]到可擴展性及檢測的準(zhǔn)確性,最終選定了FindBugs。FindBugs是一個靜態(tài)分析工具,它檢查類或者JAR文件,將字節(jié)碼與一組缺陷模式進行對比來發(fā)現(xiàn)可能的問題,可以以獨立的JAR包形式運行,也可以作為集成開發(fā)工具的插件形式存在。
擴展優(yōu)化
那么,怎么擴展FindBugs呢?調(diào)研發(fā)現(xiàn)FindBugs插件具有著極強的可擴展性,只需要將擴展的JAR包導(dǎo)入FindBugs插件,重啟,即可完成相關(guān)功能的擴展。安裝JAR包示意圖如下所示。
下面的問題是如何構(gòu)建可安裝的JAR包。繼續(xù)調(diào)研,發(fā)現(xiàn)FindBugs有一款專門對安全問題進行檢測的擴展插件Find Security Bugs,該插件主要用于對Web安全問題進行檢測,也有極少對Android相關(guān)安全問題的檢測規(guī)則??紤]以下幾個原因,需要對該插件的源碼進行重構(gòu)。
對Android安全問題的檢測太少,只包含外部文件使用、Webview、Broadcast使用等寥寥幾項;
檢測的細(xì)粒度上考慮不夠完全,會造成大量的誤報,無法滿足檢測精度的要求;
檢測問題的上報只支持英文模式,且問題展示的邏輯性不夠嚴(yán)謹(jǐn),不便于開發(fā)者進行問題排查。
基于以上三個原因,我們需要對Find Security Bugs的源碼進行重寫、優(yōu)化,通過增加檢測項來檢測盡可能多的安全問題,通過優(yōu)化檢測規(guī)則來減少檢測的誤報,問題展示使用中文進行描述,同時優(yōu)化問題描述的邏輯性,使得開發(fā)者能夠更易理解并修改相關(guān)問題,至此插件實現(xiàn)及優(yōu)化的方案確定。
2 工具實現(xiàn)介紹
FindBugs檢測的是class文件,因此當(dāng)待檢測的源碼未生成編譯文件時,F(xiàn)indBugs會先將源碼編譯生成.class文件,然后對這個class文件進行分析。FindBugs會完成對class文件的自動建模,在此模型的基礎(chǔ)上對代碼進行分析。按照在實際編寫檢測代碼過程中的總結(jié),把檢測的實現(xiàn)方式分成四種方式,下面分別進行介紹。
2.1 逐行檢查
逐行檢查主要是針對代碼中使用的一些不安全方法或參數(shù)進行檢測,其實現(xiàn)方式是重寫sawOpcode()方法,下面以Android中使用外部存儲問題作為示例進行講解。
Android中獲取外部存儲文件夾地址的方法主要包括下面這些方法:
- getExternalCacheDir()
- getExternalCacheDirs()
- getExternalFilesDir()
- getExternalFilesDirs()
- getExternalMediaDirs()
- Environment.getExternalStorageDirectory()
- Environment.getExternalStoragePublicDirectory()
檢測的方式便是,如果發(fā)現(xiàn)存在該方法的調(diào)用,則作為一個問題進行上報,實現(xiàn)完整代碼如下所示:
- public class ExternalFileAccessDetector extends OpcodeStackDetector {
- private static final String ANDROID_EXTERNAL_FILE_ACCESS_TYPE = "ANDROID_EXTERNAL_FILE_ACCESS";
- private BugReporter bugReporter;
- public ExternalFileAccessDetector(BugReporter bugReporter) {
- this.bugReporter = bugReporter;
- }
- @Override
- public void sawOpcode(int seen) {
- //printOpCode(seen);
- if (seen == Constants.INVOKEVIRTUAL && (
- getNameConstantOperand().equals("getExternalCacheDir") ||
- getNameConstantOperand().equals("getExternalCacheDirs") ||
- getNameConstantOperand().equals("getExternalFilesDir") ||
- getNameConstantOperand().equals("getExternalFilesDirs") ||
- getNameConstantOperand().equals("getExternalMediaDirs")
- )) {
- // System.out.println(getSigConstantOperand());
- bugReporter.reportBug(new BugInstance(this, ANDROID_EXTERNAL_FILE_ACCESS_TYPE, Priorities.NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
- }
- else if(seen == Constants.INVOKESTATIC && getClassConstantOperand().equals("android/os/Environment") && (getNameConstantOperand().equals("getExternalStorageDirectory") || getNameConstantOperand().equals("getExternalStoragePublicDirectory"))) {
- bugReporter.reportBug(new BugInstance(this, ANDROID_EXTERNAL_FILE_ACCESS_TYPE, Priorities.NORMAL_PRIORITY).addClass(this).addMethod(this).addSourceLine(this));
- }
- }
- }
該類的實現(xiàn)是繼承OpcodeStackDetector類,是FindBugs中的一個抽象類,封裝了對于獲取代碼特定參數(shù)的方法調(diào)用。sawOpcode方法參數(shù)可以理解為待檢測代碼行的行號,通過printOpCode(seen)可以打印該代碼行的具體內(nèi)容。Constants.INVOKEVIRTUAL表示該行調(diào)用類的實例方法,Constants.INVOKESTATIC表示調(diào)用類的靜態(tài)方法。getNameConstantOperand方法表示獲取被調(diào)用方法的名稱,getClassConstantOperand方法表示獲取調(diào)用類的名稱,getSigConstantOperand方法表示獲取方法的所有參數(shù)。bugReporter.reportBug用于上報檢測到的漏洞信息,其中BugInstance的三個參數(shù)分別表示:檢測器、漏洞類型、漏洞等級,其中漏洞等級分為五個級別,如下表所示:
addClass、addMethod、addSourceLine用于指定該漏洞所在的類、方法、行,方便報告漏洞時定位關(guān)鍵代碼。
2.2 逐方法檢查
逐方法檢查首先獲取待檢測類的所有內(nèi)容,然后對類中的方法進行逐個檢查,多用于對方法體進行檢測,其實現(xiàn)的方法主要是通過重寫visitClassContext方法,下面以對Android TrustManager的空實現(xiàn)的檢測為例進行說明。
TrustManager的空實現(xiàn),主要是指對于檢測Server端證書是否可信的方法checkServerTrusted,是否是空實現(xiàn)。下面展示問題代碼,如果是空實現(xiàn)那么將導(dǎo)致客戶端接收任意證書,從而造成加密后的HTTPS消息被中間人解密。
- @Override
- public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
- }
檢測的方式是通過遍歷類中的所有方法,找到checkServerTrusted方法,對方法整體進行檢測,確定其是否為空實現(xiàn),部分代碼如下所示:
- public class WeakTrustManagerDetector implements Detector {
- ...
- public WeakTrustManagerDetector(BugReporter bugReporter) {
- this.bugReporter = bugReporter;
- }
- @Override
- public void visitClassContext(ClassContext classContext) {
- JavaClass javaClass = classContext.getJavaClass();
- //The class extends X509TrustManager
- boolean isTrustManager = InterfaceUtils.isSubtype(javaClass,"javax.net.ssl.X509TrustManager");
- boolean isHostnameVerifier = InterfaceUtils.isSubtype(javaClass,"javax.net.ssl.HostnameVerifier");
- // if (!isTrustManager && !isHostnameVerifier) return;
- if (!isTrustManager && !isHostnameVerifier){
- for (Method m : javaClass.getMethods()) {
- allow_All_Hostname_Verify(classContext, javaClass, m);
- }
- }
- Method[] methodList = javaClass.getMethods();
- for (Method m : methodList) {
- MethodGen methodGen = classContext.getMethodGen(m);
- if (DEBUG) System.out.println(">>> Method: " + m.getName());
- if (isTrustManager &&
- (m.getName().equals("checkClientTrusted") ||
- m.getName().equals("checkServerTrusted") ||
- m.getName().equals("getAcceptedIssuers"))) {
- if(isEmptyImplementation(methodGen)) {
- bugReporter.reportBug(new BugInstance(this, WEAK_TRUST_MANAGER_TYPE, Priorities.NORMAL_PRIORITY).addClassAndMethod(javaClass, m));
- }
- ......
classContext.getJavaClass用于獲取整個類的所有內(nèi)容;javaClass.getMethods用于獲取該類中的所有方法,以一個方法列表的形式返回;classContext.getMethodGen用于獲取該方法的內(nèi)容;isEmptyImplementation將方法的內(nèi)容導(dǎo)入該函數(shù)進行檢測,用于確定方法是否是空實現(xiàn),該方法的代碼如下所示:
- private boolean isEmptyImplementation(MethodGen methodGen){
- boolean invokeInst = false;
- boolean loadField = false;
- for (Iterator itIns = methodGen.getInstructionList().iterator();itIns.hasNext();) {
- Instruction inst = ((InstructionHandle) itIns.next()).getInstruction();
- if (DEBUG)
- System.out.println(inst.toString(true));
- if (inst instanceof InvokeInstruction) {
- invokeInst = true;
- }
- if (inst instanceof GETFIELD) {
- loadField = true;
- }
- }
- return !invokeInst && !loadField;
- }
該方法主要用于檢測方法中是否包含方法調(diào)用、域操作,如果沒有包含則認(rèn)為是一個空實現(xiàn)的方法。因此該方法對于只包含 return true/false 語句的方法體同樣認(rèn)為是一個空實現(xiàn)。
2.3 污點分析
數(shù)據(jù)流分析主要用于分析特定方法加載的參數(shù)是否能夠被用戶控制,即進行污點分析。做污點分析首先需要定義污染源(source點),污染源可以理解為能夠被用戶控制的輸入數(shù)據(jù),這里定義的Android污染源主要包括用戶的輸入、Intent傳入的數(shù)據(jù),下面展示定義的部分污染源(source點):
- - EditText
- android/widget/EditText.getText()Landroid/text/Editable;:TAINTED
- - Intent
- android/content/Intent.getAction()Ljava/lang/String;:TAINTED
- android/content/Intent.getStringExtra(Ljava/lang/String;)Ljava/lang/String;:TAINTED
- ......
- - Bundle
- android/os/Bundle.get(Ljava/lang/String;)Ljava/lang/Object;:TAINTED
- android/os/Bundle.getString(Ljava/lang/String;)Ljava/lang/String;:TAINTED
- ......
定義好污染源后就需要確定污染的觸發(fā)點(sink點),可以理解為會觸發(fā)危險操作的函數(shù)。定義sink點的方式有兩種,一種是直接從文件中導(dǎo)入,以命令注入為示例,代碼如下:
- public class CommandInjectionDetector extends BasicInjectionDetector {
- public CommandInjectionDetector(BugReporter bugReporter) {
- super(bugReporter);
- loadConfiguredSinks("command.txt", "COMMAND_INJECTION");
- }
從代碼中可以清楚的看到其導(dǎo)入方式是繼承BasicInjectionDetector類,然后再該類的構(gòu)造方法中通過loadConfiguredSinks方法,導(dǎo)入包含sink點的文件,下面展示該示例文件中的內(nèi)容:
- java/lang/Runtime.exec(Ljava/lang/String;)Ljava/lang/Process;:0
- java/lang/Runtime.exec([Ljava/lang/String;)Ljava/lang/Process;:0
- java/lang/Runtime.exec(Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/Process;:0,1
- java/lang/Runtime.exec([Ljava/lang/String;[Ljava/lang/String;)Ljava/lang/Process;:0,1
- java/lang/Runtime.exec(Ljava/lang/String;[Ljava/lang/String;Ljava/io/File;)Ljava/lang/Process;:1,2
- java/lang/Runtime.exec([Ljava/lang/String;[Ljava/lang/String;Ljava/io/File;)Ljava/lang/Process;:1,2
- java/lang/ProcessBuilder.<init>([Ljava/lang/String;)V:0
- java/lang/ProcessBuilder.<init>(Ljava/util/List;)V:0
- java/lang/ProcessBuilder.command([Ljava/lang/String;)Ljava/lang/ProcessBuilder;:0
- java/lang/ProcessBuilder.command(Ljava/util/List;)Ljava/lang/ProcessBuilder;:0
- dalvik/system/DexClassLoader.loadClass(Ljava/lang/String;)Ljava/lang/Class;:0
另一種是自定義導(dǎo)入,其實現(xiàn)是通過覆蓋BasicInjectionDetector類中的getInjectionPoint方法,以WebView.loadurl方法為例,示例代碼如下所示:
- @Override
- protected InjectionPoint getInjectionPoint(InvokeInstruction invoke, ConstantPoolGen cpg, InstructionHandle handle) {
- assert invoke != null && cpg != null;
- String method = invoke.getMethodName(cpg);
- String sig = invoke.getSignature(cpg);
- // System.out.println(invoke.getClassName(cpg));
- if(sig.contains("Ljava/lang/String;")) {
- if("loadUrl".equals(method)){
- if(sig.contains("Ljava/util/Map;")){
- return new InjectionPoint(new int[]{1}, WEBVIEW_LOAD_DATA_URL_TYPE);
- }else{
- return new InjectionPoint(new int[]{0}, WEBVIEW_LOAD_DATA_URL_TYPE);
- }
- }else if("loadData".equals(method)){
- return new InjectionPoint(new int[]{2}, WEBVIEW_LOAD_DATA_URL_TYPE);
- }else if("loadDataWithBaseURL".equals(method)){
- //BUG
- return new InjectionPoint(new int[]{4}, WEBVIEW_LOAD_DATA_URL_TYPE);
- }
- }
- return InjectionPoint.NONE;
- }
通過實例化InjectionPoint類構(gòu)造新的sink點,其構(gòu)造方法中的第一個參數(shù)表示該方法接收污染數(shù)據(jù)參數(shù)的位置,如方法為webView.loadUrl(url),其第一個參數(shù)就是new int[]{0},其它的以此類推。
上報發(fā)現(xiàn)漏洞的情況,則通過覆蓋getPriorityFromTaintFrame方法的實現(xiàn),示例代碼如下所示:
- @Override
- protected int getPriorityFromTaintFrame(TaintFrame fact, int offset)
- throws DataflowAnalysisException {
- Taint stringValue = fact.getStackValue(offset);
- // System.out.println(stringValue.getConstantValue());
- if (stringValue.isTainted() || stringValue.isUnknown()) {
- return Priorities.NORMAL_PRIORITY;
- } else {
- return Priorities.IGNORE_PRIORITY;
- }
- }
通過fact.getStackValue獲取檢測的函數(shù)變量,如果該變量被污染(isTainted)或 變量是否被污染未知(但是是可控制變量),那么作為一個中危風(fēng)險(Priorities.NORMAL_PRIORITY)進行上報,其它的情況則上報為可忽略風(fēng)險(Priorities.IGNORE_PRIORITY)。
2.4 自定義代碼檢測
自定義代碼檢測實現(xiàn)的前半部分同2.2的逐方法檢測類似,均是獲取類的內(nèi)容,然后遍歷所有的方法,對方法的內(nèi)容進行檢測,但是在具體代碼檢測實現(xiàn)上是通過自定義分析進行。目前自定義檢測只應(yīng)用到Android中本地拒絕服務(wù)的檢測。本地拒絕服務(wù)的被觸發(fā)的重要原因在于對通過Intent獲取的參數(shù)未進行異常捕獲,因此檢測實現(xiàn)的方式便是檢測獲取參數(shù)的代碼行是否被try catch包裹(這個存在誤差,待改進)。對于其代碼分析,不能使用FindBugs模型進行分析,而是使用最原始的class代碼進行分析,原始class代碼的形式通過javap命令進行查看,下圖展示示例代碼。
對原始class文件進行分析存在的缺陷是無法定位具體的代碼行,那么在進行問題上報時無法將問題定位到代碼行,因此第一步需要在原有模型的基礎(chǔ)上對所有包含Intent獲取參數(shù)的方法的位置存儲到一個Map結(jié)構(gòu)中,方便后面對方法的定位,代碼實現(xiàn)如下所示,獲取方法所在的行,然后以方法名作為Key值,以代碼行相關(guān)信息作為Value值,存儲到Map中。
- private Map<String, List<Location>> get_line_location(Method m, ClassContext classContext){
- HashMap<String, List<Location>> all_line_location = new HashMap<>();
- ConstantPoolGen cpg = classContext.getConstantPoolGen();
- CFG cfg = null;
- try {
- cfg = classContext.getCFG(m);
- } catch (CFGBuilderException e) {
- e.printStackTrace();
- return all_line_location;
- }
- for (Iterator<Location> i = cfg.locationIterator(); i.hasNext(); ) {
- Location loc = i.next();
- Instruction inst = loc.getHandle().getInstruction();
- if(inst instanceof INVOKEVIRTUAL) {
- INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) inst;
- if(all_line_location.containsKey(invoke.getMethodName(cpg))){
- all_line_location.get(invoke.getMethodName(cpg)).add(loc);
- }else {
- LinkedList<Location> loc_list = new LinkedList<>();
- loc_list.add(loc);
- all_line_location.put(invoke.getMethodName(cpg), loc_list);
- }
- // }
- }
- }
- return all_line_location;
- }
之后獲取Exception包裹的范圍,F(xiàn)indBugs中包含對Exception的建模,因此能夠通過其模型能夠直接獲取其范圍并存儲到一個列表中,代碼如下所示,其中exceptionTable[i].getStartPC用于獲取try catch 的起始代碼行,exceptionTable[i].getEndPC用于獲取try catch 的結(jié)束代碼行。
- public int[] getExceptionScope(){
- try {
- CodeException[] exceptionTable = this.code.getExceptionTable();
- int[] exception_scop = new int[exceptionTable.length * 2];
- for (int i = 0; i < exceptionTable.length; i++) {
- exception_scop[i * 2] = exceptionTable[i].getStartPC();
- exception_scop[i * 2 + 1] = exceptionTable[i].getEndPC();
- }
- return exception_scop;
- }catch (Exception e){
- }
- return new int[0];
- }
在對代碼進行逐行檢查時,因為使用的是最原始class文件形式,因此需要限定其遍歷的范圍,限定的方式是通過代碼的行號,即上圖中每行代碼的第一個數(shù)值。首先需要獲取代碼總行數(shù)的大小,獲取的方式便是解析FindBugs建模后的第一行代碼,找到關(guān)鍵詞code-length后面的數(shù)值,即為代碼的行數(shù),解析代碼如下所示:
- public int get_Code_Length(String firstLineCode){
- try{
- String[] split1 = firstLineCode.split("code_length");
- // System.out.println(split1[split1.length-1]);
- byte[] code_length_bytes = split1[split1.length-1].getBytes();
- byte[] new_code_bytes = new byte[code_length_bytes.length];
- for(int i=0; i<code_length_bytes.length; i++){
- // System.out.println();
- if(code_length_bytes[i]<48 || code_length_bytes[i]>57){
- new_code_bytes[i] = 32;
- }else{
- new_code_bytes[i] = code_length_bytes[i];
- }
- }
- return Integer.parseInt(new String(new_code_bytes).trim());
- }catch(Exception e){
- e.printStackTrace();
- }
- return 0;
- }
最后對代碼進行逐行遍歷,遍歷中為防止try catch塊被遍歷到,使用行號來限制遍歷的范圍。檢測代碼行是否包含通過Intent獲取參數(shù),及該行是否被try catch 包裹,如果上述兩個條件均被觸發(fā),那么就作為一個問題進行上報。示例代碼如下,其中g(shù)et_code_line_index方法用于獲取代碼的行號,獲取的方式是截取代碼行的首字符的數(shù)值,以確定是否在代碼包裹的范圍內(nèi)。
- private void analyzeMethod(JavaClass javaClass, Method m, ClassContext classContext) throws CFGBuilderException {
- HashMap<String, List<Location>> all_line_location = (HashMap<String, List<Location>>) get_line_location(m, classContext);
- Code code = m.getCode();
- StringCodeAnalysis sca = new StringCodeAnalysis(code);
- String[] codes = sca.codes_String_Array();
- int code_length = sca.get_Code_Length(sca.get_First_Code(codes));
- int[] exception_scop = sca.getExceptionScope();
- for(int i=1; i<codes.length; i++){
- int line_index = sca.get_code_line_index(codes[i]);
- if (line_index < code_length){
- if(codes[i].toLowerCase().contains("invokevirtual") &&
- (codes[i].contains("android.content.Intent.get") || codes[i].contains("android.os.Bundle.get"))){
- if(exception_scop.length == 0){
- ......
- }else{
- boolean is_scope = false;
- for(int j=0; j<exception_scop.length; j+=2){
- int start = exception_scop[j];
- int end = exception_scop[j+1];
- if(line_index >= start && line_index <= end){
- is_scope = true;
- }
- if(is_scope){
- break;
- }
- }
- if(!is_scope){
- String method_name = get_method_name(codes[i]);
- if(all_line_location.containsKey(method_name)){
- for(Location loc : all_line_location.get(method_name)){
- bugReporter.reportBug(new BugInstance(this, LOCAL_DENIAL_SERVICE_TYPE, Priorities.NORMAL_PRIORITY).addClass(javaClass).addMethod(javaClass, m).addSourceLine(classContext, m, loc));
- }
- }else {
- bugReporter.reportBug(new BugInstance(this, LOCAL_DENIAL_SERVICE_TYPE, Priorities.NORMAL_PRIORITY).addClass(javaClass).addMethod(javaClass, m));
- }
- }
- }
- }
- }
- }
- }
3 注冊打包
上面詳細(xì)敘述了如何構(gòu)造自己的問題檢測代碼,完成檢測方法的書寫后,下一步就是在配置文件中對檢測方法進行注冊,才能使檢測代碼運轉(zhuǎn)起來。
需要在兩個文件中進行注冊,第一個是findbugs.xml,注冊示例如下:
- <Detector class="com.h3xstream.findsecbugs.android.LocalDenialOfServiceDetector" reports="LOCAL_DENIAL_SERVICE"/>
- <BugPattern type="LOCAL_DENIAL_SERVICE" abbrev="SECLDOS" category="Android安全問題" cweid="276"/>
其中Detector用于注冊該檢測方法的位置及其唯一標(biāo)識,BugPattern用于對檢測出的問題進行歸類,方便展示,如此處歸類到"Android安全問題"中,那么在生成報告的時候問題也將被歸類到"Android安全問題"中。
第二個是messages.xml注冊,注冊示例如下,該注冊主要是對該問題進行說明,包括問題的危害及修復(fù)方法。
- <Detector class="com.h3xstream.findsecbugs.android.LocalDenialOfServiceDetector"> <Details>Local Denial of Service.</Details> </Detector> <BugPattern type="LOCAL_DENIAL_SERVICE"> <ShortDescription>本地拒絕服務(wù)</ShortDescription> <LongDescription>通過Intent接收的參數(shù)未進行異常捕獲,導(dǎo)致出現(xiàn)異常使得應(yīng)用崩潰</LongDescription> <Details> <![CDATA[ <p> <b>危害:</b><br/> <pre> 應(yīng)用崩潰無法使用,影響用戶體驗; 被競爭對手利用,進行點對點攻擊。 </pre> </p> <p> <b>錯誤代碼:</b><br/> <pre> bundle.getString(""); //未try/catch intent.getStringExtra(""); //未try/catch </pre> </p> <p> <b>解決方案:</b><br/> <pre> 對通過Intent接收的參數(shù)處理時,進行嚴(yán)格的異常捕獲。 try { bundle.getString(""); intent.getStringExtra(""); }catch (Exception e){} </pre> </p> ]]> </Details> </BugPattern> <BugCode abbrev="SECLDOS">本地拒絕服務(wù)</BugCode>
一切完成就緒后使用Maven進行打包,就生產(chǎn)了供FindBugs集成開發(fā)工具插件使用的JAR包,完成安裝并重啟,即可使用自定義插件對特定問題進行檢測。
最終分析的效果圖如下圖所示:
4 結(jié)語
本文介紹了Android集成開發(fā)環(huán)境Android Studio的代碼實時檢測工具Code Arbiter的產(chǎn)生原因及代碼實現(xiàn),最后展示了分析的效果。通過Code Arbiter在生產(chǎn)環(huán)境中的應(yīng)用,其檢測效果還是相當(dāng)不錯,能夠發(fā)現(xiàn)很多編碼過程中存在的問題。但是Code Arbiter仍然存在許多不足,需要優(yōu)化。后續(xù)將在以下兩個方面對工具進行改進:
擴大漏洞檢測范圍,使Code Arbiter能夠囊括Android編碼常見安全問題;
優(yōu)化漏洞檢測規(guī)則,提高檢測的準(zhǔn)確性,減少誤報。
5 作者簡介
建弋,2016年加入美團點評,目前主要負(fù)責(zé)金融部門相關(guān)的安全工作。
【本文為51CTO專欄機構(gòu)“美團點評技術(shù)團隊”的原創(chuàng)稿件,轉(zhuǎn)載請通過微信公眾號聯(lián)系機構(gòu)獲取授權(quán)】