原文链接 : Develop a secured Android application
安卓应用已经广泛用于处理非常敏感的信息。保证用户的信息不被居心叵测的人轻易截获是每个Android开发者的责任。“开放网络应用安全项目“ (The Open Web Application Security Project )(OWASP) (引用9, 引用10) 试图列举移动应用的安全风险。有些是系统架构的责任(比如由于服务器缺陷产生的问题),有些与后端开发者有关(比如认证检查等),还有些则与移动开发者有关。这篇文章,我们将会关注与Android开发者相关的那些问题。
因此,我们将会再次讨论三个潜在的风险源头:
- 与WebService通信的风险
- 存储在设备上的信息被泄漏的风险
- 我们的应用呗第三方修改的风险
在使用WS请求的敏感应用中,最重要的事情是确保与后端通信的数据的安全性。事实上,就算应用本身是安全的,但其通过Internet发送的请求能被轻易截获,那也是没有用的。
当一个应用被中间人攻击时,将会产生两个主要的风险。
信息泄露
如果一个攻击者可以控制用户使用应用的本地网络,他就可以偷偷的轻易截获这个应用和WebService之间通信的所有内容。
Webservice (WS) 模仿
对于了解WS格式的攻击者,则可以阻止应用程序的正常请求并为应用程序提供假的返回值。在这种情况下,用户以为请求已经正常执行了,然而请求却从未到达后端。
测试你的应用是否能被中间人轻易攻击非常容易。你只需要用一个代理服务器软件, (如:CharlesProxy (引用12)),然后将测试设备的代理服务器设置为安装了这个软件的电脑上。如果你的应用没有做针对MITM的保护,你将会很容易看到你的App发起的每一个请求(的内容)。现在,假设有一个你的App的用户通过一个不安全的网络去连接WebServices,攻击者可以轻易在路由上安装一个这样的代理软件,它将会清楚的嗅探到所有的请求。
确保通信安全,最起码要使用HTTPS协议,例如使用TLS的加密通信或者其前身SSL加密。同时,如果条件允许,这并不是我们的系统需要遵守的唯一约束。想弄明白原因,我们需要先来看看SSL协议的工作原理。
一组SSL证书至少包括下面三个证书
- 根证书(Root certificate). 是由证书授权机构(Certification Authority ,CA)签发的证书。证书授权机构是一个能够确保整个传输过程安全的一个可信机构。
- 中间证书(Intermediate certificate(s)). 中间证书可以有多个。它是最终用户证书和跟证书的链路。该证书专门用于服务器发布WS服务,该证书由根证书签发。
- 最终用户证书(End-user certificate). 最终用户证书可以用于与WebService服务器通信。
Android 原生的SSL保护: Android网络层有嵌入了一些CA证书的列表(有一百多个,你可以在设备的设置菜单查看)。每一个HTTPS请求的证书链的根证书,都必须是其中之一。
然而,与服务器通信过程的请求链中的其他证书的安全性,仍然无法确认。恶意用户还是可以通过向CA买一个中间证书来实现中间人攻击。系统会认为网络传输的过程是有效的。这种方式的恶意攻击非常常见,有研究显示(引用1),使用HTTPS请求的应用程序,有73%没有使用适当的方式来检查证书。
解决上述问题的方法,在于手动检查中间证书(该证书对服务器来说应该是特定的)是一个已知的证书。这意味着,我们不得不在应用程序中存储那个特定的服务器证书。它可以作为资源文件,或者直接在代码中作为常量,
也许你会奇怪,为什么我们必须检查中间证书而不是检查最终用户证书。这有两个原因:第一个,稍后我们会看到,最终用户证书的生命周期非常短暂。第二个原因也是处于安全考虑:假设黑客控制了你的系统,他们将会获取你的私钥(private key)。应用会认为这些请求是由正确的终端用户签名的,就会允许链接。如果确认过程由中间服务器完成,中间服务器就可以远程的通过中间CA回收证书。
在JAVA中,可以使用SSLSocketFactory
类,来确认SSL链接是否安全。创建来执行中间证书检查,需要经过以下几步:
-
X509TrustManger
,这个位于 java.net.ssl 包中的抽象类用于检查SSL链接在服务端的有效性。public class MyX509TrustManager implements X509TrustManager {
private X509Certificate certificate;
public MyX509TrustManager (InputStream knownIntermediateCertificate) throws CertificateException {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
certificate = certFactory.generateCertificate(knownIntermediateCertificate);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// Do nothing. We only want to check server side certificate.
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// Verify that the certificate domain name matches the expected one
if (!chain[0].getIssuerDN().equals(certificate.getSubjectDN())) {
throw new CertificateException("Parent certificate of server was different than expected signing certificate");
}
try {
// Verifiy that the certificate key matches the expected one
chain[0].verify(certificate.getPublicKey());
// Verify that the certificate has not expired
chain[0].checkValidity();
} catch (Exception e) {
throw new CertificateException("Parent certificate of server was different than expected signing certificate");
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// Do nothing
return new X509Certificate[0];
}
}
SSLSocketFactory
,这段代码需要在网络请求前运行。TrustManager[] trustManagerArray = new TrustManager[1];
MyTrustManager trustManager = new MyTrustManager(TRUSTED_CERTIFICATE);
trustManagerArray[0] = trustManager;
final SSLContext sslc;
// TLS is the last SSL protocol and is used by all the CA
sslc = SSLContext.getInstance("TLS");
// We only need to give a TrustManager list as we don't need to perform client authentification
sslc.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslc.getSocketFactory());
中间证书可能过期(他们的生命周期是大约十年)。解决方案是在旧证书过期前,将新证书加入白名单。
中间证书可能存在风险。如果中间CA被黑,整个安全机制将会毫无用处。事实上,如果中间CA的私钥被黑客获取,它就可以伪造一个证书链,该证书链将会与你的证书链由相同的中间证书。这样,攻击者就可以实现中间人攻击。甚至CA是理论安全的,也不排除会发生诸如2011年DigiNotar被黑的事件(引用13)。那样的话,就必须更换服务器的SSL证书链,并上线包含新的中间证书的版本。
SSLSocketFactory
的信任策略会应用到应用程序的所有请求。如果有SDK嵌入,也需要为SDK的远程服务器嵌入中间证书。让其他的服务器使用你的证书,可能没那么容易,这就会产生问题。
这个问题,可以通过动态证书注入来解决。应用程序只允许一个证书(主服务器的那个),并且在应用启动时动态获得一个授权中间证书的列表。然后,将这些证书加入SSLContext
的TrustManager
中。
总之,在大多数情况下,中间检查机制能够确保对中间人(MITM)攻击的保护。当黑客截获了通信的信息,如果他使用了TrustManager无法识别的证书,将会拒绝HTTPS连接。
安卓平台提供了一种方便的存储偏好设置深知大文件的方式——SharedPreferences
接口。虽然这些设置已经被隐藏到一个隐蔽的路径了,但如果设备root了,这些数据还是有可能被获取到。
因此,如果应用要保存敏感信息,在SharedPreference
中就必须加密存储。一般有两种方式:
使用一个密码库,来加密和解密SharedPreferences
中存储的健和值。有很多JAVA的密码库可以使用,如: javax.crypto, Bouncycastle(引用2) 和 Concealed(引用3)
使用SharedPreferences
的包装类库(wrapper)。这些库对开发者非常方便,不用考虑算法选择之类的事情。但是,使用这些库可能会导致缺乏灵活性并且有些库也没有使用安全的算法,这将会导致敏感信息并没有被安全存储。其中一个这方面最常用的类库是SecurePrefences
(引用4)。在这个解决方案中,你可以采用下面的方式使用SecurePreferences
,它继承于SharedPreferences。
SecurePreferences securePreferences = new SecurePreferences(context, "MyPassword", null);
这两种对称加密算法,像AES(需要一个合适的key size)会引发另一个需要思考的问题:应该用什么密钥。确实如果我们使用一个静态密钥,这些设置可以通过反编译程序来破解。所以,最好的方法是在应用启动时让用户来输入。另一个选择是让用户使用指纹API (引用15) (API 23以后可以使用) ,它将会提供一个安全流畅的方式来鉴权。
不幸的是,这些方法并不能适合每一个应用的用户体验。比如,如果我们打算在用户输入密码前显示一些被存储的加密信息,我们就不能使用这种加密系统。
幸运的是,安卓提供了一个安全生成密钥的方式,它保证了每个应用/设备对生成的密钥的唯一性,那就是Keystore。Android Keystore的目的是为了允许应用程序将私钥放到一个其他应用程序不能获得的地方。这种机制很简单,第一次启动,你的应用检查该私钥是否存在,如果没有,就生成一个并存储在keystore中。如果私钥已经存在,你可以使用它来做为之前提到的加密算法的安全码来加密SharedPreferences存取的数据。Obaro Ogbo 写了一篇文章 (引用11) ,详细描述了如何使用KeyStore来生成私钥/公钥(Private/Public Key )对。KeyStore的主要缺陷在于,其api只支持Api 18以上版本。不过,还是有一个针对API 14 (引用14)兼容的移植版(这不是官方的移植,所以请谨慎使用)。
因此,我们可以根据下面的决策图来决定是否对设置项进行加密:
安卓开发者想确保它的应用程序没有被分析、读取甚至被修改,一般出于以下原因:
- 我们希望黑客没有办法解开那些需要用户付费才能使用的功能。
- 有时候我们开发了具有敏感信息的程序,黑客可以将所有用户输入的信息发送给他。即使(这些被修改的应用)不能轻易放到Play市场,用户也能从许多其他的地方下载到这个被修改的应用,这将以很隐秘的方式偷窥用户信息。
在开发具有敏感数据应用时,安卓开发者需要关注的是Android应用是非常容易被一些有经验的人反编译的。大多数安卓应用程序(采用java字节码),即通过“原生“安卓建立的应用确实如此。反编译及阅读这些字节码非常容易,以至于修改、重新构建一个修改过的应用(引用5)。
在这个部分,我们着重研究一些技巧和方法,以及架构规则,来避免可能产生的风险。同时,我们需要明白的是,并不是每一个客户端设备都会100%面对这些风险。
将有价值的算法放到服务端 这是一条架构规则。你的应用的价值都是基于核心算法体现,你肯定不想让其他人可以轻易读取、拷贝、并将其放倒自己的应用程序中。在这种情况下,最好的方案是在服务端实现这些算法。应用仅通过给WS提供数据,在服务端处理后,得到算法的返回值。这样做的显著缺陷是以这样的架构为核心功能的程序,不能离线使用。
不要暴露你的WS(WebService) 如果你的应用的价值依赖于从WS获取的数据,你就不得不为WS设置安全访问,如,通过为每个请求附带使用密码短语或用户名密码获取的会话令牌的方式。如果你只是在app的preference设置中放了一个认证标志,那这个标志就很容易通过修改应用代码的方式,被设置成“永久连接“。这样做的风险,是用户不得不经常输入用户名和密码来延长会话时间。
使用Proguard来混淆代码 Proguard是一个常用的JAVA工具。Proguard之行三个过程:
- 瘦身:未用到的代码被移除
- 优化:内联一些方法,未使用的方法参数被移除等
- 混淆:最后这步,Proguard将会重命名所有java源文件中的类、属性、方法名,来确保即使字节码被反编译了,这些代码也几乎不可读。当然Proguard也会确保JVM能够识别这些不同的编译元素。
这个工具非常有趣,因为它让读取反编译后的字节码非常困难。然而,尽管一些代码元素被重命名了,但反编译后,被混淆的方法和属性的作用还是有可能被猜到。另外,Proguard也生成了一个映射文件,用来将混淆后的代码转换为可读的代码(引用6)。
网络上有很多教程,来介绍关于配置Proguard的相关细节。如Android官方文档(引用7)。
使用编译后的库 借助于Java本地接口技术(JNI),使用C或C++编写的编译后的本地代码可以作为JAVA代码的接口实现。而借助Android NDK,你可以更方便的使用此功能。总的来说,这机制很简单:先编译好C/C++代码(必须包括标准的JNI入口),得到一个.so文件。然后将这个库文件包含到你的应用程序工程中,以及它的java接口。这里我们谈到编译好的类库,最主要的目的就是,对于反编译后的代码的可读性,so的机器码将比Java的字节码更难读。一个好的实践是(如果实现起来方便的话)是,将应用中具有高安全级别的部分(原文为:更敏感的部分)用C或C++来开发(例如需要保密的算法或者安全层)并以接口形式暴露,而应用中的其他部分再使用JAVA开发。
诚然,使用NDK也还是有缺点的:我们必须为不同的目标硬件架构分别编译本地库。如果漏掉了其中某种,程序就会崩溃。另外这也会使代码架构变的更复杂些。
在这篇文章中,我们为OWASP提出的《10大移动安全问题中》(引用9)中的3个提出了解决方案。像在导语中提到的那样,只有应用程序链接到的后端系统架构安全,应用的安全才能保证。我们可以从技术上开发一个安全的应用,但如果服务端的糟糕设计导致认证系统的安全性孱弱,所有的努力也将费日。同时,应用开发者有责任确保应用的安全边界没有瑕疵,这篇文章为其提供了合适的解决方案。
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。