在这个人人都能玩科技的年代,数据安全显得较为重要。

初识

我们知道,为了保证用户的隐私数据如登录密码、银行卡账号等的安全,在提交用户的隐私数据时一定要使用 POST 请求来提交,这是因为:

  • GET 请求的所有参数都会直接暴露到 URL 中
  • 请求的 URL 一般都会记录在服务器的访问日志中
  • 服务器的访问日志是黑客攻击的重点对象之一

但是,仅仅用 POST 请求提交用户的隐私数据,并不能完全解决安全问题。通过 Charles 软件设置代理服务器,可以轻松拦截手机的请求数据。因此,在提交用户的隐私数据时,一定不可以明文提交,要经过加密处理(用加密算法)后提交。

常见的加密算法有:MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ RSA \ IDEA \ DSA \ AES。

一般公司都会有一套自己的加密方案,按照公司接口文档的规定去加密。

MD5

MD5 的全称是 Message Digest Algorithm 5,译为『消息摘要算法第5版』,它能够对输入信息生成唯一的 128 位散列值(32 个字符)。

MD5 的特点

  • 输入两个不同的明文不会得到相同的输出值
  • 根据输出值,不能得到原始的明文,即其过程不可逆(那些 MD5 解密网站是在它们的数据库中存有大量的明文和对应的 MD5,然后根据 MD5 找到对应的明文)

MD5的应用

  • 由于 MD5 加密算法具有较好的安全性,而且免费,因此该加密算法被广泛使用
  • 主要运用在数字签名、文件完整性验证以及口令加密等方面

MD5解密网站:http://www.cmd5.com

提交隐私数据的安全过程举例:

  • 注册:注册时,将密码 MD5 加密(或者一套规则)后提交到服务器,服务器将这 MD5 保存到数据库,这样,即使数据库数据被泄漏,他们得到也只是经过加密后的 MD5,得不到真正的密码。
  • 登录:登录时,还是将密码 MD5 加密(或者一套规则)后提交到服务器,服务器这 MD5 于数据库的 MD5 进行对比,如何一样,说明密码正确。

所以说,凡是能够『找回密码』的 App(或者网站之类的)应该是没有经过加密的,因为 MD5 是不可逆的,如果忘记密码只能通过修改密码来覆盖之前的密码。

但是,现在的 MD5 已不再是绝对安全(因为有一些 MD5 解密网站已经存有大量的数据),对此,可以对 MD5 稍作改进,以增加解密的难度,比如:

  • 加盐(Salt):在明文的固定位置插入随机串,然后再进行 MD5
  • 先加密,后乱序:先对明文进行MD5,然后对加密得到的 MD5 串的字符进行乱序
  • … …

总之宗旨就是:黑客就算攻破了数据库,也无法解密出正确的明文。

HTTPS

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版。即 HTTP 下加入 SSL(Secure Socket Layer),HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。

当客户端向服务器发起一个 HTTPS 请求时,服务器不会马上返回客户端所需要的响应数据,而是一个『包含公钥的受保护空间』(也称之为安全证书)返回给客户端,如果客户端同意安装此证书,那么就意味着以后客户端和服务器的数据交互将会多了一层:SSL(安全套接字层),相当于有了一个安全通道。当客户端再次发送请求的时候,公钥会将请求加密之后再发送给服务器,服务器接收到请求之后,用自带的私钥进行解密,如果正确再返回数据。

HTTP 和 HTTPS 对比:

HTTP

HTTPS

我们尝试使用 NSURLSession 发一个 HTTPS 请求:

1
2
3
4
5
6
7
- (void)viewDidLoad {
[super viewDidLoad];
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://www.github.com/"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
[task resume];
}

但是请求某一些 https 网站(比如自己公司搭建的)可能会请求不回数据,这是因为像 https://www.github.com、https://www.apple.com 这些大型网站可以强制让客户端同意证书,但是有一些网站的证书不是很安全或者有一些小问题的话,是需要客户端这边同意安装了才会返回数据的。

这个问题处理起来也是比较简单,就是要实现 NSURLSessionDataTaskDelegate 的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
- (void)viewDidLoad {
[super viewDidLoad];
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.github.com/"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}];
[task resume];
}
#pragma mark - <NSURLSessionTaskDelegate>
/**
* NSURLSessionDataDelegate 父类 NSURLSessionTaskDelegate 的方法
* challenge:挑战、质询
* completionHandler:通过调用这个 block,来告诉 NSURLSession 要不要接受这个证书
* NSURLSessionAuthChallengeDisposition:如何处理这个安全证书
* NSURLCredential:安全证书
*/
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
// 如果不是服务器信任类型的证书,直接返回
if (![challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) return;
// 根据服务器的信任信息创建证书对象
NSURLCredential *credential = challenge.proposedCredential;
// 或者
// NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
// 利用这个 block 说明要使用这个证书,这个三目运算符只是为了当这个 block 是空的话,就不调用了
!completionHandler ? : completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}