iOS开发基础90-iOS 加密:从 RSA/AES/MD5 到 HMAC 与钥匙串

iOS 加密算法完全指南:从 RSA/AES/MD5 到 HMAC 与钥匙串

数据安全是 iOS 开发中不可忽视的重要话题。本文从三大加密算法(非对称、对称、哈希)讲起,深入解析 RSA、AES、MD5/SHA 的原理与使用场景,重点讲解 iOS 开发的两条安全原则(网络传输不允许明文、本地存储不允许明文),补充加盐、HMAC、HMAC+时间戳防重放、钥匙串等实际方案,纠正常见的错误认知,最后给出 iOS 加密框架、Swift 版本对照和常见坑排查。


一、加密算法概述

一句话原理

加密算法分为三大类:非对称加密(公钥私钥配对,如 RSA)、对称加密(同一个密钥加解密,如 AES)、哈希散列(不可逆的摘要,如 MD5/SHA),三者各有适用场景,通常组合使用。

三大类对比

类型 代表算法 特点 典型用途
非对称加密 RSA、ECC 公钥加密私钥解密,性能差,安全 HTTPS 握手、数字签名、密钥交换
对称加密 AES、DES、3DES 同一个密钥加解密,性能好 大量数据加密、HTTPS 数据传输
哈希散列 MD5、SHA1、SHA256 不可逆,定长输出,用于摘要/指纹 密码存储、数据校验、数字签名

实际系统中通常是组合使用:HTTPS 用 RSA 交换对称密钥,用 AES 加密传输数据,用 SHA 做数据完整性校验和数字签名。


二、非对称加密(RSA)

一句话原理

非对称加密有一对密钥:公钥(可以公开)和私钥(必须保密)。公钥加密的数据只有私钥能解密,私钥签名的数据只有公钥能验证。

RSA 原理简述

RSA 的安全性基于大整数因式分解的困难性:

  1. 找两个很大的质数 p 和 q,相乘得到 n = p × q。
  2. 公钥是 (n, e),私钥是 (n, d)。
  3. 破解 RSA 需要从 n 反推出 p 和 q,当 n 足够大时(如 2048 位),目前的计算能力无法在合理时间内分解。

两种核心用法

1. 加密:公钥加密,私钥解密

发送方:用接收方的公钥加密数据 → 密文
接收方:用自己的私钥解密 → 明文
  • 任何人都可以用公钥加密,但只有私钥持有者能解密。
  • 用于:HTTPS 密钥交换、加密发送给特定人的数据。

2. 数字签名:私钥签名,公钥验签

发送方:用自己的私钥对数据摘要签名 → 签名
接收方:用发送方的公钥验证签名 → 确认数据来自发送方且未被篡改
  • 只有私钥持有者能签名,任何人都可以用公钥验证。
  • 用于:数字证书、App 签名、API 接口签名、防篡改。

常见混淆:"私钥加密,公钥解密"严格来说叫数字签名,不是普通的加密。因为私钥只有一个人有,用私钥加密的数据所有人都能用公钥解密,没有保密性,但能证明数据来自私钥持有者。

RSA 的使用场景

场景 说明
HTTPS 握手 客户端用服务器公钥加密预主密钥,只有服务器私钥能解密
数字签名 App 签名、证书验证、JWT 签名
API 接口签名 服务端用私钥签名,客户端用公钥验签,防篡改防伪造
密钥交换 安全地交换对称加密的密钥

注意事项

  • RSA 不适合加密大数据:性能差(比 AES 慢几百倍),通常只用来加密对称密钥或数据摘要。
  • 密钥长度:推荐 2048 位及以上,1024 位已被认为不安全。
  • 填充方式:必须用安全的填充方式(OAEP),不要用原始 RSA 或 PKCS1_v1.5(有攻击风险)。

三、对称加密(DES / 3DES / AES)

一句话原理

对称加密用同一个密钥进行加密和解密,性能好,适合加密大量数据,但密钥的安全分发是难点。

1. DES(已淘汰)

  • 56 位密钥,太短,1999 年就被暴力破解。
  • 不要在新项目中使用。

2. 3DES(逐渐淘汰)

  • DES 的改进版,对数据进行三次 DES 加密(加密-解密-加密)。
  • 密钥长度 112 位或 168 位,安全性比 DES 高,但性能差。
  • NIST 已在 2023 年废弃 3DES,新项目不推荐使用。

3. AES(当前标准,推荐)

  • 高级加密标准(Advanced Encryption Standard),美国国家安全局(NSA)用于加密绝密信息。
  • 密钥长度:128 位、192 位、256 位(AES-256 最安全)。
  • iOS 系统内部的加密、钥匙串、文件保护都用 AES。
  • AES 算法本身目前没有被破解,但弱密钥、错误的加密模式会导致安全问题。

加密模式(重要)

AES 有多种加密模式,选择错误的模式会导致安全漏洞:

模式 特点 安全性 推荐
ECB 相同明文块加密后相同,暴露数据模式 ❌ 极不安全(可被图案攻击) 不推荐
CBC 每个明文块与前一个密文块异或,需要 IV ✅ 安全 推荐
CTR 计数器模式,流加密,需要 IV/nonce ✅ 安全 推荐
GCM 计数器模式 + 认证,同时保证机密性和完整性 ✅✅ 最安全(带认证) 最推荐

ECB 模式是最常见的坑:相同的明文块会产生相同的密文块,导致加密后的图片还能看出轮廓。必须用 CBC、CTR 或 GCM 模式。

初始化向量(IV)

  • CBC、CTR、GCM 模式都需要一个初始化向量(IV / Nonce)。
  • IV 不需要保密,但必须是随机的,且每次加密都不同。
  • IV 通常和密文一起存储/传输。
  • 不要用固定 IV,否则相同明文会产生相同密文,降低安全性。

填充方式(Padding)

  • 对称加密是按块加密的(AES 块大小 16 字节),数据长度不是块的整数倍时需要填充。
  • 推荐用 PKCS7(PKCS5 是 PKCS7 的子集,块大小固定 8 字节)。
  • 不要用零填充(Zero Padding),无法区分数据末尾的零和填充的零。

iOS 中的 AES 加密示例(CommonCrypto)

#import <CommonCrypto/CommonCrypto.h>

// AES 加密(CBC 模式 + PKCS7 填充)
- (NSData *)aesEncryptData:(NSData *)data key:(NSData *)key iv:(NSData *)iv {
    NSUInteger dataLength = data.length;
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesEncrypted = 0;
    CCCryptorStatus status = CCCrypt(kCCEncrypt,
                                      kCCAlgorithmAES,
                                      kCCOptionPKCS7Padding, // CBC 模式(默认)
                                      key.bytes, key.length,
                                      iv.bytes, // IV
                                      data.bytes, dataLength,
                                      buffer, bufferSize,
                                      &numBytesEncrypted);
    
    if (status == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }
    free(buffer);
    return nil;
}

注意:kCCOptionPKCS7Padding 单独使用时是 CBC 模式。如果加 kCCOptionECBMode 就是 ECB 模式(不推荐)。


四、哈希散列函数(MD5 / SHA)

一句话原理

哈希函数把任意长度的数据转换成固定长度的摘要(指纹),过程不可逆,相同输入永远得到相同输出,不同输入几乎不可能得到相同输出(抗碰撞)。

哈希函数的特点

特点 说明
不可逆 无法从摘要反推出原始数据
定长输出 MD5 输出 32 位十六进制(128 位),SHA256 输出 64 位(256 位)
确定性 相同输入永远得到相同输出
雪崩效应 输入改变一点点,输出完全不同
抗碰撞 很难找到两个不同输入产生相同输出

常见算法安全性对比

算法 输出长度 安全性 现状
MD5 128 位(32字符) ❌ 已被破解(碰撞攻击) 不推荐用于安全场景
SHA1 160 位(40字符) ❌ 已被破解(SHAttered 碰撞攻击) 不推荐用于安全场景
SHA256 256 位(64字符) ✅ 安全 推荐
SHA512 512 位(128字符) ✅✅ 更安全 推荐(高安全需求)

重要纠正:有一种常见说法是"MD5 不能反算所以安全",这是对的,但 MD5 已经被证明有碰撞攻击(可以构造两个不同文件产生相同 MD5),所以 MD5 不能用于安全场景(如密码存储、数字签名)。MD5 还可以用于非安全场景(如文件去重、简单校验),但安全相关的必须用 SHA256 及以上。

哈希的用途

用途 说明
密码存储 存储密码的哈希而不是明文(但需要加盐,见下文)
数据完整性校验 下载文件后校验 MD5/SHA,确认文件未被篡改
数字签名 对数据摘要签名,而不是对原始数据签名
去重 文件/图片的 MD5 作为唯一标识去重
API 签名 对请求参数排序后拼接,计算哈希作为签名

密码存储的正确姿势:慢哈希

普通哈希(MD5/SHA)计算速度太快,攻击者可以用彩虹表或暴力破解每秒计算上亿次。密码存储必须用慢哈希算法:

算法 特点 推荐
bcrypt 自带盐,可配置计算成本,专门为密码设计 ✅ 推荐
scrypt 内存困难型,抗 ASIC 攻击 ✅ 推荐
Argon2 密码哈希竞赛冠军,最安全 ✅✅ 最推荐
PBKDF2 标准算法,可配置迭代次数 可用

iOS 中可以用 CommonCrypto 的 CCKeyDerivationPBKDF 实现 PBKDF2,或用第三方库(如 BCrypt)。


五、iOS 安全原则一:网络传输不允许明文

一句话原理

用户隐私数据(密码、token、身份证号等)绝对不能以明文形式在网络上传输,必须加密。下面介绍加盐、HMAC、HMAC+时间戳等方案,并补充更安全的做法。

方案一:加盐(Salt)

原理

在用户密码后面拼接一串随机字符串(盐),再计算哈希:

存储:hash(密码 + 盐) → 数据库存储哈希和盐
登录:hash(输入的密码 + 盐) → 和数据库存储的哈希对比

静态盐 vs 动态盐

类型 说明 安全性
静态盐(常见错误做法) 所有用户用同一个盐,写死在客户端和服务端 ⚠️ 较低,盐泄露后所有用户都受影响
动态盐(推荐) 每个用户注册时随机生成一个盐,和哈希一起存在数据库 ✅ 高,一个用户的盐泄露不影响其他用户

常见错误做法:把盐写死在客户端代码里,所有用户用同一个盐。这样一旦盐被逆向出来,所有用户的密码都可以被彩虹表攻击。正确的做法是动态盐:每个用户注册时随机生成盐,和密码哈希一起存在服务端,客户端登录时先从服务端获取该用户的盐,再计算哈希。

加盐的注意事项

  • 盐必须足够长(至少 16 字节)、随机(用密码学安全的随机数生成器)。
  • 每个用户的盐不同。
  • 盐不需要保密,和哈希一起存储即可。
  • 加盐能有效防御彩虹表攻击,但不能防御暴力破解(所以还要用慢哈希)。

方案二:HMAC(哈希消息认证码)

一句话原理

HMAC 是用一个密钥和哈希算法生成消息认证码,既能验证数据完整性,又能验证数据来源(只有持有密钥的人才能生成正确的 HMAC)。

原理

HMAC(密钥, 消息) = 哈希((密钥 XOR opad) + 哈希((密钥 XOR ipad) + 消息))

常用:HMAC-MD5、HMAC-SHA1、HMAC-SHA256(推荐)。

HMAC 登录方案

一种常见的 HMAC 登录方案:

  1. 注册时:服务端给每个用户生成一个随机密钥 KEY,客户端和服务端都保存。
  2. 登录时:客户端计算 HMAC(KEY, 密码) 发给服务端,服务端用保存的值对比。

这个方案的好处:

  • 网络上传输的是 HMAC 结果,不是密码明文。
  • 即使被截获,攻击者也无法反推出密码。
  • 每个用户的 KEY 不同,一个用户的 KEY 泄露不影响其他用户。

隐患:

  • 攻击者截获 HMAC 结果后,可以重放攻击(直接用这个密文登录)。
  • 所以需要加时间戳(见下文)。

方案三:HMAC + 时间戳(防重放攻击)

原理

在 HMAC 结果中加入时间戳,使每次登录的密文都不同,且有有效期:

客户端:HMAC(KEY, 密码 + 时间戳(精确到分)) → 发送给服务端
服务端:用当前时间和前一分钟分别计算 HMAC,和客户端发来的对比

这样:

  • 密文每分钟变化一次。
  • 攻击者截获的密文只有 1~2 分钟有效期。
  • 有效防御重放攻击。

这是一种很实用的防重放思路。实际项目中更常用的是 nonce(随机数)+ 时间戳 的方式,服务端记录已使用的 nonce,防止重放。

更安全的方案:HTTPS + 慢哈希

加盐和 HMAC 方案都是在应用层做加密,但最基础也是最重要的是传输层用 HTTPS:

层级 方案 说明
传输层 HTTPS(TLS) 加密整个传输通道,防窃听、防篡改、防中间人
应用层 密码哈希(bcrypt/Argon2) 服务端存储密码的哈希,不存明文
应用层 Token(JWT/Session) 登录后用 token 认证,不传密码

最佳实践:

  1. 所有接口必须用 HTTPS。
  2. 客户端发送密码明文(HTTPS 通道已加密),服务端用 bcrypt/Argon2 哈希后存储。
  3. 登录成功后返回 token,后续请求用 token 认证。
  4. 高安全需求的接口可以再加一层应用层签名(HMAC + 时间戳 + nonce)。

六、iOS 安全原则二:本地存储不允许明文

一句话原理

用户隐私数据(密码、token、身份证号等)绝对不能以明文形式保存在本地(NSUserDefaults、plist、文件等),必须加密存储。iOS 最推荐的方案是钥匙串(Keychain)。

方案一:钥匙串(Keychain,推荐)

什么是钥匙串

钥匙串是 iOS 系统级的安全存储机制,用 AES 加密存储敏感信息,数据保存在系统的沙盒之外(独立的数据库),由系统统一管理。

常见错误说法:有一种说法是"钥匙串从 iOS 7.0.3 版本才开放给开发者访问",这是不准确的。钥匙串从 iOS 2.0 就存在并开放给开发者使用,iOS 7.0.3 是修复了钥匙串的某个安全漏洞。

钥匙串的特点

特点 说明
系统级加密 用 AES 加密,硬件级安全(Secure Enclave)
App 删除后数据不丢失 卸载 App 后钥匙串数据仍然保留,重装 App 还能读取
跨 App 共享 通过 App Group 可以在同一开发者的多个 App 间共享钥匙串数据
iCloud 同步 开启 Keychain Sync 后可以在多设备间同步
只能存小数据 适合存密码、token、密钥、证书等小数据,不适合存大文件
C 语言 API 原生 API 是 Security.framework 的 C 接口,繁琐难用

钥匙串能存什么

  • 密码(用户密码、Wi-Fi 密码)
  • Token(登录 token、refresh token)
  • 加密密钥(对称密钥、私钥)
  • 证书
  • 信用卡信息(高安全 App)

SSKeyChain / SAMKeychain 用法

SSKeyChain(SAMKeychain 是其 fork)是对钥匙串 C API 的轻量封装,只有 5 个方法:

#import <SSKeychain/SSKeychain.h>

// 存储密码
[SSKeychain setPassword:@"用户密码123"
            forService:@"com.example.app"   // 通常用 Bundle ID
               account:@"user@example.com"]; // 账号

// 读取密码
NSString *password = [SSKeychain passwordForService:@"com.example.app"
                                              account:@"user@example.com"];

// 删除密码
[SSKeychain deletePasswordForService:@"com.example.app"
                             account:@"user@example.com"];

// 获取所有账号
NSArray *accounts = [SSKeychain accountsForService:@"com.example.app"];

// 获取所有服务
NSArray *allAccounts = [SSKeychain allAccounts];

三个参数的含义

参数 说明 示例
service 服务名,通常用 App 的 Bundle ID @"com.example.app"
account 账号标识,区分不同用户 @"user@example.com" 或用户 ID
password 要存储的密码/数据 @"password123" 或 token 字符串

注意:钥匙串存的是字符串,如果要存 NSData 或自定义对象,需要先序列化成字符串(如 Base64 编码)。

Xcode 配置

使用钥匙串需要打开 Keychain Sharing 开关(即使不需要共享,也建议打开,否则可能出现奇怪的问题):

  1. 项目设置 → Signing & Capabilities → + Capability → Keychain Sharing。
  2. 添加一个 Keychain Group(通常用 Bundle ID)。

方案二:NSUserDefaults + 加密

如果数据量小且不需要系统级安全,可以用 AES 加密后存 NSUserDefaults:

// 加密 token 后存储
NSData *encryptedToken = [self aesEncryptData:[token dataUsingEncoding:NSUTF8StringEncoding]
                                            key:encryptionKey
                                               iv:iv];
[[NSUserDefaults standardUserDefaults] setObject:encryptedToken forKey:@"token"];

但这种方式的安全性不如钥匙串(加密密钥也存在本地,可能被逆向获取),敏感数据优先用钥匙串。

方案三:文件加密

大文件(如数据库、下载的敏感文件)可以用 AES 加密后存储,或用 iOS 的数据保护(Data Protection):

// 写文件时设置数据保护选项
NSData *data = ...;
[data writeToFile:path options:NSDataWritingFileProtectionComplete error:nil];

NSDataWritingFileProtectionComplete 会用设备密钥加密文件,设备锁定时无法读取。

绝对不要做的事

  • ❌ 不要用 NSUserDefaults 存密码、token 等敏感信息(明文存储,容易被导出)。
  • ❌ 不要用 plist 文件存敏感信息。
  • ❌ 不要把加密密钥写死在代码里(容易被逆向获取)。
  • ❌ 不要自己发明加密算法(用标准的 AES/RSA/SHA)。

七、MD5 的其他用法

1. 搜索(关键字无序匹配)

场景

搜索"深圳 福田 喜年支行"和搜索"福田 喜年支行 深圳",结果应该一样(关键字顺序不影响搜索结果)。

原理

常见错误认知:有一种说法是"将三个关键字转为 MD5 字符串后按位相加结果一样",这个说法不准确。正确的原理是:

  1. 将搜索关键字按某种规则排序(如按拼音首字母、按字典序)。
  2. 排序后拼接成一个字符串。
  3. 对拼接后的字符串计算 MD5。

这样不管用户输入的顺序如何,排序后的字符串都一样,MD5 也就一样。

- (NSString *)searchKeyForKeywords:(NSArray *)keywords {
    // 1. 排序(按字典序)
    NSArray *sorted = [keywords sortedArrayUsingSelector:@selector(compare:)];
    // 2. 拼接
    NSString *combined = [sorted componentsJoinedByString:@""];
    // 3. MD5
    return [self md5:combined];
}

不是"按位相加",而是"排序后拼接再哈希"。

2. 版权/去重(文件指纹)

原理

文件的 MD5 是文件内容的指纹:

  • 相同内容的文件(即使文件名不同、后缀不同),MD5 相同。
  • 修改过的文件(PS 过的图片、编辑过的文档),MD5 不同。
  • 文件后缀名只影响操作系统用什么程序打开,不影响文件内容,所以不影响 MD5。

用途

用途 说明
图片/文件去重 用 MD5 作为唯一标识,避免重复存储
版权验证 对比 MD5 判断是否为原图/原文件
下载校验 下载后对比 MD5,确认文件完整未被篡改
秒传 上传前计算 MD5,如果服务器已有相同 MD5 的文件,直接秒传

注意

  • MD5 有碰撞攻击风险,如果是版权保护/安全校验,推荐用 SHA256。
  • 如果只是去重/秒传(非安全场景),MD5 仍然够用。

3. 数据完整性校验

下载文件、传输数据后,计算 MD5/SHA 和发送方提供的校验值对比,确认数据在传输过程中没有损坏或被篡改:

// 下载文件后校验
NSData *downloadedData = [NSData dataWithContentsOfURL:fileURL];
NSString *fileMD5 = [self md5ForData:downloadedData];
if ([fileMD5 isEqualToString:expectedMD5]) {
    NSLog(@"文件完整");
} else {
    NSLog(@"文件损坏,重新下载");
}

八、iOS 加密框架与工具

1. CommonCrypto(系统底层,C 语言 API)

  • iOS 系统自带的加密框架,C 语言接口。
  • 支持:AES、DES、3DES、SHA、MD5、HMAC、PBKDF2。
  • 不需要额外引入库,#import <CommonCrypto/CommonCrypto.h> 即可。
  • 性能好,但 API 繁琐,容易出错。

2. CryptoKit(iOS 13+,Swift 原生,推荐)

  • iOS 13 引入的 Swift 原生加密框架,API 简洁安全。
  • 支持:SHA256/SHA384/SHA512、HMAC、AES-GCM、ChaCha20-Poly1305、Curve25519 等。
  • 自动管理内存,类型安全,不容易出错。
  • Swift 项目推荐用 CryptoKit。

3. Security.framework

  • 系统级安全框架,C 语言接口。
  • 支持:钥匙串、证书、RSA/ECC 密钥生成、数字签名、TLS。
  • 钥匙串操作的底层 API。

4. 第三方库

库 语言 说明
CryptoSwift Swift 纯 Swift 实现的加密库,支持多种算法
RNCryptor OC/Swift 封装好的 AES 加密库,处理了 IV、盐、密钥派生等细节
SSKeychain/SAMKeychain OC 钥匙串轻量封装
KeychainAccess Swift 钥匙串 Swift 封装,API 优雅
BCrypt OC/Swift bcrypt 密码哈希

九、Swift 版本对照(CryptoKit)

import CryptoKit

// MARK: - SHA256 哈希
func sha256(_ string: String) -> String {
    let data = Data(string.utf8)
    let hash = SHA256.hash(data: data)
    return hash.compactMap { String(format: "%02x", $0) }.joined()
}

// MARK: - HMAC
func hmacSHA256(message: String, key: String) -> String {
    let keyData = SymmetricKey(data: Data(key.utf8))
    let messageData = Data(message.utf8)
    let hmac = HMAC<SHA256>.authenticationCode(for: messageData, using: keyData)
    return Data(hmac).compactMap { String(format: "%02x", $0) }.joined()
}

// MARK: - AES-GCM 加密
func aesEncrypt(message: String, key: SymmetricKey) throws -> Data {
    let data = Data(message.utf8)
    let sealedBox = try AES.GCM.seal(data, using: key)
    // combined 包含 nonce + 密文 + 标签
    return sealedBox.combined!
}

func aesDecrypt(combinedData: Data, key: SymmetricKey) throws -> String {
    let sealedBox = try AES.GCM.SealedBox(combined: combinedData)
    let decryptedData = try AES.GCM.open(sealedBox, using: key)
    return String(data: decryptedData, encoding: .utf8)!
}

// MARK: - 钥匙串(KeychainAccess 库)
import KeychainAccess

let keychain = Keychain(service: "com.example.app")

// 存储
try keychain.set("password123", key: "user@example.com")

// 读取
let password = try keychain.get("user@example.com")

// 删除
try keychain.remove("user@example.com")

十、常见问题与坑

Q1:MD5 还能用吗?

答案:分场景:

  • ❌ 安全场景(密码存储、数字签名、防篡改):不要用 MD5,用 SHA256 及以上。MD5 已被证明有碰撞攻击。
  • ✅ 非安全场景(文件去重、秒传、简单校验):可以用 MD5,性能好,够用。

Q2:密码应该怎么存?

答案:

  1. 客户端通过 HTTPS 发送密码明文(HTTPS 通道已加密)。
  2. 服务端用慢哈希算法(bcrypt、scrypt、Argon2、PBKDF2)加盐哈希后存储。
  3. 绝对不要存明文,不要用 MD5/SHA 直接哈希(太快,容易暴力破解)。
  4. 客户端本地如果需要记住密码,用钥匙串存储。

Q3:AES 加密用什么模式?

答案:

  • 推荐 GCM(带认证,最安全)或 CBC(需要 IV + HMAC 认证)。
  • 绝对不要用 ECB 模式(相同明文产生相同密文,可被图案攻击)。
  • IV 必须随机且每次加密不同,不要用固定 IV。
  • 填充用 PKCS7。

Q4:钥匙串数据会被备份吗?

答案:默认情况下,iTunes/iCloud 备份会包含钥匙串数据,但钥匙串数据是加密的,只有在同一设备上恢复才能解密。如果开启了 iCloud Keychain,钥匙串数据会加密同步到 iCloud。

如果不希望钥匙串数据被备份,可以设置 kSecAttrAccessible 为 kSecAttrAccessibleThisDeviceOnly。

Q5:HTTPS 还需要应用层加密吗?

答案:看安全需求:

  • 普通 App:HTTPS 足够,不需要额外应用层加密。
  • 高安全需求(金融、医疗、企业):可以在 HTTPS 基础上再加应用层加密(如请求参数加密、响应加密、HMAC 签名),防御客户端被逆向、SSL Pinning 被绕过等风险。
  • 但应用层加密不能替代 HTTPS,HTTPS 是基础。

Q6:RSA 能加密大数据吗?

答案:不推荐。RSA 加密性能差,且加密数据长度有限制(2048 位密钥最多加密 245 字节数据)。

正确做法:

  1. 生成一个随机的对称密钥(AES 密钥)。
  2. 用 AES 加密大数据。
  3. 用 RSA 公钥加密 AES 密钥。
  4. 把加密后的 AES 密钥和 AES 密文一起发送。
  5. 接收方用 RSA 私钥解密得到 AES 密钥,再用 AES 解密数据。

这就是 HTTPS 的基本思路(非对称加密交换对称密钥,对称加密传输数据)。

Q7:加盐后还需要用慢哈希吗?

答案:需要。加盐只能防御彩虹表攻击,不能防御暴力破解。如果用 MD5/SHA 加盐,攻击者拿到盐后仍然可以每秒计算上亿次哈希进行暴力破解。

正确做法:加盐 + 慢哈希(bcrypt/scrypt/Argon2/PBKDF2),慢哈希算法故意设计得计算很慢(可配置迭代次数/内存),让暴力破解的成本变得不可接受。

Q8:自己实现加密算法可以吗?

答案:绝对不要。加密算法的实现有很多细节(侧信道攻击、填充预言攻击、随机数生成等),自己实现几乎肯定会有安全漏洞。用系统库(CommonCrypto/CryptoKit)或经过审计的成熟库。

密码学第一原则:不要自己造密码学轮子(Don't roll your own crypto)。

Q9:HTTPS 抓包能看到明文吗?

答案:

  • 正常情况下:HTTPS 数据是加密的,抓包工具只能看到密文。
  • 但如果用户在设备上安装了抓包工具的根证书并信任(如 Charles),且 App 没有做 SSL Pinning,抓包工具可以做中间人攻击,看到明文。
  • 防御:高安全 App 应该做 SSL Pinning(证书绑定),只信任指定的服务器证书,即使用户安装了恶意根证书也无法解密。

Q10:钥匙串存 token 和 NSUserDefaults 存 token 有什么区别?

对比 钥匙串 NSUserDefaults
存储方式 AES 加密,系统级安全 明文 plist
App 删除后 数据保留 数据删除
安全性 高(硬件级加密) 低(可被导出读取)
适合存储 密码、token、密钥 非敏感的用户偏好设置
跨 App 共享 支持(App Group) 不支持

token 虽然不是密码,但也是敏感信息(拿到 token 就能冒充用户),推荐存钥匙串。如果只是普通的非敏感设置(如主题、语言),用 NSUserDefaults。


十一、总结

  • 三大加密算法:
    • 非对称加密(RSA):公钥私钥配对,用于密钥交换和数字签名,不适合加密大数据。
    • 对称加密(AES):同一密钥加解密,性能好,用于大量数据加密;用 GCM 或 CBC 模式,不要用 ECB;IV 必须随机。
    • 哈希散列(MD5/SHA):不可逆摘要,用于密码存储、数据校验、数字签名;MD5/SHA1 已不安全,安全场景用 SHA256+;密码存储用慢哈希(bcrypt/Argon2)。
  • 网络传输安全:
    • 基础:必须用 HTTPS。
    • 密码:服务端用慢哈希加盐存储,不传明文。
    • 高安全:HMAC + 时间戳 + nonce 防重放防篡改。
  • 本地存储安全:
    • 敏感数据(密码、token、密钥)存钥匙串(系统级 AES 加密)。
    • 不要用 NSUserDefaults/plist 存敏感信息。
    • 大文件用数据保护(Data Protection)或 AES 加密。
  • MD5 的非安全用途:文件去重、秒传、简单校验(安全校验用 SHA256)。
  • iOS 加密框架:CommonCrypto(C 底层)、CryptoKit(iOS 13+ Swift 推荐)、Security.framework(钥匙串/证书)、第三方库(CryptoSwift、RNCryptor、SSKeychain)。
  • 核心原则:不要自己造加密轮子,用标准算法和成熟库;HTTPS 是基础,应用层加密是补充;密码必须用慢哈希加盐。

posted @ 2018-08-03 11:32  Mr.陳  阅读(1021)  评论(0)    收藏  举报