Mobile BI 移动商务智能的数据安全

这篇文章主要介绍了Mobile BI(移动商务智能)使用过程中本地的数据安全,主要包括如何保护以及数据加密两块。

文章的具体内容包括:数据格式(Binary Data、XML、JSON),数据保护(Cache Protection、Confidential Project、DPC),数据加密(文件加密、凭证加密)、iOS Coding引用

数据格式

在移动应用中,数据的格式保证了各模块之间数据交互的可能性。这包括了移动应用和服务器之间、移动应用自身各模块之间、以及移动应用与移动存储之间的数据交互,一般而言,这三种类型都会使用相同的数据格式。

对于我们的Mobile BI产品,iOS主要基于Binary Data,而Android类似于Web,主要使用了JSON Data,另外XML也在一部分功能中被使用,比如配置文件等。

Binary Data

这属于自定义的一种数据格式,将数据的信息序列化到二进制数据上,而为了服务器和客户端能够交流,客户端会使用服务器相同的逻辑来处理二进制数据的信息。

因为数据的格式是自定义的,所以相应的不需要太多上下文的信息,也更容易进行优化,所以相比XML或者JSON而言,传输效率是最高的。

XML

XML Extensible Markup Language 可扩展标记语言,被设计用来传送及携带数据信息,而不用来表现或展示数据,与此对应的HTML语言是用来表现数据的。需要学习XML语法规范的可以参见w3schools XML Tutorial

示例

<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
<food>
    <name>Belgian Waffles</name>
    <price>$5.95</price>
    <description>
   Two of our famous Belgian Waffles with plenty of real maple syrup
   </description>
    <calories>650</calories>
</food>
<food>
    <name>Strawberry Belgian Waffles</name>
    <price>$7.95</price>
    <description>
    Light Belgian waffles covered with strawberries and whipped cream
    </description>
    <calories>900</calories>
</food>
</breakfast_menu>

XML标签是大小写敏感的,此外,因为XML格式本身需要使用一些特殊字符,为了避免这些字符在作为值时与XML本身的格式信息冲突,我们需要进行一些格式转换,即Escaping Characters: < -> <, > -> >, & -> &, ' -> ' and " -> "

在使用XML的过程中,可以将叶节点值存储在属性Attribute或者元素Element中,即 ANF Attribute Normal Form <ml v="250"/>, 以及 ENF Element Normal Form <ml><v>250</v></ml>

DOM Document Object Model 文档对象模型,为XML的标准编程接口。DOM把XML文档作为树结构来查看,通常需要加载整个文档和构造层次结构来进行操作。因为整个树被加载在内存中,所以相应的数据结构的修改、查找会方面很多。

SAX Simple API for XML 是一个循序存取XML的解析器API,SAX运行时是单向的,即解析过的资料无法在不重新开始的情况下再次读取。相比较DOM,SAX仅需要很少量的内存,DOM一般需要将整棵树都放入内存,所以DOM的内存使用量是依赖于输入资料的大小,而SAX只基于XML树的最大深度以及XML属性存储的最大资料。SAX处理文件的读取解析会很快速,但是并不适用于快速查找和更新。

iOS中使用NSXMLParser事件驱动解析器,即SAX方式解析XML数据。

JSON

JSON JavaScript Object Notation JavaScript对象表示法 是一种轻量级的数据交换语言,以文字为基础,易于阅读。JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,其数据格式与语言无关。JSON常用于WEB应用以及JavaScript、Java、Node.js应用的开发

示例:

{
  "firstName": "John",
  "lastName": "Smith",
  "isAlive": true,
  "age": 25,
  "address": {
    "streetAddress": "21 2nd Street",
    "city": "New York",
    "state": "NY",
    "postalCode": "10021-3100"
  },
  "phoneNumbers": [
    {
      "type": "home",
      "number": "212 555-1234"
    },
    {
      "type": "office",
      "number": "646 555-4567"
    },
  ],
  "children": [],
  "spouse": null
}

因为作为JavaScript的子集,一般JSON会使用eval()作为读取数据的方式,但这种方式只能针对可靠的数据来源,因为eval()同样可以执行任意JavaScript代码。此外可以使用JSON.parse(str), parseJSON这种具有安全检查的方法来读取。

与XML相比,XML是一个完整的标记语言,而JSON不是。XML利用标记语言的特性提供了绝佳的延展性,在数据存储、扩展以及高级检索方面具备对JSON的优势,而JSON则比XML更加小巧,并可以依赖于浏览器的内建快速解析支持,所以会更适合于网络数据的传输。

Android提供原生类用于解析JSON,iOS中使用NSJSONSerialization解析JSON数据。

数据保护

Mobile BI iOS Application中文档内容的保存主要使用Binary Data,以文件的形式存储在iOS Storage中,部分XML格式的文件类似。所以我们数据的保护其实讨论的就是如何保护这些存储在Storage中的数据信息。

Cache Protection

在应用的使用过程中,为了支持功能的高效运转以及离线功能的实现,我们需要将一部分数据缓存在设备上,这也就意味着我们需要对这些缓存进行保护,避免随便泄露出去。

一个明显的策略就是我们需要根据用户的意愿以及数据本身的有效性,提供清理缓存数据的功能。我们设计出一系列会触发缓存清理的项目,包括:

Data Wipe on Client Certificate expired
Clear Caches on Logout
Clear on Close
Clear Cached Data
Change Config
Change User
Change Connectivity Settings
Security Policy Updated
User enters incorrect DPC more than X times
Reset Application
Password Expired
Locale Change

Confidential Project

这个功能是使用一个"Cover Screen"遮盖住应用的内容,而用户需要输入验证才能移除这个"Cover Screen"。这个功能的特殊点在于,用户验证采用的是与Mobile BI的Project一致的凭证(即用户名和密码等),这一点满足了一部分客户的需求。

但是缺点也是显而易见:只是盖住了应用的内容,说明应用的内容可以在用户被验证前产生,这就有泄露的可能性;采用与Project一致的凭证,这就说明要么需要同缓存的Project凭证相比较,要么需要通过网络确认,都有将凭证暴露的危险。因此这个功能现在已经被移除。

DPC

DPC(Device Protection Code) "Designed to prevent unauthorized access to the Mobile application",将用户输入的密码与应用中加密密钥绑定,确保只有在用户输入有效密码后才能解密应用数据,利用这一特性,可以取代Confidential Project这个功能。

对于用户输入的密码,我们不希望应用直接记录下来,因为只要记录,就会存在不安全的可能性。而对于应用自身使用的加密方式,一般会为了速度而选择AES这种速度较快的加密方式。我们需要一种策略来建立两者之间的联系,并保证两者的安全要求都能够得到满足:

Data Encryption Key
  - Stored in the keychain with the encrypted format

Password Encryption Key
  - Encrypt the Data Encryption Key

我们设计了这两个加密密钥,一个数据密钥用来加解密应用数据,被以加密的形式存储在Keychain中,另一个密码密钥用来解密这个数据密钥,而这个密码密钥是直接通过用户的输入密码而生成的。使用这种策略,可以保证:

用户的密码是可变的,这样保证了在用户修改密码的情况下,也不需要更新数据密钥,从而保证加密 的应用数据可以继续被使用。

密码密钥由用户输入直接生成,不需要存储,保证了安全性。

独立的两个密钥满足了不同的要求:应用数据量大,对加解密的效率要求高;密码密钥只在应用打开时使用,对安全要求度高

我们使用PBKDF来生成密码密钥,这属于CPU密集型算法,基本规则就是将输入的Salted Hash进行多次重复计算,而这个次数是可设定的,使用这种策略可以有效的对应类似于彩虹表这种攻击。对于首次生成PBKDF密钥:

选用"256位的Salt",计算Iteration,确认"SHA256 哈希算法",使用"Password + Salt + Iteration"组合生成 "256位" 的PBKDF Key

在使用的过程中,为了安全性,我们不会直接保存这个密码密钥值,而只是把生成这个值所需要的信息保存起来,加上用户输入的密码,每次验证时使用这些信息生成密钥值。加上保存一个Message以及相应HMAC值的方式,使用这个新生成的密钥值加密Message与保存的HMAC值进行比对来验证用户:

信息保存至Keychain:Salt, Iteration 用来生成PDKDF;Message, HMAC 用于验证

数据加密

Mobile BI中包含大量的报表数据信息,这些数据会被保存在设备的本地存储上面,相应的我们也提供了不同级别的数据加密方式来保护这些数据。

文件加密

对于iOS设备来说,在使用iOS的文件API时,我们可以相应的选择文件保护的方式,即称为Hardware Encryption,保护的级别被设定为NSDataWritingFileProtectionComplete,这代表文件是被加密保存的,并且只有在设备在解锁状态下才能够被访问。

在设备被锁的情况下,我们相应的提供了Software Encryption的方式,即我们自己在保存数据之前会对数据加密,这种方式也可以应用到全局,即可实现软硬同时加密的方式。

目前我们采用的是256位AES加密方式,我们会通过一系列的方式确保生成一个足够安全的数据加密密钥:

Data Encryption Key
数据加密密钥,其实就是一段固定长度的随机数据,当然要确保足够随机和安全,示例如下:

uint8_t* newKeyBytes = malloc(keySize * sizeof(uint8_t));
memset((void *)newKeyBytes, 0x0, keySize);
OSStatus result = SecRandomCopyBytes(kSecRandomDefault, kCCKeySizeAES256, newKeyBytes);
    
NSData* newKey = [[NSData alloc] initWithBytes:(const void *)newKeyBytes length:kCCKeySizeAES256];

Salting
密码加盐Salting是密码存储时采用的一种安全方法,即加一些随机的数据到已有密码里,可以保证同样的密码能够生成不同的散列,提高破解难度:

Appending some random data to the plaintext before hashing

  • A best practice for password storage: ensures that the same password doesn’t always result in the same hash
  • The Same principle for which we introduced the random IV for credentials encryption

Random IV
初始向量 Initialization Vector 是在加密过程中引入的一个随机数据,确保同样的密码可以生成不同的加密结果:

A Random IV: avoid against Same Text Attack

  • A text will always be encrypted to same encrypted text
  • The IV need not be secure hence we pre-append it to the encrypted text so that we can use it as input while decryption

加密流程

加密的数据由 头数据Header、初始向量IV、数据Data 三者构成,其中的头数据包含了加密使用的算法,加密版本等信息。而加密时需要以下设定:算法 AES、工作模式 CBC、填充 PKCS7 Padding、密钥长度 256、IV在CBC中使用。

另外,我们在最终存储时,会使用Base64将结果编码,等于是进一步混淆。

凭证加密

区别于数据文件的可选 Sofware Encyprtion 加密方式,对于凭证信息,包括用户名密码这些敏感信息,我们是默认加密后再保存的。密码加密的方式流程与文件加密一致,采用256位AES加密算法。

不仅于此,我们还提供了多种设置可以配置密码的存储、失效、改动等以便更好的提高安全性:

Never Cache Credentials
Never Persist Credentials
Password Expiration
Password Has Expired
Must Change Password

iOS Coding

PBKDF
PBKDF 即 Password Based Key Derivation Function

iOS中提供的PBKDF的方法如下:


它包含的一些参数的信息如下:

"algorithm" 仅支持 PBKDF2
"password" 即输入的密码文本
"salt" 用来混淆的salt盐
"prf" Pseudo Random Algorithm 伪随机算法
    kCCPRFHmacAlgSHA1
    kCCPRFHmacAlgSHA224
    kCCPRFHmacAlgSHA256
    kCCPRFHmacAlgSHA384
    kCCPRFHmacAlgSHA512
"rounds" PRF的使用次数
"derivedKey" 即生成的密钥
"derivedKey" 即生成的密钥的长度

在我们的应用中选用kCCPRFHmacAlgSHA256算法以及设定生成的密钥长度为kCCKeySizeAES256

CCCalibratePBKDF
根据设定的要求计算出PRF需要循环的次数:


它的参数信息如下:

"algorithm" 仅支持 PBKDF2
"passwordLen" 密码文本的长度
"saltLen" 混淆盐的长度
"prf" Pseudo Random Algorithm 伪随机算法
"derivedKeyLen" 生成密钥的预期长度
"msec" 结合以上参数的情况下,所预期的计算时间

SecRandomCopyBytes
使用生成的安全随机数作为混淆盐 Salt

CCHmac
密钥散列消息认证码生成函数

CCCrypt

用来实现加解密的函数,基本是顺序实现了:
CCCrytorCreate(), CCCryptorUpdate(), CCCryptorFinal(), and CCCryptorRelease()

参数信息:

"op" 即设定加解密模式
    kCCEncrypt
    kCCDecrypt
"alg" 指定使用的算法
    kCCAlgorithmAES
    kCCAlgorithmDES
    kCCAlgorithm3DES 
    kCCAlgorithmCAST  
    kCCAlgorithmRC4
    kCCAlgorithmRC2
    kCCAlgorithmBlowfish
"options" 确定分组密码的工作模式,默认为CBC模式
    kCCOptionPKCS7Padding: Perform PKCS7 padding
    kCCOptionECBMode: Electronic Code Book Mode
"iv" 引入的初始化向量,在CBC模式下需要与密码块大小一致
"key", "keyLength" 即使用的密钥

引用

Wikipedia Extensible Markup Language

Wikipedia JavaScript Object Notation

iOS开发——XML/JSON数据解析

推荐阅读更多精彩内容