在网络世界中,安全是一个很重要的问题,以往的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": "1234567890","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.0,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 1024
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来实现 没有依赖,加密方式安全就安全

iOS网络请求安全(JWT,RSA)相关推荐

  1. 吕文翰 php,自己动手写一个 iOS 网络请求库(三)——降低耦合

    自己动手写一个 iOS 网络请求库(三)--降低耦合 2015-5-22 / 阅读数:16112 / 分类: iOS & Swift 本文中,我们将一起降低之前代码的耦合度,并使用适配器模式实 ...

  2. iOS网络请求安全认证(JWT,RSA)

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

  3. 最简单的iOS网络请求

    为什么80%的码农都做不了架构师?>>>    做iOS开发,说到网络请求,大家可能都不约而同的提到AFN,可以说大家的网络请求都是用AFN封装而成,AFN的强大易用的确很好. 但是 ...

  4. ios开发循环网络请求_GitHub - JadenTeng/ResourceX: iOS网络请求,网络泛型编程,工具类的封装,基于AFNetworking 实现, NSCache数据缓存...

    ResourceX 通过AFNetworking.YYModel 解析网络泛型编程简化网络请求 现如今,网络通信几乎涉及每一个app程序.对于绝大多数请求HTTP API的方法,它们的执行流程都可以分 ...

  5. iOS网络请求认证挑战

    一.引言 Http请求中认证挑战相关的代理如下: 1.将要发送一个认证挑战的请求 - connection:willSendRequestForAuthenticationChallenge: 2.是 ...

  6. iOS 网络请求劫持

    1.概述: NSURLProtocol是URL loading system 中的一个重要的组成部分,它允许我们对全局的网络请求(基于使用URLRequest)做拦截,可拦截的请求类型有NSURLCo ...

  7. iOS网络请求错误nw_proxy_resolver_create_parsed_array PAC evaluation error: NSURLErrorDomain: -1004

    在发起一个网络请求时,出现错误 nw_proxy_resolver_create_parsed_array PAC evaluation error: NSURLErrorDomain: -1004 ...

  8. iOS ---网络请求封装(自动缓存与手动缓存)

    #import <Foundation/Foundation.h> @interface WNetworkCache : NSObject /** *  手动写入/更新缓存 * *  @p ...

  9. php后台和ios网络请求,iOS网络 POST通过JSON传数据到后台

    后台php脚本代码 header('Content-Type:text/plain;charset=utf-8'); $json = file_get_contents('php://input'); ...

最新文章

  1. Windows自动启动程序的十大藏身之所
  2. require的key一个坑
  3. [vue] 你有写过自定义指令吗?自定义指令的生命周期(钩子函数)有哪些?
  4. [JVM]35个java代码性能优化总结
  5. python报错对象没有属性_属性错误:函数对象在python中没有属性
  6. Eclipse+Pydev环境搭建
  7. 软件系统安全测试和性能测试的区别,【安全测试】性能测试进阶——基本概念篇...
  8. 机器学习代码实战——网格搜索和交叉验证(GridSearchCV)
  9. LaTex 加粗(加黑)的方式
  10. MLOps- 吴恩达Andrew Ng Selecting and Training a Model Week2 论文等资料汇总
  11. PostgreSQL导入sql文件的方法
  12. 【刷题总结】二叉树前中后序遍历
  13. PDF转图片 Ghostscript.NET
  14. 强制卸载Edge(Chromium内核版本)
  15. Nginx安全配置手册
  16. gopher对mysql的利用_gopher协议的攻击利用
  17. linux 中meltdown指令,宇宙最强,meltdown论文中英文对照版(二)
  18. python-指数分布介绍(scipy.stats.expon)
  19. 鼠标滑过图片,图片抖动
  20. 在线进行立体几何画图——GeoGebra

热门文章

  1. 26.PhantomData幽灵数据.rs
  2. QT乱码总结7.编码测试和总结二
  3. PostgreSQL COPY 导入/导出数据
  4. 懒人chromium net android移植指南
  5. 消息中间件(Kafka/RabbitMQ)收录集
  6. 基于时序数据库做监控,这里有超流行的开源方案
  7. 网络编程套接字(三)
  8. LiveVideoStack音视频技术年度评奖启动
  9. 董海冰:2018风云再起 ,期待AV1、AI和AR
  10. Hadoop之NameNode和SecondaryNameNode工作机制详解