【安全开发】Android安全编码规范

申明:本文非笔者原创,原文转载自:https://github.com/SecurityPaper/SecurityPaper-web/blob/master/_posts/2.SDL%E8%A7%84%E8%8C%83%E6%96%87%E6%A1%A3/2018-08-17-SDL-6-Android%E5%AE%89%E5%85%A8%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83.md

1.目的

为使系统开发人员能够编写符合安全要求的代码,以降低代码安全漏洞,减少代码被利用的可能性,从而提升各系统安全水平,符合国家安全合规性要求,保障产品安全稳定运营以及信息安全,特制定本规范。

2.引用规范

  • 《信息安全技术移动智能终端个人信息保护技术要求》
  • 《YD/T 1438-2006 数字移动台应用层软件功能要求和测试方法》
  • 《YD/T 2307-2011 数字移动通信终端通用功能技术要求和测试方法》
  • 《中国金融移动支付客户端技术规范》
  • 《中国金融移动支付应用安全规范》
  • 《移动互联网应用软件安全评估大纲》
  • 《中国国家信息安全漏洞库CNNVD》
  • 《OWASP Mobile Top 10 2017》

3.适用范围

本规范适用于研发中心各级产品的设计、开发及管理过程。其它研发机构可参考本管理规范; Android安全编码规范目标是为开发人员提供安全编码学习的参考资料,也可为Android安全编码和Android安全编码人工审计提供依据。 安全编码原则:

长远性和现实性相结合

既要兼顾银行的目前状况与长远发展等因素,放眼未来、统筹规划,又要具有可行性。

全面性和针对性相结合

既要具有全面性、着眼全局、不能遗漏,又要突出重点,建设方案和实施计划具有较强的针对性。

整体性和阶段性相结合

既要制定整体发展规划、安全建设蓝图等战略性指导和安全策略文档,又要制定出体系实施的阶段性目标,分期分批实施。

先进性和实用性相结合

在信息安全战略和策略、目标和要求、规定和制度、技术、人员和知识等各方面,既要有先进性(例如虚拟化技术),又要有实用性。

开放性和可扩展性相结合

应采用最新且成熟的体系框架,保证具有开放性和可扩展性。

完整性和经济性相结合

既要考虑采用的产品和技术在整体上具有完整性和一致性,又要尽量保护银行已有的软硬件投资,使得总体上具有更好经济性。


4.安全编码规则

本篇参考OWASP Mobile Top 10 2016分别从平台使用不当、不安全的数据储存、不安全的通信、不安全的认证、加密不足、不安全的授权、客户端的代码质量、代码篡改、逆向工程、多余的功能、其他安全问题10个方面规定了如何在代码方面防范软件安全问题。这些问题一旦出现将会形成软件安全漏洞如秘钥使用不当、件最小化组件暴露等造成生产安全事故,可能带来经济、客户、声誉等方面重大的损失。

4.1.平台使用不当


4.1.1.定义

“平台使用不当”包涵Android控件的配置不当或编码不当。包括Activity、Service、ContentProvider、Broadcast Receiver、Intent组件、WebView组件使用过程中配置是否规范与编码是否规范。

4.1.2.风险

“平台使用不当”会造成的风险包括组件被恶意调用、恶意发送广播、恶意启动应用服务、恶意调用组件,拦截组件返回的数据、远程代码执行等。

4.1.3.防范方法

4.1.3.1.预防组件最小化组件暴露
  • 【规范要求】

针对不需要进行跨应用调用的组件,应在配置文件(AndroidManifest.xml)中显示配置android:exported="false"属性。

【详细说明】

组件配置android:exported="false"属性,表明它为私有组件,只可在同一个应用程序组件间或带有相同用户ID的应用程序间才能启动或绑定该服务。在非必要情况下,如果该属性设置为“true”,则该组件可以被任意应用执行启动操作,造成组件恶意调用等风险。

  • 【代码示例】

AndroidManifest.xml配置文件中activity组件的配置方式示例。

反例

<activity
     android:name="com.example.bkdemo2.LoginActivity" android:exported="true" android:label="@string/app_name" > </activity>

正例

<activity
     android:name="com.example.bkdemo2.LoginActivity" android:exported="false" android:label="@string/app_name" > </activity>

4.1.3.2.公开的组件安全
  • 【规范要求】

因特殊需要而公开的Activity、Service、Broadcast Receiver、Content Provider组件建议添加自定义permission权限进行访问控制。

  • 【详情说明】

因特殊需要而公开(exported=”true”)的对于需要公开的 Activity、Service、Broadcast Receiver、Content Provider组件采用自定义访问权限的方法提供访问控制波保护。通过自定义访问权限保护后公开的组件只能被申请了该权限的外部应用(Application)调用,未申请权限的外部应用(Application)在调用时将会出现“java.lang.SecurityException: Not allowed to bind to service Intent”异常,造成调用失败。

程序中的启动/使用Activity、Service、Broadcast Receiver、Content Provider则由程序定位与需求来确认是否添加自定义访问权限,启动的Activity、Service、Broadcast Receiver、Content Provider本身是需要被其他程序进行调用的,如果没有特殊需求(该程序只允许指定APP启动)的话就不能添加该权限。

【代码示例】

  1. AndroidManifest.xml中的定义/注册权限的写法为:
<permission
      android:name="com.ijiami.permission.testPermission" android:label="@string/app_name" android:protectionLevel="normal" />

2)AndroidManifest.xml中Activity组件使用已注册的自定义权限写法为:

<activity
      android:name="com.example.bkdemo2.LoginActivity" android:exported="true" android:label="@string/app_name" android:permission="com.ijiami.permission.testPermission" > </activity>

3)AndroidManifest.xml中Service组件使用已注册的自定义权限写法为:

<Service
      android:name="com.example.bkdemo2.LoginService" android:exported="true" android:label="@string/app_name" android:permission="com.ijiami.permission.testPermission" > </ Service>

4)AndroidManifest.xml中Receiver组件使用已注册的自定义权限写法为:

<receiver  
      android:name="com.example.bkdemo2.testReceiver" android:exported="true" android:label="@string/app_name" android:permission="com.ijiami.permission.testPermission" > </receiver>

5)Receiver组件使用已注册的自定义权限写法(代码中使用):

IntentFilter iFilter = new IntentFilter();
iFilter.addAction("com.example.bkdemo2.testReceiver");
this.registerReceiver(myReciver, iFilter, "com.ijiami.permission.testPermission", handler);

6)AndroidManifest.xml中ContentProvider组件使用已注册的自定义权限写法为:

<provider
      android:name="com.example.bkdemo2.testProvider" android:exported="true" android:label="@string/app_name" android:permission="com.ijiami.permission.testPermission" > </provider>

7)外部应用需要使用自定义权限的写法(AndroidManifest.xml配置)为:

<uses-permission android:name="com.ijiami.permission.testPermission" />

8)外部应用Receiver组件需要使用自定义权限的写法(代码中配置)为:

this.sendBroadcast(intent, "com.ijiami.permission.testPermission");

4.1.3.3.ContentProvider安全
  • 【规范要求】

对于不同场景的ContentProvider数据需配置不同的组件参数、造函数参数,对ContentProvider数据的使用过程进行保护。ContentProvider需要通过配置组件参数与设置不同构造函数参数来对不同场景的数据使用进行保护。

  • 【详情说明】

ContentProvider组件是数据提供者组件,可以为外部应用提供统一的数据存储和读取接口。在ContentProvider的使用过程中,应根据业务的需要,严格控制数据的增删改查权限,避免非必要的权限开放。非必要的权限开放会造成数据泄露、数据完整性被破坏等安全风险。如:一段只读数据开放了可写权限,则任何的外部应用都可以对该数据进行篡改,造成数据损坏。一个Provider里面可能有私有数据,也有公有数据。也就是说,有可能有些数据可以公开,有些不能公开。并且,有些数据可以让别人修改,有些不能让别人修改。

  • 【代码示例】
  1. 单独对设置pathPattern下的访问控制权限(访问pathPattern路径下需要permission权限):
  2. 对设置了pathPattern的provider添加自定义访问控制权限(访问pathPattern路径下文件需要添加自定义permission权限):
<provider
      android:name=".testProvider" android:authorities="com.ijiami.testProvider" android:multiprocess="true"> <path-permission android:pathPattern="/apk/.*" android:permission="com.ijiami.testProvider.permission.application.  read"/> </provider>

3)provider设置全局可读权限:

<provider
     android:name=".testProvider" android:authorities="com.ijiami.testProvider" android:multiprocess="true" android:readPermission="com.ijiami.permission.readPermission" > </provider>

4)provider设置全局可写权限:

<provider
     android:name=".testProvider" android:authorities="com.ijiami.testProvider" android:multiprocess="true" android:writePermission="com.ijiami.permission.writePermission" > </provider>

5)provider设置全局可读/写权限:

<provider
     android:name=".testProvider" android:authorities="com.ijiami.testProvider" android:multiprocess="true" android:permission="com.ijiami.permission.writeAndReadPermission" > </provider>

4.1.3.4.Intent意图使用
  • 【规范要求】

为了更高的数据安全及更小的性能消耗,在使用Intent进行组件(Activity、Content provider、Broadcast receiver、Service)间跳转时应尽量使用显示调用,非特殊情况,应避免使用隐式调用Intent进行权限设置,包括Activity、Content provider、Broadcast receiver、Service等,为了数据安全与性能消耗须使用显式调用尽量减少使用隐式调用。

  • 【详情说明】

显式调用:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,使用Intent.setComponent()、Intent.setClassName()、Intent.setClass()方法进行目标组件的指向或者在Intent对象初始化“new Intent(A.class,B.class)”时指明需要转向的组件。显式调用意图明确的指定了要激活的组件,一般在应用程序内部组件间跳转时都应使用显示调用。

隐式调用:通过Intent Filter来实现的,它一般在不能明确知道目标组件名称的情况下,通过设置动作(action)、类别(category)、数据(URI和数据类型)等隐式意图的方式来进行目标跳转,Android系统会根据设置的隐式意图找到最合适的组件作为目标组件进行跳转。隐式调用一般是用于在不同应用程序之间的组件跳转,因跳转目标是由系统来进行判断,特殊情况下会出现目标错误,造成传递数据泄露的安全风险,并且隐式调用对性能消耗较大。

  • 【代码示例】

显式调用代码:

Intent intent = new Intent();
Bundle bundle = new Bundle(); bundle.putString("id", "strID"); intent.setClass(this, Intent_Demo1_Result1.class); intent.putExtras(bundle); startActivity(intent);

4.1.3.5.预防Webview远程代码执行

【规范要求】

无特殊原因,targetSdkVersion设置应大于等于17。如因特殊需要targetSdkVersion版本设置低于17,应禁止Webview远程代码执行权限,防止被远程控制。

【详情说明】

android targetSdkVersion版本低于17时,WebView组件存在远程代码执行漏洞,中间人可以利用Webview的漏洞执行任意代码。

如果由于特殊原因需要把targetSdkVersion设置为低于17的时候,因webView本身存在的安全漏洞,应对webView.load指定加载的url/path的html/js文件进行认证与完整性验证,确包加载的url/path完整性,防止因为url/path被篡改而造成的远程控制的代码执行风险。

【代码示例】

<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />

4.1.3.6.数据备份和恢复设置

  • 【规范要求】

正式发布的应用应关闭数据备份功能。应在AndroidManifest.xml的Application参数设置中将android:allowBackup参数显示设置为“false”,关闭非root情况下允许对应用数据的备份与恢复功能。

  • 【详情说明】

当在AndroidManifest.xml中application配置参数allowBackup被设置为true或不设置该标志时,应用程序数据可以再非root状态下进行数据的备份和恢复,攻击者可以通过adb调试指令直接复制应用程序数据。造成应用数据泄露风险。

  • 【代码示例】
android:allowBackup="false"

4.2.不安全的数据储存


4.2.1.定义

“不安全的数据储存”涵盖了平台功能的误用或平台安全控件使用失败引起的问题与预防方案,其中包括:SharedPreference数据储存安全、密码储存安全、sdcard数据储存安全。

4.2.2.风险

Android编码规范中“不安全的数据储存”会造成的风险包括:密码泄露、敏感信息泄露、敏感数据完整性破坏等风险。

4.2.3.防范方法

4.2.3.1.SharedPreference数据储存安全
  • 【规范要求】

进行SharedPreference数据存储时应使用私有化(MODE_PRIVATE模式)存储模式。避免使用共享可读、可写模式存储。

  • 【详情说明】

MODE_WORLD_READABL或MODE_WORLD_READABLE模式存储数据表示该数据是可共享给其他外部程序使用的,目前在android4.0以上版本已经废弃了该模式,建议在使用SharedPreference存储时应采用MODE_PRIVATE进行私有化模式存储,防存在内容被替换的风险。

  • 【代码示例】

反例:存在数据安全风险的SharedPreference创建方式:

SharedPreferences mySharedPreferences= getSharedPreferences("test",Activity.MODE_WORLD_READABLE); SharedPreferences mySharedPreferences= getSharedPreferences("test",Activity.MODE_WORLD_WRITEABLE);

正例:安全规范的SharedPreference创建方式:

SharedPreferences mySharedPreferences= getSharedPreferences("test",Activity.MODE_PRIVATE);

4.2.3.2.密码储存安全
  • 【规范要求】

在特殊情况下需要对密码进行落地存储,不应存储用户的密码信息,而是存储用户的密码的摘要(HASH)信息,每次用户登录时进行摘要匹配。

  • 【详情说明】

本地进行密码信息存储时,应储存密码的摘要(HASH)信息。预防终端被ROOT情况下,受保护的系统目录下的本地储存数据被随意访问造成密码泄露风险。

4.2.3.3.避免使用sdcard数据储存
  • 【规范要求】

在进行数据避免将数据储存到sdcard中,尽量使用sqlite、sharedpreferences或系统私有目录的file文件进行数据储存。

  • 【详情说明】

使用外部存储实现数据持久化,这里的外部存储一般就是指的是sdcard。使用sdcard存储的数据,不限制只有本应用访问,任何可以有访问Sdcard权限的应用均可以访问,容易导致信息泄漏安全风险。

4.3.不安全的通信

4.3.1.定义

“不安全的通信”涵盖了在Android代码编写过程使用不安全的方式进行客户端与服务端业务交互,比如:通讯数据安全、会话安全等。

4.3.2 风险

Android编码规范中“不安全的通信”可能造成服务端储存的数据被无权限访问风险。

4.3.3.防范方法

4.3.3.1.会话安全
  • 【规范要求】

使用Http协议进行会话时,建议将session ID设置在Cookie头中,服务器根据该sessionID获取对应的Session,而不是重新创建一个新Session。

  • 【详情说明】

当客户端访问一个使用session 的站点,同时在自己机器上建立一个cookie时,如果未使用服务端的session机制进行会话通信则可能造成服务端储存的数据存在被任意访问风险。

  • 【代码示例】
java.net.HttpURLConnection获取Cookie:
URL url = new URL("requrl"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); // 取得sessionid. String cookieval = con.getHeaderField("set-cookie"); String sessionid; if (cookieval != null) { sessionid = cookieval.substring(0, cookieval.indexOf(";")); } java.net.HttpURLConnection发送设置cookie: URL url = new URL("requrl"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); if (sessionid != null) { con.setRequestProperty("cookie", sessionid); } org.apache.http.client.HttpClient设置cookie: HttpClient http = new DefaultHttpClient(); HttpGet httppost = new HttpGet("url"); httppost.addHeader("Cookie", sessionId);

4.4.不安全的认证


4.4.1.定义

“不安全的认证”指在一个Android应用程序中,如果试图在没有适当的安全措施的情况下,仅仅通过客户端检测进行用户验证或授权,那么就是存在不安全认证的风险,比如:预防WebView自动保存密码功能。

4.4.2.风险

Android编码中“不安全的认证”会造成的风险包括:WebView使用使用过程中的密码泄露;

4.4.3.防范方法

4.4.3.1.预防WebView自动保存密码功能
  • 【规范要求】

在使用WebView控件时,应显示关闭控件自带的记住密码功能。即:设置WebView.getSettings().setSavePassword(false);

  • 【详情说明】

Google在设计WebView的时候提供默认自带记住密码的功能,即程序在不设置theWebView.getSettings().setSavePassword(false);的时候WebView在使用密码控件后会自动弹出界面提示用户是否记住密码,如果用户选择“记住”选择项后密码会明文储存在/data/data/com.package.name/databases/webview.db中,如果设备中出现了Root提权的其他应用的时候该应用则可直接读取所有应用通过webView储存的密码。所以在使用Webview时应显示关闭Webview的自动保存密码功能,防止用户密码被Webview明文存储在设备中。

  • 【代码示例】

1)关闭WebView的自动保存密码功能代码为:

theWebView.getSettings().setSavePassword(false);

2)不关闭WebView的自动保存密码功能时功能提示截图:

功能提示截图


4.5.加密不足


4.5.1.定义

“加密不足”指当一个Android程序存储数据的位置本身教脆弱时,那么这个漏洞就会产生,比如:加密算法使用不规范、硬编码形式储存密钥等。

4.5.2.风险

Android编码规范中“加密不足”会造成的风险包括:已加密的敏感数据被破解与窃取风险。

4.5.3.防范方法

4.5.3.1.加密算法使用规范
  • 【规范要求】
  1. 不建议对密码等敏感信息使用如下加密算法:
    • MD2
    • MD4
    • MD5
    • SHA-1
    • PIPEMD

2)安全规范建议使用加密算法:

    • SHA-256
    • SHA-3
  • 【代码示例】

反例:不建议对密码、敏感等信息使用的加密算法类型(MD5):

MessageDigest md = MessageDigest.getInstance("MD5"); byte[] md5Bytes = md.digest("password".getBytes()); String result = Base64.encodeToString(md5Bytes, Base64.DEFAULT);

正例:安全规范对密码、敏感信息加密要求使用的算法类型(SHA-256):

byte[] input = "password".getBytes(); MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); sha256.update(input); byte[] output = sha256.digest(); String result = Base64.encodeToString(output, Base64.DEFAULT);

4.5.3.2.禁止硬编码形式存储密钥
  • 【规范要求】

1)使用SharedPreference进行密钥存储时,应对密钥进行加密处理。使用so库进行密钥的存储,并且将整体的加密、解密操作都放在so库中进行。将密钥进行加密存储在assets目录下,将加密、解密过程存储在so库文件中,并对so库文件进行加壳等安全保护,增强密钥保护的安全强度。

  • 【详情说明】

信息安全的基础在于密码学,而常用的密码学算法都是公开的,加密内容的保密依靠的是密钥的保密,密钥如果泄露,对于对称密码算法,根据用到的密钥算法和加密后的密文,很容易得到加密前的明文;对于非对称密码算法或者签名算法,根据密钥和要加密的明文,很容易获得计算出签名值,从而伪造签名。

【代码示例】

反例

/**
  * DES算法,加密
  *
  * @param data
 * 待加密字符串  * @param key  * 加密私钥,长度不能够小于8位  * @return 加密后的字节数组,一般结合Base64编码使用  * @throws CryptException  *        异常  */ private static String encode(String key, byte[] data) throws Exception { try { DESKeySpec dks = new DESKeySpec(key.getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); Key secretKey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(ALGORITHM_DES); IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); AlgorithmParameterSpec paramSpec = iv; cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec); byte[] bytes = cipher.doFinal(data); return Base64.encodeToString(bytes, 0); } catch (Exception e) { throw new Exception(e); } }

正例:

  /**
  * DES算法,解密
  *
  * @param data
 * 待解密字符串  * @param key  * 解密私钥,长度不能够小于8位  * @return 解密后的字节数组  * @throws Exception  * 异常  */ private static byte[] decode(String key, byte[] data) throws Exception { try { DESKeySpec dks = new DESKeySpec(key.getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); Key secretKey = keyFactory.generateSecret(dks); Cipher cipher = Cipher.getInstance(ALGORITHM_DES); IvParameterSpec iv = new IvParameterSpec("12345678".getBytes()); AlgorithmParameterSpec paramSpec = iv; cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec); return cipher.doFinal(data); } catch (Exception e) { throw new Exception(e); } }

4.6.不安全的授权


4.6.1.定义

“不安全的授权”指在一个Android应用程序中,如果试图在没有适当的安全措施的情况下,仅仅通过客户端检测进行用户验证或授权,那么就是存在风险的,比如:分配唯一ID安全策略、避免使用IMEI作为设备唯一ID等。

4.6.2.风险

Android编码规范中“不安全的授权”造成的风险包括:本地储存的敏感数据被非法替换、APP被恶意刷量、信息伪造等风险。

4.6.3.防范方法

4.6.3.1.分配唯一的ID
  • 【规范要求】

为每一个具有访问权限的用户分配唯一的ID,以保证任何对关键数据和支付软件进行的操作都能够被追溯到已知的、被授权的用户。

  • 【详情说明】

为每一个具有访问权限的用户分配唯一的ID,以保证任何对关键数据和支付软件进行的操作都能够被追溯到已知的、被授权的用户;唯一ID的使用场景分析如下:

1)存在安全隐患的数据储存方案如下:

存在安全隐患的数据储存方案

通过如上方案加密的数据未与终端或用户唯一ID绑定,数据可直接被抽离出来后重新在任何其他终端被使用。

2)进行安全规范类加密的原理如下:

进行安全规范类加密的原理

通过如上方案对数据加密后,秘钥的组成加入终端或用户唯一ID,即使在数据被抽离出来后使用到任意APP中,但该数据由于在解密使用过程中与终端或用户的唯一ID不匹配而导致数据解密失败,无法使用,能有效防范数据调用的风险。

4.6.3.2.避免使用IMEI作为设备唯一ID
  • 【规范要求】

在需要使用设备唯一ID的业务场景中,应使用DEVICE_ID、MAC ADDRESS、Sim Serial Number、IMEI等数据据组装后生成Hash值来作为设备唯一ID。避免单独使用IMEI作为设备唯一ID标识。

  • 【详情说明】

由于Android领域中有不少模拟器而模拟器可模拟与篡改IMEI;IMEI在个别特殊系统与终端在中是无法获取到的,基于如上分析如果把IMEI作为设备的唯一ID将出现一定的重复几率。

  • 【代码示例】

1)获取DEVICE_ID

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); String DEVICE_ID = tm.getDeviceId();

2)获取MAC ADDRESS

WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiInfo info = wifi.getConnectionInfo(); String macAdress = info.getMacAddress();

3)获取Sim Serial Number

TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); String SimSerialNumber = tm.getSimSerialNumber();

4)获取IMEI

String IMEI = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();

4.7.客户端代码质量


4.7.1.定义

“客户端代码质量”指一个Android应用程序在编码过程中使用错误配置、过时API、缺少校验等编码而造成的风险,比如:APP拒绝服务、targetSdkVersion设置、随机数使用规范、禁止输出日志信息等。

4.7.2.风险

Android编码规范中“客户端代码质量”会造成的风险包括:APP拒绝服务、使用WebView时引起的远程恶意代码执行、使用随机数业务出现规律、应用敏感数据泄露等。

4.7.3.防范方法

4.7.3.1.预防APP拒绝服务
  • 【规范要求】

对组件间传递的参数在接收前进行非空验证,避免因空参数造成的APP拒绝服务

  • 【详情说明】

Activity,Service等组件因业务需要,部分是对外开放的(AndroidManifest.xml中exported属性为true或定义的intent-filter的组件是可导出组件),当这些组件对外部应用传递的参数未做校验时,可能因传入参数异常导致APP拒绝服务。对外开放组件要求严格校验输入参数,注意空值判定及类型转换判断,防止由于解析异常参数导致的应用崩溃。

  • 【代码示例】
  1. 反例:会造成APP拒绝服务的Activity带参数跳转
@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = getIntent(); Bundle mBundle = intent.getExtras(); String getValue = mBundle.getString("value"); }

2)正例:预防造成APP拒绝服务的Activity带参数跳转

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = getIntent(); if (intent == null) return; Bundle mBundle = intent.getExtras(); if (mBundle == null) return; String getValue = mBundle.getString("value"); if (getValue == null) return; }

4.7.3.2.targetSdkVersion设置
  • 【规范要求】

因业务需要,在代码在那个需要使用低版本系统API是,通常我们会使用反射系统API的方式来进行调用,如果低版本系统API与高版本系统API存在冲突时,系统会参考清单文件(AndroidManifest.xml)中配置的targetSdkVersion参数来匹配最佳的系统API。如果因特殊原因需要把targetSdkVersion值设置为低于17时,由于webView的安全漏洞问题,需要对webView.load加载指定的url/path的html/js进行认证与完整性验证,确认load的url/path为原始文件,而非被篡改后文件。防止加载的文件存在恶意注入的远程控制代码。

  • 【详情说明】

因Webview组件自身漏洞,建议AndroidManifest.xml中的targetSdkVersion属性应设置为大于等于17。targetSdkVersion=”17”即表示程序的测试目标机器是os 4.2系统,不建议把targetSdkVersion的参数设置低于17,主要的原因包括:1)os4.2以下系统的手机现阶段市场占有率非常低 2)os4.2及其以上的系统修复了之前系统中存在的大量安全问题与Bug,比如webView的安全问题等等;

注意:程序中使用低版本API函数情况的时候,程序会使用反射来进行低版本函数API的调用。如果有重复API与修复API的冲突时候程序会参考targetSdkVersion的设置选择最佳API进行调用或者反射。

  • 【代码示例】
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" />

4.7.3.3.随机数使用规范
  • 【规范要求】

因业务要求需要在代码中使用随机数功能,随机概率功能应通过/dev/urandom或者/dev/random获取的熵值对伪随机数生成器PRNG进行初始化操作。

  • 【详情说明】

使用SecureRandom时不要使用SecureRandom(byte[]seed)这个构造函数,会造成生成的随机数不随机。建议通过/dev/urandom或者/dev/random获取的熵值对伪随机数生成器PRNG进行初始化操作。

  • 【代码示例】

1)反例(不安全的随机数获取方法):

Random mRandom = new Random();
int rNum = mRandom.nextInt() * 10; byte[] seed = new byte[16]; SecureRandom mSRandom = new SecureRandom(seed); byte[] seed = new byte[16]; SecureRandom mSRandom = new SecureRandom(); mSRandom.setSeed(seed); long seed = 123451; SecureRandom mSRandom = new SecureRandom(); mSRandom.setSeed(seed);

2)正例(安全规范类的随机数获取方法):

byte[] output =new byte[16];
SecureRandom mSRandom = new SecureRandom(); mSRandom.nextBytes(output);
4.7.3.4.发布应用中禁止输出日志信息
  • 【规范要求】

  • 1)因app的错误采集、异常反馈等需求而必要的日志建议遵循的安全编码规范:

    • Log.e()/Log.w()/Log.i():建议打印操作日志;
    • Log.d()/Log.v():建议打印开发日志;
  • 2)敏感信息不应用Log.e()/Log.w()/Log.i(), System.out/System.err 进行打印;

  • 3)敏感信息打印建议使用 Log.d()/Log.v()(前提:release版本将被自动去除);

  • 4)公开的APK文件应该是release版而不是development版;

  • 5)使用android.util.Log类的方法输出日志,不推荐使用System.out/err;

  • 6)ProGuard不能移除如下日志:Log.w(“Log”,"result:" + value).,所以建议使用全局变量控制日志的输出;

  • 7)不建议将日志输出到sdscard中,因为sdcard的文件可被任何APP进行访问与读写。

  • 【详情说明】

  • 1) development version :

开发版,正在开发内测的版本,会有许多调试日志;

  • 2)release version :

发行版,签名后开发给用户的正式版本,日志量较少;

  • 3)android.util.Log提供了五种输出日志的方法:

Log.e(), Log.w(), Log.i(), Log.d(), Log.v();

  • 【代码示例】

安全规范建议使用日志统一管理代码:

import android.util.Log;
/**
 * Log统一管理类
 *
 *
 * */ public class MyLog { private MyLog() { /* cannot be instantiated */ throw new UnsupportedOperationException("cannot be instantiated"); } // 是否需要打印bug,可以在application的onCreate函数里面初始化 public static boolean isDebug = true; private static final String TAG = "way"; // 下面四个是默认tag的函数 public static void i(String msg) { if (isDebug) Log.i(TAG, msg); } public static void d(String msg) { if (isDebug) Log.d(TAG, msg); } public static void e(String msg) { if (isDebug) Log.e(TAG, msg); } public static void v(String msg) { if (isDebug) Log.v(TAG, msg); } // 下面是传入自定义tag的函数 public static void i(String tag, String msg) { if (isDebug) Log.i(tag, msg); } public static void d(String tag, String msg) { if (isDebug) Log.i(tag, msg); } public static void e(String tag, String msg) { if (isDebug) Log.i(tag, msg); } public static void v(String tag, String msg) { if (isDebug) Log.i(tag, msg); } }

4.8.代码篡改


4.8.1.定义

“代码篡改”指当一个应用程序安装至移动设备后,代码和数据资源就存放到设备中了,攻击者可以通过直接修改代码、动态修改内存数据、更改或替换应用程序使用的系统API等方法,颠覆应用程序的运行过程和结果,以达到自身的不正当目的。

4.8.2.风险

Android编码规范中“代码篡改”会造成的风险包括:二进制修改、本地资源修改、钩子注入(函数钩用)、函数重要业务逻辑篡改等。

4.8.3.防范方法

4.8.3.1.签名校验
  • 【规范要求】

对应用程序的签名MD5值进行校验以保证应用程序的完整性。当校验结果显示程序完整性被破坏后,应用程序应主动停止自身运行。

  • 【详情说明】

打包签名后APK安装文件中任何文件一定被改动(如反编译),那么签名信息将失效。在整个APK编译过程中,是先进行APK文件的编译操作,然后进行签名操作。APK的签名方式包括keystore、私钥/公钥两种签名策略,而两种签名策略都基于证书文件进行签名,而每一个APP的生产者的签名证书都是自己独有的。 基于如上背景情况下如果在程序中进行对自身签名的校验即可保证程序安全。

  • 【代码示例】

Android中获取自签名代码:

/**
 * 字节数组转字符数组
 * @param mSignature
 * @return  */ private char[] toChars(byte[] mSignature) { byte[] sig = mSignature; final int N = sig.length; final int N2 = N * 2; char[] text = new char[N2]; for (int j = 0; j < N; j++) { byte v = sig[j]; int d = (v >> 4) & 0xf; text[j * 2] = (char) (d >= 10 ? ('a' + d - 10) : ('0' + d)); d = v & 0xf; text[j * 2 + 1] = (char) (d >= 10 ? ('a' + d - 10) : ('0' + d)); } return text; } /**  * 获取签名信息  * @param context  * @return  */ public String getSign(Context context) { PackageManager pm = context.getPackageManager(); List<PackageInfo> apps = pm .getInstalledPackages(PackageManager.GET_SIGNATURES); Iterator<PackageInfo> iter = apps.iterator(); while (iter.hasNext()) { PackageInfo packageinfo = iter.next(); String packageName = packageinfo.packageName; if (packageName != null && packageName.equals(context.getPackageName())) { return new String(toChars(packageinfo.signatures[0].toByteArray())); } } return null; }

Java中获取APK签名信息代码:

/**
 * 字节数组转字符数组
 *
 * @param mSignature
 * @return  */ private static char[] toChars(byte[] mSignature) { byte[] sig = mSignature; final int N = sig.length; final int N2 = N * 2; char[] text = new char[N2]; for (int j = 0; j < N; j++) { byte v = sig[j]; int d = (v >> 4) & 0xf; text[j * 2] = (char) (d >= 10 ? ('a' + d - 10) : ('0' + d)); d = v & 0xf; text[j * 2 + 1] = (char) (d >= 10 ? ('a' + d - 10) : ('0' + d)); } return text; } /**  * 解析java.security.cert.Certificate对象  * @param jarFile  * @param je  * @param readBuffer  * @return  */ private static java.security.cert.Certificate[] loadCertificates( JarFile jarFile, JarEntry je, byte[] readBuffer) { try { InputStream is = jarFile.getInputStream(je); while (is.read(readBuffer, 0, readBuffer.length) != -1) { } is.close(); return (java.security.cert.Certificate[]) (je != null ? je .getCertificates() : null); } catch (Exception e) { e.printStackTrace(); System.err.println("Exception reading " + je.getName() + " in " + jarFile.getName() + ": " + e); } return null; } /**  * 获取签名  * @param 文件路径  * @return  */ public static String getApkSignInfo(String apkFilePath) { byte[] readBuffer = new byte[8192]; java.security.cert.Certificate[] certs = null; try { JarFile jarFile = new JarFile(apkFilePath); Enumeration<?> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry je = (JarEntry) entries.nextElement(); if (je.isDirectory()) { continue; } if (je.getName().startsWith("META-INF/")) { continue; } java.security.cert.Certificate[] localCerts = loadCertificates( jarFile, je, readBuffer); if (certs == null) { certs = localCerts; } else { for (int i = 0; i < certs.length; i++) { boolean found = false; for (int j = 0; j < localCerts.length; j++) { if (certs[i] != null && certs[i].equals(localCerts[j])) { found = true; break; } } if (!found || certs.length != localCerts.length) { jarFile.close(); return null; } } } } jarFile.close(); return new String(toChars(certs[0].getEncoded())); } catch (Exception e) { e.printStackTrace(); } 

转载于:https://www.cnblogs.com/xiaozi/p/10044604.html

Kali Linux实战:如何用Android手机模拟信息窃取攻击(附防御指南) 本文深入解析了在Kali Linux平台上利用Metasploit框架对Android设备进行安全测试的实战流程,包括测试环境构建、攻击向量模拟及信息窃取演示。文章强调所有操作应在受控的合法测试环境中进行,并提供了从设备加固、应用甄别到安全编码的立体化防御指南,旨在提升安全意识和防御能力。 阅读详情

相关推荐

Android编码安全规范

本文档介绍了在Android编码中可能存在的一些安全陷阱,并为此给出了推荐的代码返利。

开发规范-Android编码规范

代码提交规范篇 【推荐】代码提交应该短小而频繁,尽量避免单次提交大量代码。 说明:约束单次提交的范围有利于写出更加针对性的说明,也对代码审核更加友好。 反例:单次提交超过200+行的代码或20+的文件;只在休息的时候(午休、下班)提交代码;很难一句话说清楚这次提交的内容 【强制】代码提交说明应该描述本次提交的具体内容,并带上适当的前缀 feat:新功能的说明 fix:修补bug的说明 doc...

u010897392的专栏 936

App常见漏洞及安全编码规范.pdf

高危风险:对业务数据(如:用户账号、密码、银行卡密码等等)有窃取风险或者后门;对业务核心代码存在泄露得分析或者后门;严重漏洞 中危风险:对应用代码的不符合安全开发规范,有被第三方利用的风险;对应用内部文件存在数据被读取风险 低危风险:对应用代码有安全隐患,风险低

Android安全编码规范

1.目的 为使系统开发人员能够编写符合安全要求的代码,以降低代码安全漏洞,减少代码被利用的可能性,从而提升各系统安全水平,符合国家安全合规性要求,保障产品安全稳定运营以及信息安全,特制定本规范。 2.引用规范 《信息安全技术移动智能终端个人信息保护技术要求》 《YD/T 1438-2006 数字移动台应用层软件功能要求和测试方法》 《YD/T 2307-2011 数字移动通信终端通用功能技术要求和测试方法》 《中国金融移动支付客户端技术规范》 《中国金融移动支付应用安全规范》 《移动互联网应

D.K专栏 1190

Cadence Virtuoso Layout 版图绘制

画好原理图,打好pin脚(pin最好以全大写的形式书写,以防后续操作中可能出现Bug) 查看所使用工艺库的design rule文件,确定栅格单位设置大小 在准备绘制的原理图界面启动layout XL/GXL 在layout界面按e,设置网格大小与design rule匹配 直接根据原理图生成版图 根据原理图连接关系显示版图中未连接的飞线 查看和更改原理图与版图中器件对应的链接关系 shift + f:显示器件版图细节 版图的构成:元器件(工艺厂商提供)、器件连接、阱连接、IO和PAD模拟电路

bobo_supper的博客 2万+

量化策略分享之ST股弱转强,回测年化123%

本策略的核心是精选ST股票,国九条过滤,防止直接暴雷退市,只做ST股票的弱转强,弱转强的认定标准是前日涨停但昨日不涨停,昨日收盘价大于前一日最低价,昨日收盘价大于10日线,昨日成交量大于前一日的成交量但小于前一日成交量的10倍,股价大于1;这类股票强势,有资金介入,能获得超额收益。

qq_29301281的博客 1268

C/C++安全编程规范

此外,非法的指针操作也可能导致程序逻辑上的错误,例如将数据写入了错误的内存位置,从而破坏了其他变量的值。当程序遇到一个空指针时,它会访问该指针所指向的数据,但由于是空指针没有可供访问的实际数据存在,因此这将导致程序崩溃。安全编程是一种软件开发方法,目的是通过采取具体措施来减少程序中存在的安全漏洞和黑客攻击的可能性,确保软件在运行过程中不会遭受攻击或泄露敏感信息。对任何用户输入的数据,都必须进行输入验证,对于用户输入的所有数据,都应该进行校验和过滤,来确保输入的数据不包含恶意代码或不合法的字符。

weixin_56018002的博客 2228

Multisim新手必看:从零搭建数字时钟仿真电路(附完整原理图)

本文详细介绍了如何使用Multisim从零开始搭建数字时钟仿真电路,涵盖晶振电路设计、计数电路实现、校时功能配置等关键步骤。通过完整的原理图和实用技巧,帮助新手快速掌握Multisim仿真设计,实现精准的数字时钟功能。

ios99的博客 328

开发代码规范

平日java开发规范手册

qq_56734899的博客 2579

CAN总线错误帧全解析:从数据包到硬件层的故障树分析

本文深入解析CAN总线错误帧的故障树分析方法,从数据包到硬件层全面剖析错误机制。通过物理层信号测试、数据链路层错误解码和应用层协议排查,提供系统化的诊断框架。结合CANoe配置和示波器波形分析,帮助工程师快速定位总线故障,提升系统可靠性。

weixin_26742753的博客 491

用Excel或WPS做两独立样本的T检验

一般情况下收集数据时常用的是Excel或者WPS,但统计时却用SPSS等软件进行统计学分析,经常很多人找不到SPSS的安装包,或者苦于正版激活或忘记教程,其实Excel或WPS自带函数就足够了,均数、标准差以及统计检验都是一个函数而已。解释:先做F检验,如果F>0.05就做T检验,Ttset里的数据为两组的数据的比较,结果如下。A组的均数计算 =AVERAGE(B2:B6)A组的标准差计算 =STDEV(B2:B6)B组的标准差计算=STDEV(B7:B19)分组 数值 A组均数 A组标准差 p值。

Mrrunsen的博客 6752

Android 编码规范

一、命名规范 1.1包命名 命名规则:一个唯一包名的前缀总是全部小写ASCII字母并且是一个顶级域名,通常是com,edu,gov,mil,net,org等。 规约:以公司为准,一般是com.公司名.项目名称缩写.模块名或层级名称 1.2类和接口命名 命名规则:类名是一个名词,采用大小写混合的方式,每个单词的首字母大写。避免使用缩写词,除非该缩写词被更广泛使用,如URL,HTML等。

Keep Calm and Carry On. 1706

YOLOv8的特征蒸馏代码应用讲解(CWD/MGD/mimic/在线蒸馏/逻辑蒸馏)

基于YOLOv8的逻辑蒸馏、特征蒸馏、在线蒸馏等方法代码介绍。

qq_41920323的博客 2583

安卓开发入门:从环境搭建到安全实践

移动开发领域中,Android凭借其开源特性和庞大的市场份额成为开发者首选技术栈。基于Java/Kotlin的生态体系不仅降低了学习门槛,其组件化架构更能延伸到智能硬件等新兴领域。开发环境搭建涉及JDK版本管理、Gradle配置优化等工程实践,其中阿里云镜像源可显著提升依赖下载速度。在应用安全方面,客户端密码存储需采用SHA-256等哈希算法处理,但完整身份验证仍需后端配合。通过ADB工具链和ViewBinding等现代技术,开发者能有效提升调试效率并规避空指针异常。

weixin_29597551的博客 13

YoloV8优化:感受野注意力卷积运算(RFAConv),效果秒杀CBAM和CA等 | 即插即用系列

感受野注意力卷积运算(RFAConv),解决卷积块注意力模块(CBAM)和协调注意力模块(CA)只关注空间特征,不能完全解决卷积核参数共享的问题

①答疑群聊服务;②YOLO大模型知识问答系统;③计算机视觉论文生成智能体; 4265

2011-2024年间各省数字普惠金融指数数据(覆盖广度、使用深度和数字化程度)

2、指标:数字金融普惠指数、数字金融覆盖广度指数、数字金融使用深度指数、普惠金融数字化程度指数、数字金融使用深度指数下属的支付、保险、货币基金、信用服务、投资、信贷等分类指数。中国各省的数字普惠金融指数数据,从数字金融覆盖广度、数字金融使用深度和普惠金融数字化程度3个维度来构建数字普惠金融指标体系。数字普惠金融指数一共3个维度、33项具体指标。全套指数包含数字金融覆盖广度指数、数字金融使用深度指数和普惠金融数字化程度指数,以及数字金融使用深度指数下属的支付、保险、货币基金、信用服务、投资、信贷等分类指数。

【优快云】 1万+

Android弹窗安全:XPopup防注入与权限控制全解析

你是否曾遇到过弹窗输入框被恶意字符攻击?是否因权限管理不当导致应用遭受悬浮窗劫持?在Android开发中,弹窗作为用户交互的重要入口,其安全性往往被忽视。本文将深入剖析XPopup库在权限控制与输入安全方面的设计理念,提供从基础防护到高级加固的全流程解决方案,帮助开发者构建固若金汤的弹窗交互体系。 ## 一、权限控制:XPopup的安全基石 ### 1.1 权限管理架构解析 XPopup通过...

gitblog_00322的博客 1189

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Android安全开发规范

1、Activity 安全    描述:可被外部调用的activity,起因是因为 menifest.xml中Activity的属性explorted=true ,导致可以被劫持或者单个activity调用出现异常。    检测方法:在ADB shell 环境下输入 am start -n com.qihoo.something/com.qihoo360.SomeActivity    修复方案:...

迷路啦的博客 1469

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android安全防护终极指南:企业级应用安全10大最佳实践 [特殊字符]️

在当今移动优先的时代,Android应用安全已成为企业开发者和安全工程师必须掌握的核心技能。随着移动应用在企业业务中扮演越来越重要的角色,**Android安全防护**已成为保护用户数据和商业机密的关键防线。本指南将为您揭示企业级Android应用安全的完整防护策略,帮助您构建坚不可摧的移动应用防御体系。 ## 为什么Android安全如此重要?🔐 Android作为全球市场份额最大的移动操

gitblog_00067的博客 523

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Android-Cheat-sheet安全实践:防止内存泄漏与数据保护的终极指南

在Android开发中,内存泄漏和数据安全是影响应用稳定性与用户信任的两大核心问题。Android-Cheat-sheet作为面试常备的算法与安全实践指南,提供了丰富的代码示例和解决方案,帮助开发者构建更健壮的应用。本文将结合项目中的经典案例,详解内存泄漏的识别与修复方法,以及数据保护的关键策略。 ## 一、内存泄漏的常见类型与检测技巧 🕵️‍♂️ 内存泄漏是Android应用性能优化的常见

gitblog_00176的博客 410

代码规范之Alibaba Java Coding Guidelines

基于项目实战 整理出来的代码规范插件的使用 团队开发必备神器

weixin_47143458的博客 1万+

Bitwarden Android 七阶段开发工作流:从实现到 PR 的完整 AI 协作指南

本篇技术指南围绕 Bitwarden Android 仓库中的 [.claude/commands/work-on-android.md](https://link.gitcode.com/i/e46ca1b598830d54725ccb32262bd1b5) 命令展开,系统讲解其定义的「实现 → 测试 → 构建验证 → 自查 → 提交 → 评审 → 拉取请求」七阶段开发工作流。文章将逐一拆解每个

gitblog_00454的博客 358

从‘O泡果奶’App看Android安全:你的手机如何被恶作剧软件‘锁死’?

本文通过分析'O泡果奶'App的技术手段,揭示了Android系统权限滥用的安全风险。文章详细解析了界面劫持、输入拦截和后台保活等恶意技术,并探讨了Android权限系统的设计缺陷,最后提供了用户防范和开发者安全实践的建议。

weixin_30457465的博客 484

Android Logcat Security

0x00 科普 development version :开发版,正在开发内测的版本,会有许多调试日志。 release version : 发行版,签名后开发给用户的正式版本,日志量较少。 android.util.Log:提供了五种输出日志的方法 Log.e(), Log.w(), Log.i(), Log.d(), Log.v() ERROR, WARN, INFO, DEBU

omnispace的博客 1095
上一篇: 【安全开发】python安全编码规范
下一篇: 【安全开发】IOS安全编码规范
an0708
博客等级 码龄12年 30粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值