本文引用了简书做者“骑小猪看流星”技术文章“Cookie、Session、Token那点事儿”的部份内容,感谢原做者。php
众所周之,IM是个典型的快速数据流交换系统,当今主流IM系统(尤为移动端IM)的数据流交换方式都是Http短链接+TCP或UDP长链接来实现。Http短链接主要用于从服务器读取各类持久化信息:好比用户信息、聊天历史记录、好友列表等等,长链接则是用于实时的聊天消息或指令的接收和发送。html
做为IM系统中不可或缺的技术,Http短连的重要性无可替代,但Http做为传统互联网信息交换技术,一些典型的概念好比:Cookie、Session、Token,对于IM新手程序员来讲并不容易理解。鉴于Http短链接在IM系统中的重要性,如何正确地理解Cookie、Session、Token这样的东西,决定了您的技术方案可否找到最佳实践。本文将从基础上讲解这3者的原理、用途以及正确地应用场景。前端
题外话:本文讨论的使用Http短链接的话题可能并不适用于微信这样的IM,由于微信的短链接并不是使用Http标准协议实现,而是基于自研的Mars网络层框架再造了一套短链接机制,从而更适用于IM这种场景(更低延迟、更省流量、更好的弱网适应算法等),详情请见《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》。固然,Mars虽好,但不必定适合您的团队,由于定制的方案相较于标准通用方案来讲,没有强大的技术实力,仍是不太容易掌控的了的。程序员
一篇文章:《现代移动端网络短链接的优化手段总结:请求速度、弱网适应、安全保障》这篇文章详述了现今移动网络下http短链接的网络层技术问题,有助于更好地理解本文,有兴趣的话也推荐读一读。web
学习交流:redis
- 即时通信开发交流群:320837163[推荐]算法
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》数据库
(本文同步发布于:http://www.52im.net/thread-1525-1-1.html)express
▼ IM开发干货系列文章(本文是其第13篇):编程
《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》
《一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)》
《IM开发基础知识补课(一):正确理解前置HTTP SSO单点登录接口的原理》
《IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?》
若是您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。
Cookie 技术产生源于 HTTP 协议在互联网上的急速发展。随着互联网时代的策马奔腾,带宽等限制不存在了,人们须要更复杂的互联网交互活动,就必须同服务器保持活动状态(简称:保活)。因而,在浏览器发展初期,为了适应用户的需求技术上推出了各类保持 Web 浏览状态的手段,其中就包括了 Cookie 技术。Cookie 在计算机中是个存储在浏览器目录中的文本文件,当浏览器运行时,存储在 RAM 中发挥做用 (此种 Cookies 称做 Session Cookies),一旦用户从该网站或服务器退出,Cookie 可存储在用户本地的硬盘上 (此种 Cookies 称做 Persistent Cookies)。
Cookie 起源:1993 年,网景公司雇员 Lou Montulli 为了让用户在访问某网站时,进一步提升访问速度,同时也为了进一步实现我的化网络,发明了今天普遍使用的 Cookie。(因此,适当的偷懒也会促进人类计算机发展史的一小步~)
Cookie时效性:目前有些 Cookie 是临时的,有些则是持续的。临时的 Cookie 只在浏览器上保存一段规定的时间,一旦超过规定的时间,该 Cookie 就会被系统清除。
Cookie使用限制:Cookie 必须在 HTML 文件的内容输出以前设置;不一样的浏览器 (Netscape Navigator、Internet Explorer) 对 Cookie 的处理不一致,使用时必定要考虑;客户端用户若是设置禁止 Cookie,则 Cookie 不能创建。 而且在客户端,一个浏览器能建立的 Cookie 数量最多为 300 个,而且每一个不能超过 4KB,每一个 Web 站点能设置的 Cookie 总数不能超过 20 个。
执行流程:
A:首先,客户端会发送一个http请求到服务器端;
B: 服务器端接受客户端请求后,发送一个http响应到客户端,这个响应头,其中就包含Set-Cookie头部;
C:在客户端发起的第二次请求(注意:若是服务器须要咱们带上Cookie,咱们就须要在B步骤上面拿到这个Cookie而后做为请求头一块儿发起第二次请求),提供给了服务器端能够用来惟一标识客户端身份的信息。这时,服务器端也就能够判断客户端是否启用了cookies。尽管,用户可能在和应用程序交互的过程当中忽然禁用cookies的使用,可是,这个状况基本是不太可能发生的,因此能够不加以考虑,这在实践中也被证实是对的。
为了方便理解,能够先看下这张流程执行图加深概念:
那么,在浏览器上面的请求头和Cookie在那?下图给你们截取了其中一种:
众所周知,HTTP 是一个无状态协议,因此客户端每次发出请求时,下一次请求没法得知上一次请求所包含的状态数据,如何能把一个用户的状态数据关联起来呢?
好比在淘宝的某个页面中,你进行了登录操做。当你跳转到商品页时,服务端如何知道你是已经登录的状态?
Cookie 虽然很方便,可是使用 Cookie 有一个很大的弊端,Cookie 中的全部数据在客户端就能够被修改,数据很是容易被伪造,那么一些重要的数据就不能存放在 Cookie 中了,并且若是 Cookie 中数据字段太多会影响传输效率。为了解决这些问题,就产生了 Session,Session 中的数据是保留在服务器端的。
总之:Session是对于服务端来讲的,客户端是没有Session一说的。Session是服务器在和客户端创建链接时添加客户端链接标志,最终会在服务器软件(Apache、Tomcat、JBoss)转化为一个临时Cookie发送给给客户端,当客户端第一请求时服务器会检查是否携带了这个Session(临时Cookie),若是没有则会添加Session,若是有就拿出这个Session来作相关操做。
Session 的运做经过一个session_id来进行。session_id一般是存放在客户端的 Cookie 中,好比在 express 中(说的是Nodejs),默认是connect.sid这个字段,当请求到来时,服务端检查 Cookie 中保存的 session_id 并经过这个 session_id 与服务器端的 Session data 关联起来,进行数据的保存和修改。
这意思就是说,当你浏览一个网页时,服务端随机产生一个 1024 比特长的字符串,而后存在你 Cookie 中的connect.sid字段中。当你下次访问时,Cookie 会带有这个字符串,而后浏览器就知道你是上次访问过的某某某,而后从服务器的存储中取出上次记录在你身上的数据。因为字符串是随机产生的,并且位数足够多,因此也不担忧有人可以伪造。伪形成功的几率比坐在家里编程时被邻居家的狗忽然闯入并咬死的概率还低。
一个完整的Cookie+Session应用过程以下图所示:
Session 能够存放在:
1)内存;
2)Cookie自己;
3)redis 或 memcached 等缓存中;
4)数据库中。
线上来讲,缓存的方案比较常见,存数据库的话,查询效率相比前三者都过低,不推荐;Cookie Session 有安全性问题,下面会提到。
传统的身份验证方法从最先的Cookie到Session以及给Session Cookie作个加密,接下来咱们来看看Token认证。
诸如Ember,Angular,Backbone之类的Web前端框架类库正随着更加精细的Web应用而日益壮大。正因如此,服务器端的组建也正正在从传统的任务中解脱,转而变的更像API。API使得传统的前端和后端的概念解耦。开发者能够脱离前端,独立的开发后端,在测试上得到更大的便利。这种途径也使得一个移动应用和网页应用可使用相同的后端。
当使用一个API时,其中一个挑战就是认证(authentication)。在传统的web应用中,服务端成功的返回一个响应(response)依赖于两件事。一是,他经过一种存储机制保存了会话信息(Session)。每个会话都有它独特的信息(id),经常是一个长的,随机化的字符串,它被用来让将来的请求(Request)检索信息。其次,包含在响应头(Header)里面的信息使客户端保存了一个Cookie。服务器自动的在每一个子请求里面加上了会话ID,这使得服务器能够经过检索Session中的信息来辨别用户。这就是传统的web应用逃避HTTP面向无链接的方法(This is how traditional web applications get around the fact that HTTP is stateless)。
API应该被设计成无状态的(Stateless)。这意味着没有登录,注销的方法,也没有sessions,API的设计者一样也不能依赖Cookie,由于不能保证这些request是由浏览器所发出的。天然,咱们须要一个新的机制。Token这种东西就应运而生了。
token是用户身份的验证方式,咱们一般叫它:令牌。最简单的token组成:uid(用户惟一的身份标识)、time(当前时间的时间戳)、sign(签名,由token的前几位+盐以哈希算法压缩成必定长的十六进制字符串,能够防止恶意第三方拼接token请求服务器)。还能够把不变的参数也放进token,避免屡次查库。
咱们能够把Token想象成一个安全的护照。你在一个安全的前台验证你的身份(经过你的用户名和密码),若是你成功验证了本身,你就能够取得这个。当你走进大楼的时候(试图从调用API获取资源),你会被要求验证你的护照,而不是在前台从新验证。
简单来讲,就像下图这样:
Token的使用流程:
A:当用户首次登陆成功(注册也是一种能够适用的场景)以后, 服务器端就会生成一个 token 值,这个值,会在服务器保存token值(保存在数据库中),再将这个token值返回给客户端;
B:客户端拿到 token 值以后,进行本地保存。(SP存储是你们可以比较支持和易于理解操做的存储);
C:当客户端再次发送网络请求(通常不是登陆请求)的时候,就会将这个 token 值附带到参数中发送给服务器;
D:服务器接收到客户端的请求以后,会取出token值与保存在本地(数据库)中的token值作对比。
Token的身份认证逻辑:
对比一:若是两个 token 值相同, 说明用户登陆成功过!当前用户处于登陆状态!
对比二:若是没有这个 token 值, 则说明没有登陆成功;
对比三:若是 token 值不一样: 说明原来的登陆信息已经失效,让用户从新登陆。
咱们能够保存认证过的Token记录在服务器上,来添加一个附加的安全层,而后在每一步验证Token的时候验证这个记录(好比每次客户端请求API时检查这个Token的合法性)。这将会阻止第三方假装一个Token,也将会使得服务器能够失效一个Token。
1)cookie数据存放在客户的浏览器上,session数据放在服务器上;
2)cookie不是很安全,别人能够分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session;
3)session会在必定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie;
4)单个cookie保存的数据不能超过4K,不少浏览器都限制一个站点最多保存20个cookie。
因此我的建议:
将登录信息等重要信息存放为session;
其余信息若是须要保留,能够放在cookie中。
Session和 token并不矛盾,做为身份认证token安全性比Session好,由于每一个请求都有签名还能防止监听以及重放攻击,而Session就必须靠链路层来保障通信安全了。如上所说,若是你须要实现有状态的会话,仍然能够增长session来在服务器端保存一些状态
App一般用restful api跟server打交道。Rest是stateless的,也就是app不须要像browser那样用cookie来保存Session,所以用Session token来标示本身就够了,session/state由api server的逻辑处理。若是你的后端不是stateless的rest api,那么你可能须要在app里保存Session.能够在app里嵌入webkit,用一个隐藏的browser来管理cookie Session.
Session是一种HTTP存储机制,目的是为无状态的HTTP提供的持久机制。所谓Session认证只是简单的把User信息存储到Session里,由于SID的不可预测性,暂且认为是安全的。这是一种认证手段。而Token,若是指的是OAuth Token或相似的机制的话,提供的是 认证 和 受权 ,认证是针对用户,受权是针对App。其目的是让 某App有权利访问 某用户 的信息。这里的Token是惟一的。不能够转移到其它App上,也不能够转到其它 用户 上。转过来讲Session。Session只提供一种简单的认证,即有此SID,即认为有此User的所有权利。是须要严格保密的,这个数据应该只保存在站方,不该该共享给其它网站或者第三方App。因此简单来讲,若是你的用户数据可能须要和第三方共享,或者容许第三方调用API接口,用Token。若是永远只是本身的网站,本身的App,用什么就无所谓了。
Token就是令牌,好比你受权(登陆)一个程序时,他就是个依据,判断你是否已经受权该软件;cookie就是写在客户端的一个txt文件,里面包括你登陆信息之类的,这样你下次在登陆某个网站,就会自动调用cookie自动登陆用户名;session和cookie差很少,只是Session是写在服务器端的文件,也须要在客户端写入cookie文件,可是文件里是你的浏览器编号。Session的状态是存储在服务器端,客户端只有Session id;而Token的状态是存储在客户端。
[1] 有关IM安全的文章:
《即时通信安全篇(一):正确地理解和使用Android端加密算法》
《即时通信安全篇(四):实例分析Android中密钥硬编码的风险》
《即时通信安全篇(五):对称加密技术在Android平台上的应用实践》
《传输层安全协议SSL/TLS的Java平台实现简介和Demo演示》
《理论联系实际:一套典型的IM通讯协议设计详解(含安全层设计)》
《微信新一代通讯安全解决方案:基于TLS1.3的MMTLS详解》
《来自阿里OpenIM:打造安全可靠即时通信服务的技术实践分享》
《Web端即时通信安全:跨站点WebSocket劫持漏洞详解(含示例代码)》
>> 更多同类文章 ……
[2] 有关IM架构设计的文章:
《一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》
《IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?》
《IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议》
《IM开发基础知识补课(四):正确理解HTTP短链接中的Cookie、Session和Token》
>> 更多同类文章 ……
[3] IM开发综合文章:
《现代移动端网络短链接的优化手段总结:请求速度、弱网适应、安全保障》
《IM开发基础知识补课:正确理解前置HTTP SSO单点登录接口的原理》
《IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》
《开源IM工程“蘑菇街TeamTalk”的现状:一场虎头蛇尾的开源秀》
《QQ音乐团队分享:Android中的图片压缩技术详解(上篇)》
《QQ音乐团队分享:Android中的图片压缩技术详解(下篇)》
《腾讯原创分享(一):如何大幅提高移动网络下手机QQ的图片传输速度和成功率》
《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)》
《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》
《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》
《基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?》
>> 更多同类文章 ……
(本文同步发布于:http://www.52im.net/thread-1525-1-1.html)