Android 密钥保护和 C/S 网络传输安全理论指南

注:本文将着重讲解 Android KeyStore、so 库保护 app key / secret、HTTPS 原理及其防中间人***措施。

谈到 Android 安全性话题,Android Developers 官方网站给出了许多很好的建议和讲解,涵盖了存储数据、权限、网络、处理凭据、输入验证、处理用户数据、加密等方方面面,甚至对于动态加载代码也提供了建议,具体可以看看 training 的?security tips?章节。而今天,我想特别来讲一讲在 Android 密钥保护和 C/S 网络传输安全 这两方面的具体安全措施。

密钥的保护以及网络传输安全 应该是移动应用安全最关键的内容。

所谓的密钥,简单来说,可以认为是我们常用的 app key / secret / token 或数据加密的 key,这些 keys 就像我们宝库的钥匙,一旦泄露,就像大门被人撬开,什么安全都无从谈起。因此,密钥们的安全存储、防窃取便显得异常重要。我曾经看过许多国内外著名的应用在使用自家 API 或?SaaS?服务的时候,在 Java 代码或 SharePreferences 里明文记录着 app key / secret / token,这样的做法,就算使用了 proguard 对代码进行混淆,也是非常容易被逆向获得服务端接入密钥,非常危险。

在这一方面,Android 提供大量用来保护数据的加密算法,例如 Cipher 类中提供了 AES 和 RSA 算法,再例如安全随机数生成器 SecureRandom 给 KeyGenerator 提供了更加可靠的初始化参数,避免离线***等等。

而如果需要存储密钥以供重复使用,Android 提供了 KeyStore 等可以长期存储和检索加密密钥的机制,Android KeyStore 系统特别适合于存储加密密钥。”AndroidKeyStore” 是 KeyStore 的一个子集,存进 AndroidKeyStore 的 key 将受到签名保护,并且这些 key 是存在系统里的,而不是在 App 的 data 目录下,依托于硬件的 KeyChain 存储,可以做到 private key 一旦存入就无法取出,总之,每个 App 自己创建的 key,别的应用是访问不到的。

很多时候,我们会需要将用户的账号密码或 token 存储下来,以做到下次打开免登的目的。

KeyStore 提供了两个能力:

  • 生成随机加密密钥
  • 安全存储和读取数据

有了这两个能力,我们的密钥保护就变得很容易了,你只需要:

  1. 在应用安装后第一次运行时,生成一个随机密钥,并存入 KeyStore

2.. 当你想存储一个数据,便从 KeyStore 中取出之前生成的随机密钥,对你的数据进行加密,加密完成后,已完成加密的数据可以随意存储在任意地方,比如 SharePreferences,此时即使它被他人读取到,也无法解密出你的原数据,因为他人取不到你的密钥

3.. 当你需要拿到你的原数据,只需要从 SharePreferences 中读取你加密后的数据,并从 KeyStore 取出加密密钥,使用加密密钥对 “加密后的数据” 进行解密即可

其中加密算法可以使用 Cipher AES 来保证安全性,不要使用自己创造的加密算法。

这就是使用 KeyStore 的一整套流程,另外 KeyStore 还可以用来做数据签名和签名验证,就像一个黑匣子一样,具体可以自行搜索了解。

KeyStore 适用于生成和存储密钥,这些密钥可以用来加密运行时获取到的数据,比如运行时,用户输入的密码,或者服务端传下来的 token。但对于需要预设在 App 内的 API key / secret,因为 KeyStore 是运行时随机生成加密密钥,所以我们无法预估API key / secret 会被加密成什么样,自然也就无法预先把加密后的 API key / secret 预埋在 App 内,因此对于这类需要预设的固定密钥,我将介绍另外一种十分安全、难破解的保护方式。

首先我们需要思考,这个 key 应该放到哪里才能够最大限度提升其被逆向获取的难度,放 Java 代码里?根本不安全。放文件或图片像素里?顶多续 1 小时。放 so 库里?可以,so 库能够很大程度提升逆向破解难度,但如果别人把 so 库文件拿出来,再直接调用这些 native 接口,便也可以获取到你的 key,怎么办?

我的做法是在 so 库的 C 代码里?JNI_OnLoad()?方法对 APK 签名进行验证,如果签名不对,直接 crash,这样移植出去便和砖头没什么两样。而你的应用又不得不依赖这个 so 库进行获取 API key / secret,因此它又不能直接剥离,这就保证了不能没有它,又不能移植它,换句话说就是:如果别人反编译了你的代码,发现你使用 so 进行签名验证,便直接把这个 so 文件摘掉,这样做的结果是,App 获取不到你存在 so 中的 secret 了,便无法正常工作了;而如果别人对你的应用进行修改和重新签名,或移植你的 so 库来读取内部的 secret,则会因为签名验证不通过直接自爆。

以上便是对于保护 key / secret 的一些有效举措,再总结下就是,使用 so 库存储预设 key / secret,使用 Android KeyStore 存储运行时动态获取到的私密内容。

而另一方面,对网络传输进行加密、防中间人***也是至关重要的,如果你的密钥保护得很好,但数据却在网络传输过程中被拦截篡改,那也是前功尽弃。

如果使用 HTTP,对于 API 请求参数会变的请求,一般都会进行参数防篡改校验,和参数加密,客户端和服务端会约定一个固定的密钥作为加密的 key,这个 key 便属于上面我们讲过的需要预设在 App 代码里的,因此比较安全的做法就是将它埋藏在 so 库里。

但更推荐、更简单的做法是,使用 HTTPS,HTTPS 是 HTTP 的安全版本,为什么这么说呢?因为HTTPS 自带加密、验签、检查数据完整性等功能,它在 HTTP 下加入了 SSL (Secure Socket Layer),SSL 位于 TCP/IP 和 HTTP 协议之间,负责加密、验签、检查数据完整性工作。

HTTPS 的握手过程中能够确立客户端与服务端双方加密传输数据的密码信息,流程大致如下:

  1. 客户端将自己支持的加密算法类型和检验数据完整性的 HASH 算法类型告诉服务端
  2. 服务端从客户端传上来的加密算法中选出一种支持的类型,用于生成一对非对称密钥对,并将自己的证书发给客户端,证书中将带有这对非对称密钥的公钥和证书颁发机构、过期时间等。其中所谓的非对称加密及其公钥和密钥,如果不懂,可以简单理解为:这是一种加密算法,私钥加密的内容只有公钥才能解密,反之公钥加密的内容只有私钥才能解密,以此来保证两端信息的安全性。
  3. 客户端获得证书后,会对证书的合法性进行检验,如果证书合法,则客户端将随机生成一对称加密的密钥,并使用服务端给的非对称加密密钥对这个对称加密密钥进行加密,并生成 HASH 值,统一发给服务端。所谓对称加密及其密钥,简单说:这是一种加密算法,加密和解密使用的密钥是一样的。
  4. 服务端拿到信息后,使用私钥进行解密取出对称加密的密钥,并验证 HASH 值。验证无误后,使用这个对称加密密钥对握手信息进行加密,发给客户端。
  5. 客户端解密和 HASH 验证,无误则握手成功完成。接下来所有的通讯都会使用这个已经同步到两端的对称加密密钥进行加密通讯。而一旦这个握手过程中有任何错误,都会中止握手过程,请求的参数和内容传输是在这些过程之后,因此若是握手过程出错,则不会发送请求内容。

但是,尽管有了以上机制来保证端与端之间通信的安全,仍然无法保证安全,因为防不住中间人***,也就是说,如果有个中间人横跨在你的客户端与服务端之间,你以为你在和服务端握手,但实际上是在与这个中间人握手,这个中间人将持有你目标服务端的公钥,以及它自己产生的密钥和公钥,然后把它自己产生的公钥交给你,你以为你拿到手的是服务端直接给你的公钥,因此这个中间人能够解密你的所有请求。

你的客户端?<–>?Packet Capture/Charles(××× 或 Wi-Fi 或代理,它们都算中间人)?<–>?你的目标服务器

关于这个话题,我回答过一个 StackOverflow 问题,提问者不明白为什么他使用了 HTTPS,结果一个叫做 Packet Capture 的抓包工具居然还能获取到他的请求内容。实际上原理就是因为这个中间人替换掉了服务端的证书。

解决办法就是客户端要对服务端传下来的证书是否正确进行验证,如果使用 OkHttp 的话,可以预设服务端证书的 pining 值,通过 OkHttp Builder 的 certificatePinner 方法进行设置,非常简单。如此设置之后,一旦证书被替换掉,便与你预设的证书 pinning 不对等,握手过程就会中止,请求数据根本不会传输出去,这样中间人也就获取不到你的请求内容了。

除了设置 certificatePinner 的方法之外,还可以把服务端的证书的拷贝 完整地放在客户端一份,等服务端传下来的时候,对本地证书进行对比,若不对等,则抛出错误。对于 OkHttp,可以使用 OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory()) 来给它传递你的证书。

这么做以后,便可以防止网络传输过程中中间人获取你的加密信息。整个应用的基础安全措施也就到此实施结束了。值得一提的是,对于 HTTPS,很多人存在误解,以为 GET 请求是不安全的,POST 才是安全的,实际上,不仅仅 GET 的参数内容会被加密,你的 header、body 等等都是会被加密,都是安全的。

最后,感谢你耐心阅读到到此,虽然本文一行代码都没有贴出,但我相信它提供了很全面详细的理论指南,至于具体的代码,都可以通过 Google 轻松获得,或者有能力的人也可以自行编写实现。

原文地址:http://blog.51cto.com/14009815/2347971

时间: 01-30

Android 密钥保护和 C/S 网络传输安全理论指南的相关文章

Android网络传输中必用的两个加密算法:MD5 和 RSA (附java完成测试代码)

MD5和RSA是网络传输中最常用的两个算法,了解这两个算法原理后就能大致知道加密是怎么一回事了.但这两种算法使用环境有差异,刚好互补. 一.MD5算法 首先MD5是不可逆的,只能加密而不能解密.比如明文是yanzi1225627,得到MD5加密后的字符串是:14F2AE15259E2C276A095E7394DA0CA9  但不能由后面一大串倒推出yanzi1225627.因此可以用来存储用户输入的密码在服务器上.现在下载文件校验文件是否中途被篡改也是用的它,原理参见:http://blog.c

【转】android实时视频网络传输方案总结(一共有五套)

最近研究了Android的实时视频网络传输问题,在视频处理方面花费了大量精力进行研究,总结出以下五套方案,并加以比较 以320×240大小的视频传输为例 方案 压缩率 压缩/传输方式 实时性 平均流量消耗  传输距离 用camera的回调函数发送原始的yuv420数据 0 无压缩,按帧传输 高(20~30 fps) 很高(6.5 Mbps)太恐怖了O_O  近距离有线或无线 用MediaRecorder对yuv420进行H264硬编码后发送 高(95%) 帧间压缩,视频流传输 高(20 fps)

如何在Android中播放网络传输过来的AAC音频?

============问题描述============ 如何在Android中播放网络传输过来的AAC音频?每个包都有ADTS头的. ============解决方案1============ 如果是应用的话,直接设置MediaPlayer setDataSource设置为网络音频的uri,然后prepareAsync(), prepare完成后调用start不就可以了吗? framework层的话还是要用aacdecoder进行解码播放,要么用软件解码,要么用硬件解码.

APP安全--网络传输安全 AES/RSA/ECC/MD5/SHA

移动端App安全如果按CS结构来划分的话,主要涉及客户端本身数据安全,Client到Server网络传输的安全,客户端本身安全又包括代码安全和数据存储安全.所以当我们谈论App安全问题的时候一般来说在以下三类范畴当中. App代码安全,包括代码混淆,加密或者app加壳. App数据存储安全,主要指在磁盘做数据持久化的时候所做的加密. App网络传输安全,指对数据从客户端传输到Server中间过程的加密,防止网络世界当中其他节点对数据的窃听. 这一篇我们先聊下网络传输的安全. 安全相关的基础概念

使用加密解密技术和CA认证解决网络传输中的安全隐患

服务端:xuegod63.cn   IP:192.168.1.63 客户端:xuegod64.cn   IP:192.168.1.64   网络安全: 网络传输中的安全隐患-.   中间人攻击 全隐患:        解决方法 1.窃听-- >  加密 2.篡改 ->  哈西算法:MD5,sha1 (检查数据完整性) 3.伪装(钩鱼网站,伪装WIFI)  ->  身份认证(用户名/密码.数字证书) 4.网络中断 (内网冒冲网关,DDOS )  –>绑定静态arp地址: 加大服务器和

网络传输的加密与解密(不是很难理解的一个版本)

--网络传输的加密与解密--    由于互联网早期并没有考虑到数据报文安全的问题,早期的理念都是基于进行通信的.现在随着网络兴起,互联网上慢慢有很多"犯罪团体",用较低的犯罪成本通常是基于一个网络通信协议的一个小的漏洞来完成窃取.篡改.重播其他人的数据报文. 而往往计算机网络安全维护者和那些恶意攻击者玩的就是一个类似猫鼠游戏,网络安全维护者处处考虑对计算机的安全负责,而恶意攻击者处处找安全的漏洞.而对于那些恶意攻击方式大体分两种. 一种叫被动攻击,大体上来说就是窃听,攻击者获得传输信息

网络传输协议

网络传输协议 1.常见协议 1.HTTP.HTTPS 超文本传输协议 2.FTP 文件传输协议 3.SMTP 简单邮件传输协议 2.http协议 超文本传输协议(HTTP,HyperText Transfer Protocol) 网站是基于HTTP协议的, 例如网站的图片.CSS.JS等都是基于HTTP协议进行传输的. HTML Hypertext Markup Language HTTP协议是由从客户机到服务器的请求(Request)和从服务器到客户机的响应(Response)进行了约束和规范

atitit.二进制数据无损转字符串网络传输

1. gbk的网络传输问题,为什么gbk不能使用来传输二进制数据 1 2. base64 2 3. iso-8859-1  (推荐) 2 4. utf-8 (不能使用) 2 1. gbk的网络传输问题,为什么gbk不能使用来传输二进制数据 gbk会造成信息丢失 由于有些字符在gbk字符集中找不到对应的字符,所以默认使用编码63代替,也就是?(问号)...gbk仅仅能兼容低位asc编码(英文字母),高位编码要使用来编码汉字了... 作者::老哇的爪子Attilax艾龙,EMAIL:[email p

Oracle工具之--ASM与文件系统及跨网络传输文件

Oracle工具之--ASM与文件系统及跨网络传输文件   Oracle DBMS_FILE_TRANSFER可以实现文件系统和ASM磁盘组之间实现文件传输及ASM磁盘组之间跨网络的传输. DBMS_FILE_TRANSFER:   The DBMS_FILE_TRANSFER package provides procedures to copy a binary file within a database or to transfer a binary file between datab

浅谈跨国网络传输

在这个大数据,云部署不断映入眼帘的时代,也许很多人作为公司IT架构的管理者都会觉得有些无助和迷惘.新兴的科技确实给日常的IT工作带来了便利,但亦带来了种种挑战和不可预期的困难. 数据的存储,传输的便利固然重要,但是数据的安全却要重要的多.你永远都不会希望把自己的核心数据放到公共的存储空间中,也随即诞生了私有云等一系列的概念,但是终究还是第三方的架构方案,这种不可控性随时都可发生. 对于跨国的数据传输,国内的网络提供商无论是电信和联通都无法给出完美的答案,因为国内伟大的防火墙的原因,速度慢之又慢,