在网络世界中,安全是一个很重要的问题,以往的HTTP请求已经不能承担这个安全任务,抓包工具一抓,你的所有网络请求全都曝光。当然,你可能会采用加密算法来加密数据,但是这仍然不够。

在移动端和服务器的通信过程中,有两种认证方式:token和session。

Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在数据库和内存中,而随着认证用户的增多,服务端的开销会明显增大。

扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

__CSRF: __因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!

基于token的鉴权机制
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

  • 用户使用用户名密码来请求服务器
  • 服务器进行验证用户的信息
  • 服务器通过验证发送给用户一个token
  • 客户端存储token,并在每次请求时附送上这个token值
  • 服务端验证token值,并返回数据

这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *

那么我们现在回到JWT的主题上。

JWT是啥?

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT长什么样?

JWT是由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHQiOjE0ODg1NTM3OTk5NzIsImlwIjoiMTkyLjE2OC4xMDIuMTk1IiwidGVsIjoiMTMxMjM0NTY3ODkiLCJ0eXBlIjoiMiIsImRldmljZSI6ImVjMGEwOWZhOWRiOTNjNDQ1Mzk1YzcyNmI2OTUyM2YzIiwiaWF0IjoxNDg4NTI0OTk5OTcyfQ.9rl2XwKIMnVCVVKv9GvhTify7P2xhxIITfaSX4tm_78

JWT的构成

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

Header

JWT的头部承载两部分信息:

声明类型,这里是JWT
声明加密的算法 通常直接使用 HMAC SHA256
完整的头部就像下面这样的JSON:

{
'typ': 'JWT',
'alg': 'HS256'
}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.

Playload

Token的第二部分是负载,它包含了claim, Claim是一些实体(通常指的用户)的状态和额外的元数据,有三种类型的claim: reserved , public 和 private .

  • Reserved claims: 这些claim是JWT预先定义的,在JWT中并不会强制使用它们,而是推荐使用,常用的有 iss(签发者) , exp(过期时间戳) , sub(面向的用户) , aud(接收方) , iat(签发时间) 。

  • Public claims:根据需要定义自己的字段,注意应该避免冲突

  • Private claims:这些是自定义的字段,可以用来在双方之间交换信息

负载使用的例子:

{
"sub": "",
"name": "John Doe",
"admin": true
}

上述的负载需要经过 Base64Url编码后作为JWT结构的第二部分。

Signature

创建签名需要使用编码后的header和payload以及一个秘钥,使用header中指定签名算法进行签名。例如如果希望使用HMAC SHA256算法,那么签名应该使用下列方式创建:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

签名用于验证消息的发送者以及消息是没有经过篡改的。

完整的JWT

JWT格式的输出是以 . 分隔的三段Base64编码,与SAML等基于XML的标准相比,JWT在HTTP和HTML环境中更容易传递。

下列的JWT展示了一个完整的JWT格式,它拼接了之前的Header, Payload以及秘钥签名:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJleHQiOjE0ODg1NTM3OTk5NzIsImlwIjoiMTkyLjE2OC4xMDIuMTk1IiwidGVsIjoiMTMxMjM0NTY3ODkiLCJ0eXBlIjoiMiIsImRldmljZSI6ImVjMGEwOWZhOWRiOTNjNDQ1Mzk1YzcyNmI2OTUyM2YzIiwiaWF0IjoxNDg4NTI0OTk5OTcyfQ.
9rl2XwKIMnVCVVKv9GvhTify7P2xhxIITfaSX4tm_78

如何应用

[AFHTTPSessionManager manager].requestSerializer setValue:JWTToken forHTTPHeaderField:@"token"];
在这次demo中我用的是AFN3.,Xcoede8。 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];//服务器返回的是字符串
NSMutableDictionary *para = [[NSMutableDictionary alloc] init];
[para setValue:userPhoneNumber forKey:@"ac_id"];//用户手机号
[para setValue:dToken forKey:@"token"];//UUID NSURLSessionDataTask *task = [self httpRequestWithMethod:@"POST" pathUrl:USER_GET_NEW_SESSION_ID_URL parameters:para success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { NSString *resonseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];//服务器给我们的是一个二进制流字符串,先将其转化成NSString NSString *decodeStr = [RSACode decryptString:resonseString publicKey:PUBLICKEY];//服务器给我的数据经过了RSA加密,这里用公钥进行解密
NSDictionary *dicObject = [RSACode dictionaryWithJsonString:decodeStr];//解密后得到的是一个字符串,将其转换成字典
NSMutableArray *resultJson = [dicObject objectForKey:@"result"]; [[NSUserDefaults standardUserDefaults] setValue:[[resultJson firstObject]objectForKey:@"jwtToken"] forKey:RME_DEVICE_JWT];//通过NSUserDefaults将token进行永久化存储
[self.requestSerializer setValue:[[resultJson firstObject]objectForKey:@"jwtToken"] forHTTPHeaderField:@"token"];//将token放到请求头 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { }];

上面讲完了JWT,接下来就是RSA加密。

RSA算法是目前最流行的公钥密码算法,它使用长度可以变化的密钥。RSA是第一个既能用于数据加密也能用于数字签名的算法。 RSA算法的原理如下: 1.随机选择两个大质数pqp不等于q,计算N=pq; 2.选择一个大于1小于N的自然数ee必须与(p-1)×(q-1)互素。 3.用公式计算出d:d×e = 1 (mod (p-1)×(q-1)) 。 4.销毁pq。 最终得到的Ne就是“公钥”,d就是“私钥”,发送方使用N去加密数据,接收方只有使用d才能解开数据内容。
RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的,而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上好几倍,这也是RSA最大的缺陷,因此它通常只能用于加密少量数据或者加密密钥。需要注意的是,RSA算法的安全性只是一种计算安全性,绝不是无条件的安全性,这是由它的理论基础决定的。因此,在实现RSA算法的过程中,每一步都应尽量从安全性方面考虑。

首先通过Mac终端生成公钥和私钥。

 
RSA公钥私钥.png

红线部分是需要输入的指令,生成的文件在当前目录下。

openssl
genrsa -out rsa_private_key.pem
pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt
rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem

生成了公钥和私钥之后,我们APP端只要持有公钥即可,私钥放于服务端。这样在和服务器进行通信的时候,敏感信息服务器可以用私钥将其加密,即使他人拿到数据也没有用。而我们传给服务器的数据,也可以通过公钥去加密,由于公钥加密的数据只有对应的私钥才能解开,而私钥只有服务器才持有,这样就保证了只有服务器才能解开加密。这样就会使我们和服务器的通信更加安全可靠。


  Session Token
状态存储位置 服务器存储所有的Session状态信息 每个客户端存储自己的token状态
扩展性 即使是分布式的布局方式,也需要到存储当前Session的服务器获取数据 任意一台服务器均可解析Token
分享 无法分享和授权给其他应用 可以很方便的分享和授权给其他应用,而且很安全,无法伪造
依赖性 通常需要借助Cookie来实现 没有依赖,加密方式安全就安全

链接:http://www.jianshu.com/p/08b85f749c86

iOS网络请求安全认证(JWT,RSA)的更多相关文章

  1. 【转载】一步一步搭建自己的iOS网络请求库

    一步一步搭建自己的iOS网络请求库(一) 大家好,我是LastDay,很久没有写博客了,这周会分享一个的HTTP请求库的编写经验. 简单的介绍 介绍一下,NSURLSession是iOS7中新的网络接 ...

  2. springmvc接口ios网络请求

    springmvc:   application/json;charset=utf-8的ios网络请求: 后台使用 @RequestBody注解参数接收:

  3. iOS 网络请求NSURLSession

    iOS 7 和 Mac OS X 10.9 Mavericks 中一个显著的变化就是对 Foundation URL 加载系统的彻底重构. 现在已经有人在深入苹果的网络层基础架构的地方做研究了,所以我 ...

  4. iOS网络请求-AFNetworking源码解析

    趁着端午节日,自己没有什么过多的安排,准备花4-5天左右,针对网络请求源码AFNetworking和YTKNetwork进行解析以及这两年多iOS实际开发经验(其实YTKNetwork也是对AFNet ...

  5. IOS 网络请求

    技术交流新QQ群:414971585 关于网络请求的重要性我想不用多说了吧.对于移动客户端来说,网络的重要性不言而喻.常见的网络请求有同步GET, 同步POST, 异步GET, 异步POST.今天来看 ...

  6. IOS 网络请求方式

    iOS开发中的网络请求   今天来说说关于iOS开发过程中的网络请求. 关于网络请求的重要性我想不用多说了吧.对于移动客户端来说,网络的重要性不言而喻.常见的网络请求有同步GET, 同步POST, 异 ...

  7. IOS网络请求框架AFNetworking和ASIHttpRequest对比

    ASI基于CFNetwork框架开发,而AFN基于NSURL. ASI更底层,请求使用创建CFHTTPMessageRef进行,使用NSOperationQueue进行管理,ASIHTTPReques ...

  8. iOS网络请求基础

    这篇是关于网络请求的,结合公司的实际情况编写,如果有不同意见欢迎留言共同讨论. iOS在9.0之后彻底放弃了NSURLConnection,现在已经改用了NSURLSession进行网络请求.一般现在 ...

  9. IOS网络请求之NSURLSession使用

    前言: 无论是Android还是ios都离不开与服务器交互,这就必须用到网络请求,记得在2013年做iOS的时候那时候用的ASIHTTPRequest框架,现在重新捡起iOS的时候ASIHTTPReq ...

随机推荐

  1. datatable 列名重新排序

    1. DataTable.Columns["MONEY"].SetOrdinal[4]; 2.dt = dt.DefaultView.ToTable(false, listarr. ...

  2. MySQL面试题之如何优化一条有问题的SQL语句?

    如何优化一条有问题的sql语句? 针对sql语句的优化.我们可以从如下几个角度去分析 回归到表的设计层面,数据类型选择是否合理 大表碎片的整理是否完善 表的统计信息,是不是准确的 审查表的执行计划,判 ...

  3. mybatis使用<choose> <when>

    一.需求 后台使用orcale数据库,mybatis做持久层,前台搜索功能,根据类型搜索,但是数据库中没有类型字段, 所以需要在where条件语句中进行判断,当type == x1 时和type == ...

  4. Git学习记录 力做全网最强入门教程

    目录 Git学习记录 力做全网最强入门教程 什么是GitHub? 什么是Git? Git的配置 Git的安装(只介绍windos操作系统下) Git的配置 至此我们的入门教程到此结束,更新中级教程要等 ...

  5. 为什么MySQL数据库索引选择使用B+树?

    在进一步分析为什么MySQL数据库索引选择使用B+树之前,我相信很多小伙伴对数据结构中的树还是有些许模糊的,因此我们由浅入深一步步探讨树的演进过程,在一步步引出B树以及为什么MySQL数据库索引选择使 ...

  6. lij IDEA项目包分层结构显示设置

    使用Intellij IDEA创建项目发现包没有分层,使用不方便. 可以点击右上角的设置,把红框选项的√去掉即可. 就会分层显示了,这就很舒服了.

  7. 1873 初中的算术(java大数)

    1873 初中的算术 1 秒 131,072 KB 10 分 2 级题   Noder现在上初三了,正在开始复习中考.他每天要计算型如 (a× a× a× ⋯× a) ...

  8. Signature Request Warnings & eth_sign学习

    https://consensys.zendesk.com/hc/en-us/articles/360004427792-Signature-Request-Warnings-eth-sign Met ...

  9. python3 练习题(多级菜单)

    '''多级菜单需求:1.现有省/市/县3级结构,要求程序启动后,允许用户可依次选择进入各子菜单2.可在任意一级菜单返回上一级3.可以在任意一级菜单退出程序所需新知识点: 列表/字典'''menu = ...

  10. OnlineJudgeServer运行

    我在这如下这两篇文章都说过青岛OJ相关的 OnlineJudgeFE之前端二次开发 青岛大学开源OJ平台搭建 今天我还是要来讲讲关于这个青岛OJ. 青岛OJ采用的是完全的前后端分离架构. Online ...