您的位置:首页 > 移动开发 > Android开发

android 数据存储安全

2017-02-13 09:30 357 查看
一、 android 数据存储安全
     Android系统提供了以下四种Android应用本地存储方式:Shared Preferences、SQLite Databases、Internal Storage、External 
1、Shared Preferences
      shared preferences 存储的安全风险(Storage等存储方式。Shared Preferences是一种轻量级的基于XML文件存储的键值对(key-value)数据的数据存储方式,一般用于储存应用的配置等信息 )
危险存在的原因有如下:
      a. 使用MODE_WORLD_READABLE模式创建Shared Preferences文件,使得其他应用对该Shared Preferences文件具备可读的权  限;
       b. 使用MODE_WORLD_WRITEABLE模式创建Shared Preferences文件并含有“android:sharedUserId”属性值,使得其他应用对该应用的Shared Preferences文件具备可写的权限。
       c. 在具备root权限的程序或用户对任何应用程序通过任意模式创建的的Shared Preferences文件都具有可读可写的权限。
2、SQLite Databases
    操作数据库可使用SQLiteOpenHelper或ContentProvider的方式。使用SQLiteOpenHelper操作数据库时,数据库存放 在data/data/<packagename>/databases/目录,这个目录只能是应用自己访问,相对是安全的,但是root用户,这个目录也是透明的,因此,私密数据也要做到加密存储。使用ContentProvider操作数据时,本质上也是使用SQLiteOpenHelper,这时需要在AndroidManifest.xml来注册这个Provider,注册Provider就对外提供了访问这个数据库的接口,其他应用就可以访问这个数据库了,为了数据库数据安全就需要控制访问,如果不想对外提供访问只需在AndroidManifest.xml注册Provider时设置android:exported="false";如果想提供对外访问能力,最好设置android:readPermission和android:writePermission这两个属性,来分别指定对这个ContentProvider中数据读和写操作的权限。android数据库还要预防数据注入的攻击。
3、Internal Storage
     RAM数据存储在/data/data/<package name>/files目录中,只允许当前应用访问,安全性较好,但是root后的机器也是可以被读取篡改的,这里的数据也不是绝对的安全,RAM的敏感数据也要加密存储。
4、External
    SD卡是一个公共的存储空间,只要申请了如下权限,就可以操作SD卡。也就是说SD卡数据是最不安全的,很容易被其他应用读取篡改,如果SD中存放数据,建议存放一些无关紧要的数据,重要数据加密存储或者存放到RAM中。
二、解决方式
     数据安全最重要的是解决数据加密的问题,密钥存储问题,选择合适的加密方法。加密方法,密钥存储建议使用。java中有许多
例如AES加密,MD5,BASE64,RSA等等http://snowolf.iteye.com/blog/379860这篇文章列举了很多,但是基本都是j2se平台的,android平台不一定支持,但是AES算法Android是自带了https://developer.android.com/reference/javax/crypto/Cipher.html(官方文档)
     AES加密算法的使用,
1 创建密钥

private static SecretKeySpec createKey(String password) {
    byte[] data = null;
    if (password == null) {
        password = "";
    }
    StringBuffer sb = new StringBuffer(32);
    sb.append(password);
    while (sb.length() < 32) {
        sb.append("0");
    }
    if (sb.length() > 32) {
        sb.setLength(32);
    }

    try {
        data = sb.toString().getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return new SecretKeySpec(data, "AES");
}

2 加密字节数组
这里只给出加密字节数组,至于加密其他数据,可以将其他数组转换成字节数组,然后加密。

public static byte[] encrypt(byte[] content, SecretKeySpec key) {
    try {
        Cipher cipher = Cipher.getInstance(CipherMode);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] result = cipher.doFinal(content);
        return result;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

加密后的结果也可以使用下面方法将其转换成16位字符串,方便存储。

private static String byte2hex(byte[] b) { // 一个字节的数,
    StringBuffer sb = new Strin
c2c7
gBuffer(b.length * 2);
    String tmp = "";
    for (int n = 0; n < b.length; n++) {
        // 整数转成十六进制表示
        tmp = (java.lang.Integer.toHexString(b
 & 0XFF));
        if (tmp.length() == 1) {
            sb.append("0");
        }
        sb.append(tmp);
    }
    return sb.toString().toUpperCase(); // 转成大写
}

同样可以使用一下方法可以将字符串转成字节数组

private static byte[] hex2byte(String inputString) {
    if (inputString == null || inputString.length() < 2) {
        return new byte[0];
    }
    inputString = inputString.toLowerCase();
    int l = inputString.length() / 2;
    byte[] result = new byte[l];
    for (int i = 0; i < l; ++i) {
        String tmp = inputString.substring(2 * i, 2 * i + 2);
        result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
    }
    return result;
}

3解密

public static byte[] decrypt(byte[] content, Context password) {
    try {
        SecretKeySpec key = createKey(getCertificateSHA1Fingerprint(password));
        Cipher cipher = Cipher.getInstance(CipherMode);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] result = cipher.doFinal(content);
        return result;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

以上就是AES加密的全部过程,做为对称加密方法中一种(后面会说非对称加密方法)AES 加密缺点就是由于加密跟解密密钥是同一个,如果密钥丢失,一样会导致信息泄漏,那么密钥的保存就很重要了,那么android 中AES加密的密钥保存到哪呢,下面提供两种方法
1 将密钥保存到native(具体方法http://blog.csdn.net/dingding_android/article/details/51775876),由于java 代码很容易被反编译,即使混淆也过后也很容易被破解,但是C语言由于反编译后是汇编语言,这就相对安全多了
2 使用apk的sha1 值当做密钥(sha1 获取方法http://www.jianshu.com/p/562ce6fbc835),sha1 是apk 打包完成后apk 的标识,是区别每个app的特定的一个标识,防止被篡改,也就是只有当前app可以访问的到,这样就相对安全多了,在代码中获取sha1 值代码如下
     

private static String getCertificateSHA1Fingerprint(Context context) {
    //获取包管理器
    PackageManager pm = context.getPackageManager();
    //获取当前要获取SHA1值的包名,也可以用其他的包名,但需要注意,
    //在用其他包名的前提是,此方法传递的参数Context应该是对应包的上下文。
    String packageName = context.getPackageName();
    //返回包括在包中的签名信息
    int flags = PackageManager.GET_SIGNATURES;
    PackageInfo packageInfo = null;
    try {
        //获得包的所有内容信息类
        packageInfo = pm.getPackageInfo(packageName, flags);
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }
    //签名信息
    Signature[] signatures = packageInfo.signatures;
    byte[] cert = signatures[0].toByteArray();
    //将签名转换为字节数组流
    InputStream input = new ByteArrayInputStream(cert);
    //证书工厂类,这个类实现了出厂合格证算法的功能
    CertificateFactory cf = null;
    try {
        cf = CertificateFactory.getInstance("X509");
    } catch (CertificateException e) {
        e.printStackTrace();
    }
    //X509证书,X.509是一种非常通用的证书格式
    X509Certificate c = null;
    try {
        c = (X509Certificate) cf.generateCertificate(input);
    } catch (CertificateException e) {
        e.printStackTrace();
    }
    String hexString = null;
    try {
        //加密算法的类,这里的参数可以使MD4,MD5等加密算法
        MessageDigest md = MessageDigest.getInstance("SHA1");
        //获得公钥
        byte[] publicKey = md.digest(c.getEncoded());
        //字节到十六进制的格式转换
        hexString = byte2HexFormatted(publicKey);
    } catch (NoSuchAlgorithmException e1) {
        e1.printStackTrace();
    } catch (CertificateEncodingException e) {
        e.printStackTrace();
    }
    return hexString;
}

3、 android 数据传输安全
https://developer.android.com/training/articles/security-ssl.html官方文章有详细解释。
          这里说一种就是https 和SSL 实现客户端跟服务端之间的加密通讯。
          基本概念:

          
HTTPS是HTTP over SSL/TLS,HTTP是应用层协议,TCP是传输层协议,在应用层和传输层之间,增加了一个安全套接层SSL/TLS:
SSL/TLS层负责客户端和服务器之间的加解密算法协商、密钥交换、通信连接的建立,安全连接的建立过程如下所示:

     
简单解释就是

HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。握手过程的简单描述如下:

浏览器将自己支持的一套加密算法、HASH算法发送给网站。
网站从中选出一组加密算法与HASH算法,并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
浏览器获得网站证书之后,开始验证证书的合法性,如果证书信任,则生成一串随机数字作为通讯过程中对称加密的秘钥。然后取出证书中的公钥,将这串数字以及HASH的结果进行加密,然后发给网站。
网站接收浏览器发来的数据之后,通过私钥进行解密,然后HASH校验,如果一致,则使用浏览器发来的数字串使加密一段握手消息发给浏览器。
浏览器解密,并HASH校验,没有问题,则握手结束。接下来的传输过程将由之前浏览器生成的随机密码并利用对称加密算法进行加密。

握手过程中如果有任何错误,都会使加密连接断开,从而阻止了隐私信息的传输。
     根据上面的流程,我们可以看到服务器端会有一个证书,在交互过程中客户端需要去验证证书的合法性,对于权威机构颁发的证书当然我们会直接认为合法。对于自己造的证书,那么我们就需要去校验合法性了。当然,对于自签名的网站的访问,网上的部分的做法是直接设置信任所有的证书,对于这种做法肯定是有风险的。
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: