6.3.2 消息认证码

消息认证码(MAC): 可以检测到负载是否被修改并验证其真实性。实现方式是对进来的请求数据(或是预先设定好的请求数据的子集)生成哈希值,然后将哈希值与随负载一同发送的预先计算好的 MAC 进行对比。 MAC 类似于之前介绍的哈希函数, 但却更加安全, 这是因为它们总是与一个密钥配对。应用会计算随请求发送的 MAC 值。 接下来, 将进来的 MAC 与服务层使用相同密钥和数据集计算出的 MAC 进行比较。 如果两个 MAC 不同, 我们就认为消息被修改了。 另一种方式是生成密文的 MAC。 虽然结果都是一样的, 不过这样可以在执行代价比较高昂的解密处理前判断消息是否已经被修改过

虽然还有其他的 MAC 算法, 不过本节介绍的示例专注于基于哈希的消息认证码(HMAC), 这是因为 HMAC 是 iOS 和大多数服务层平台原生支持的。 HMAC 也经常被称作密钥消息认证码, 它是由 RFC 2104(http://tools.ietf.org/html/rfc2104) 定义的。 HMAC 可以使用任何哈希函数, 通常会使用 MD5 或 SHA-1, 不过其功能主要依赖于底层哈希函数的功能与密钥。 虽然 MD5 哈希算法存在一些弱点, SHA-1 的加密性更强一些, 不过这并不会对它们在 HMAC 中的使用造成影响

iOS HMAC 实现支持 MD5、SHA-1、SHA-224、SHA-256、SHA-384 及 SHA-512 摘要算法。 HMAC 的输出长度总是与使用的哈希算法的摘要长度一样。 与之前介绍的其他哈希函数一样, HMAC 既可以手工生成, 也可以使用便捷方法生成, 代码清单 6-7 演示了如何使用便捷方法生成 HMAC

HMAC 示例基于之前创建的 NSString+Hashing 类别构建。 首先, 该类别还需要方法定义并导入两个库, 如代码清单 6-7 所示

Hashing.h

导入 CommonCryptor 似乎没有必要, 不过需要在 hmacWithKey: 的实现中访问密钥长度常量 kCCKeySizeAES256, 如代码清单 6-8 所示。


Hashing.m

代码清单 6-8 包含 hmacWithKey: 的实现, 它类似于之前介绍过的 hashWithType: 方法。 不过有两个差别, 分别是增加了密钥以及只能使用 SHA-256 摘要算法的限制。 密钥与输入数据的创建采用 UTF8 编码, 然后传给 CCHmac() 函数来创建 HMAC。 该函数会使用 HMAC 值来装配缓存, 然后 hmacWithKey: 以字符串的形式将其返回

你可能想知道密钥的值来自哪里, 是如何选择的。 密钥对于密码安全来说是必不可少的, 密钥长度的重要性怎么强调也不过分! 如果缺乏安全且随机的密钥, 应用就会暴露给各种攻击! 根据需要保护的数据的不同, 你可能还会受到可能的诉讼问题, 比如数据外泄或是违反美国健康保险流通与责任法案(HIPAA)等。 保护好密钥是确保传输数据安全的唯一保障措施

由于密钥是安全模型的关键所在, 因此必须好好选择。 密钥的最终长度应该等于加密算法或 HMAC 的密钥长度, 短于算法密钥长度的都需要补 NULL, 直到等于算法密钥的长度为止, 这会削弱缺少的那些字符的随机性。 如果必须将用户的输入数据作为密钥的基础, 那么可以在输入前追加随机或伪随机的值, 这叫做加盐。 如果需要再生成这个密钥, 那么确保将用于生成最终密钥值的盐也存储起来。 最后, 使用之前介绍过的算法(如 MD5 或 SHA-1 等)运行几千次哈希计算来得到加盐后的值, 然后去除一定的字节数作为最终使用的密钥

如果应用要求以用户输入作为密钥的基础, 那么可以考虑使用 CommonCrypto/CommonKeyDerivation 库的 CCKeyDerivationPBKDF() 函数。 CCKeyDerivationPBKDF() 会返回盐的密钥值、推导算法、推导次数以及用户指定的输出密钥长度。 还可以通过 SecRandomCopyBytes() 函数生成随机的字节数组

虽然对于开发者来说, 将各种处理细节输出到日志中是种很常见的做法, 不过绝不应该将生成的密钥打印到控制台。 日志文件可以非常容易地从设备上获取, 如果被攻击者发现, 那就是非常严重的安全问题

共享密钥的缺点在于应用需要规划好密钥版本。 不可避免地, 你会遇到必须修改共享密钥的情况。 这就要求部署应用的新版本, 然后更新服务层。 然而, iOS 用户并不总是会安装应用更新, 也没有任何机制可以强制用户这么做。 对于使用旧版本应用的用户来说, 该怎么处理呢? 需要确保来自旧版本的用户交易也能被正确地解密、 验证并被服务处理。 密钥版本化可以在不发布应用更新的情况下解决这个问题: 不过, 要从一开始就将其放到应用的开发当中。


生成 HMAC

该例将资金转移负载的子集作为 MAC; 不过, 也可以使用整个负载, MAC 的拼接顺序与属性(即想要哈希的值) 必须与服务层共享, 这样才能确保解密的正确性, 如果安谧端或服务层在不同的假设下动作, 那么消息完整性检查就会失败, 什么都不会得到处理

既然已经传输了 MAC, 并且服务层也对负载进行了解密, 那么服务必须生成与之相伴的 MAC。 如下代码片段展示了如何使用与客户端相同的拼接输入字符串在 PHP 中生成 HMAC(PHP 函数 hash_hmac() 与 iOS 中的 HMac() 函数接收类似的输入, 并且可以指定所用的算法、哈希的内容以及要使用的密钥):

PHP mac

注意之前两个示例的输出值是一样的。 由于这两个值相同, 因此服务层可以相信接收到的是未被修改的请求, 并且可以安全地进行资金转移

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容