1.登录和授权

Cookie

起源:购物车

他的起源比较早,那个时候还不是IE,更不是现在的Chrome,是更早的Netscape(网景),而且那个时候浏览器的开发者,浏览器的公司他会去帮别人开发网站。当时是是什么情况?是有个电商网站希望有购物车这个功能,可是(购物车现在都是怎么做?不管是淘宝还是什么网站,他们的购物车都是存在服务器的)那个时候的开发商他不想在自己服务器上面存信息,你又没有买,我存什么呀,你存本地吧,但是本地怎么存呢?没这功能呀。他就去给他的开发人员说,给这个浏览器公司的人说, 你去给浏览器加这个功能吧, 你同时是浏览器的开发者,又是网站的开发者,那么这个时候你做这个事比较方便。然后浏览器开发者就说,可以,我给你做,然后他们就干脆一不做二不休,做了一个完整的功能,这个功能叫做Cookie。他就是用来记录购物车的,只不过因为服务器不想记,想让记到本地去,记到每一个添加购物车的电脑上。

工作机制:

他是在本地记录,那么本地记录一个服务器需要的信息,怎么做呢?大致就是,服务器需要你保存什么,本来是服务器自己保存对吧,改成客户端记录,服务器需要你保存什么,然后发过来,你把他保存到本地就可以了。
第一步,我在这个网站里面,我想往我的购物车里面加一个苹果,怎么加呢?我访问cart(购物车)这个接口,用post传过去一个数据,叫apple=1,就表示我要往我的购物车里面加一个apple,好,服务器就知道了。然后服务器处理完就会给我返回一个信息,好的(200 OK),同时会加一个header,这个header叫Set-Cookie:cart=“apple=1”(不是Cookie,是Set-Cookie。Cookie是客户端给服务器用的,而 Set-Cookie就是服务器给客户端用的,意思是你把这个cookie存下来吧),表示购物车里面有一个苹果。然后客户端就记下来了。好的,我知道了,我下次再访问shop.com的时候附加进去(这个shop.com就是服务器的请求地址,跟上面的请求是对应的,而且这个cookie存下来以后,他还有继续的自动机制,当你浏览器再次访问这个内容的时候,他的cookie会自动附加进去,这是自动的,由浏览器来实现的,网站开发者不需要关心,用户也不需要关心)

下次,我要加一个东西,比如我要加一个香蕉,我只要发过去我需要一个香蕉,同时将本地的这个cookie附加过去,而且这个cookie我不需要管,浏览器自动处理,服务器发消息的时候也不需要管,现在,我通过这个post告诉服务器要加一个香蕉,并且通过cookie告诉他我已经加了一个苹果,然后服务器就知道了,然后就返回消息告诉你记下来,记在本地。这个时候客户端自动更新这个东西。注意到没有,服务器什么都没记,他不管,但是客户端记了,但是依然不影响通讯。

这个时候如果他要结账,他不需要发其他内容,因为cookie会把他的购物车给带过去,然后服务器再把这东西返回来。这里有一个东西很浪费,我把购物车信息发给你,你再发给我,好浪费啊,真麻烦,既然你帮我处理,我自己处理不就完了吗?这是早期,js这个东西在早期还是很落后的,服务器帮你做一个事,而且他还会做一些额外的事情,帮你做验证啊,还有没有货这些,我只是把他传过去,然后传回来,但是这个工作还是要服务器做的,而且cookie是谁管理的?是服务器,每次修改都是服务器在做。客户端完全只是一个被动的机器。这个就是cookie设计这个机制的原因。就是服务器需要存什么,告诉他,客户端无条件的存下来,然后每次访问回去的时候,再把他带回去。说白了,cookie是一个机制,他是一个header,Set-Cookie是一个header,Cookie也是一个header,但是更确切地来说,cookie更是一个机制。

大致知道就可以,因为我们在工作中,在移动开发中用cookie用得非常少,前些年还用一用,现在都不用了。逐渐在抛弃,但是抛弃的不是cookie,而是抛弃使用cookie来做登录,用cookie来做认证。

作用:

会话管理:登录状态,购物车

那么我们怎么用cookie来管理登录状态呢?
首先,我向服务器发一个http请求,去login,我要登录,我把我的用户名和登录密码都添加过去了,服务器确认,他怎么确认?他会记录a(username)登录了,同时他会为这件事情创建一个会话,表示我现在在和某个客户端,或者说某个用户代理,我们在通信,他现在是一个什么状态,他也许是一个登录状态,也许是一个非登录状态,总之我们正在会话中,他会记录下来他的会话信息(session),比如他的id是123。他就会把这个东西给存下来,然后呢,把我的session id返回给我,服务器返回给客户端,session是一个名字,我可以叫session,可以叫metting都可以,他只是表示我和客户端之间交互了,然后他就会发回来,他也是通过set-cookie。他是通过服务端定的,客户端什么都不管,我只把他记下来。

然后客户端再次访问的时候,就会自动把这个session给移过去,然后服务器收到以后就会去对照,有没有一个session id=123的,一看,有,哦,原来他是username叫a的这个人,并且他现在是登录状态,好的,他要用户信息是吧?我给他,因为他已经登录了。然后就会正常地返回过来。这个是使用cookie来管理登录状态。

那么那个session,cookie里面是可以有多个的,现在我用sessionid来管理我的登录信息是吧,同时我虽然已经用session存了你的登录信息了,我还不想存你的购物车,没关系,你要添加一个apple对吧?跟刚才那个过程是一样的,你发一个apple=1过来,我给你返回一个cart=“apple=1”,你们你记下来,额,你可以记两个cookie,一个sessionid用来管理你的登录,一个cart来管理你的购物车,两个东西互相不干扰。cookie是可以记多个的。

个性化:用户偏好、主题

怎么用cookie来管理用户偏好呢?比如我现在有一个网站,叫shop.com,一个叫黑色主题,一个叫白色主题,我向服务器请求,请求完了以后,服务器给我返回一个client_id,他和session id是一样的,是一个标记,我把这个标记给你发过去,啪嗒贴脸上,然后每次你找我说话,我都会看见,你是做了那个标记的人。

下次你再跟我说,我想换个蓝色主题, 专门发一个请求去改变主题,服务器觉得可以,就返回ok,这是一个正常的返回,然后服务器就记住了,这个client_id=123的人喜欢蓝色主题,他帮你保存了。

http是无状态的,假如你不存这个123,你下次再访问另一个页面,那肯定还是给你默认主题,因为记不住你,我不知道你就是上次那个人。那么下次我再访问过来,这个cookie是会自动附加的,然后他访问的是另外一个页面,并不是原页面,也不是改变主题的页面,可是服务器就是知道我要给他蓝色主题,因为他是123.这个就是网站用来管理用户偏好,怎么帮我们记录。这是其中一种记录方式,使用cookie在用户端记录的。

分析用户行为:

分析用户行为,用户的追踪,这个在国外是比较有争议的,尤其是欧洲。我们在登录网址的时候,不知道你们注意到没有,尤其是一些国外的网站,国内的网站还不是很在意这个,因为跟法律有关跟当地法律有关,跟道德关系其实很小很小,一般都是跟法律有关,法律要求你必须这么干,或者就是民众的意识,你必须这么干这么干,你如果不这么干大家不用你网站了,那怎么办?做呗。分析用户行为,追踪用户行为,就是你能知道用户去了哪些网站,那么我们访问国外网站的时候,他在顶部或者底部跟你说,你现在访问的网站正在使用cookie对你进行行迹的追踪,这个对你是没有害处的,而且我们一定不会把你的消息给公开,只是我们自己来用的,请你理解。都会用这样的东西。我们看起来可能会觉得你怎么这么多余啊,你用就用呗,你还告诉我,让我不爽干嘛?但其实是这样的,在那些国家尤其是欧洲,你不通知用户,就使用cookie追踪用户是非法的,是会遭到惩罚的,比如巨额罚款,那么他们要做,就只有把他申明出来,用户点一个确定。都会点的,少数人不点,这个用户追踪是很有价值的。如果你真的那么在意的话那你别用了。没办法,我很想让你用,我很想赚你的钱,我只有不挣了。

说一下这个东西怎么工作的。我有一个客户端和服务器,我想向你请求一个数据,然后你返回的数据有点意思,在body里面返回一个图片的链接,从你这个链接可以定到那个图片去,而且是自动的。就好像在你的网站打开一个在线图片一样,但他有什么关键的地方?就下面图片标记的那个地方,他加了一个和图片本身无关的信息from=shop.com,我在访问shop.com对吧,他去另外一个网站(3rd-part.com),这个网站就是帮助记录用户行踪的网站,追踪用户信息,从来都不是从a网站记录a网站,从b网站记录b网站,永远都是有一个统一的站点,他去记录用户去各个站点的行迹,然后他做一个统计。然后让其他网站一起来用,一个网站只记录一个网站在当前,只记录用户在自己的行为是没用的。这个不叫用户追踪。都是有一个统一的网站去记。这个例子里面就是这个3rd-part.com,他去记录了这个用户在shop.com的行为,那么这个链接有什么效果,就是这个用户打开这个网站之后,自动地去显示一张图片,可能会是一张广告什么的,然后这个图片他会附加一个信息,这个信息跟图片显示无关。也就是我去shop.com去放这个图片,后面就是追这个,如果我去tabao.com就是追的tabao.com,他们显示的是同样的图片,但是对于第三方记录网站来说不一样,他就会记录下来,当前这个用户是从shop.com来的,他就会在他的数据里面加一条,加什么呢?这个用户他去过shop.com。

服务器返回这个信息,客户端就会记下来(client_id = 123),然后客户端就会访问这个图片,访问图片的时候就会自动往这个第三方发一个请求,你不发请求怎么显示图片吧?怎么把图片下载下来?那么就只能请求这个第三方,然后第三方(3rd-part.com)他就会记录,在他的数据库里面加一条,这个叫123的用户他来自shop.com,他就会增加这个用户记录,接下来,他会把图片显示给你,然后呢,也给你这么一个记录,会给一个针对第三方网站的一个id,这两个id可以不是同一个东西,他们名字也不一样,他们后面值也可以不一样,因为他们只是一个三方网站用来记录用户行踪的。如果接下来,这个用户去上另外一个网站,假如这个网站也捆绑了这个第三方的统计,那么他会有什么一个结果,他也会显示这个图片,然后这个第三方就会知道,这个用户已经来过了,之前是去过shop.com,现在来了taobao.com,我记录一下,这个用户喜欢shop.com和taobao.com,喜欢去这么两个网站。那么这个时候就对这个用户有一定的画像了。他去了两个网站,如果用户去的网站很多的话,虽然我不知道你具体是谁,但是我知道你是一个什么样的人,那么说明什么?说明要推广告了。比如我之前去了一个色情网站,然后我现在去一个电商网站,那么他就可能会推情趣用品。另外,想象的空间是非常大的,就是你拿到足够多的用户数据之后,你对这个用户的画像足够精确之后,他能推的广告非常多。其实这种追踪用户行为,都是为了什么?都是为了推广告,都是为了从你兜里拿钱。

说两个额外的东西

XSS(Cross-site scripting):HttpOnly

XSS跨站脚本攻击,攻击?攻击不只是我打你,我对你有人任何的侵犯行为都叫攻击。我们的js,我们的网页脚本,他可能会帮我们的网页去做一些很方便的事情,另外他也可以拿到他的cookie,去用cookie做一些很方便的事情。可是,他也有可能去做坏事,比如我们记录用户信息靠的是什么?靠得就是cookie,那么假如你的cookie存的不是购物车,存的不是什么喜好,而是登录信息,如果js是一个坏人写的,他会怎么做呢?他可能会拿到你本地的cookie,然后直接给发出去,他去访问一个地址,比如访问他们自己的网站的一个存cookie的地址,把这个cookie发过去了, 你都不知道,后台就做这件事了。你的cookie就这么泄漏了,你的登录信息就这么泄漏了。一个js,一个本地脚本去获取header信息多正常啊,非常正常。这就是为什么cookie这个东西他为什么危险。因为我们登录这个事,本来是不存在的,后来慢慢出了,就用cookie做吧,然后慢慢就有人利用这个漏洞去做坏事。我的一个脚本,拿到你的cookie,直接给发走了,连邮件都不用,直接访问一个网页,一个url就可以了。
他的应对政策有很多,其中一个就是在cookie这个header后面加上HttpOnly限制。
比如:Set-Cookie:sessionid=123;HttpOnly
他有什么效果?就是这个cookie你的本地脚本看不到,他只用于我们http的交换,只用于信息交换,本地脚本看不到,那么如果你是一个包含敏感信息,比如登录信息的cookie的话,那么你加这个东西去做限制。这都是后来被摸索出来的。

XSRF(Cross-site request forgery):Referer

跨站请求伪造,这个更加猥琐,也让我们有点想不到。他是什么呢?cookie是个自动机制,假如我现在访问一个网站,是个银行网站,然后我又去访问一个坏人的网站,我并不知道这个坏人网站,这个坏人在他的脚本里面加东西了,加什么呢?让我去访问一个地址,比如我使用图片的时候访问一个地址,访问地址的时候会附加一些别的操作,让我去访问银行,他就只管去试一试,我就赌你最近访问过银行,并且有cookie。
比如这么一个url:https://bank.com/transfer?amount=1000000&to=bad(假如有这么一个银行网站,去转钱接口,转一百万,转给谁?坏人)
就这么一个url,你访问过去,就把钱转给坏人了,不需要我登录,不需要我确认,为什么?因为有cookie,cookie是自动的,对吧?假如我之前去登录过这个网站,那么他只要暗中去访问这个网址,刷,我钱转走了。当然实际操作中会有各种各样的防范,银行方面也会做这方面的防范,浏览器他们也会互相配合做这些东西,只是这是一个搞坏事的原型。
那么解决方案,其中一点就是Referer这个header,Referer他的拼写是错的,Referrer(转发者)由于历史原因,就应该错着写才行。
用法:Referer:www.google.com
他就是用来显示你是从哪个网站跳转过来的。假如这个银行发现你这个url,你这个申请转账的url他是来自一个我不认识的网站,或者一个危险的网站,那么我拒绝对你转账。不过这种解决方案也有他的缺陷,你需要依赖浏览器,浏览器需要能给你做这个功能,假如浏览器不帮你做这个功能,我从a网站跳到b网站的时候,我不帮你自动加这个Referer这个header,那不就是瞎了吗。

不过说来说去就比较长了,这两个都是cookie比较危险的点。cookie危险的点很多,但是不是因为他不好,而是这个东西天生劣势,由于要获得什么什么好处,所以会有什么什么危险。cookie为什么被遗弃?并不是他被遗弃,而是不再用于授权。

2.Authorization

相比于cookie,Authorization就更加流行,而且越来越流行。
Authorization最常用的有两种:

Basic:

basic就是基本的授权方式,即使我们用的很少,但是也是很实用的。

Authorization:Basic<username:password(Base64ed)>

例子:
get /user http/1.1
host: xxxxxx.xxx
Authorization:Basic eGlhb21pbmc6cWl1bG9uZw==

比如现在我要做一个请求,我有一个header叫Authorization:Basic xxxx,这个就是认证信息,如果这个数据对了,那么我可以获取到用户信息,如果这个错了,用户信息就获取不到,他会跟我说你没有权限,你的权限不足。这是一个http请求,用法就是这样的,他用在header里面。

那么这个xxxx里面是什么内容呢?base64转化后的用户名和密码。
比如我的用户名和密码是xiaoming和qiulong,
合在一起就是:xiaoming:qiulong
转化后就是:eGlhb21pbmc6cWl1bG9uZw==
我这么请求数据服务器就会给我返回正确信息,这个就是basic,为什么叫basic,因为他是最基本的信息了,用户名密码都给我就完了。这个东西他有什么缺陷呢?他是有安全风险的,你这个东西万一被截获怎么办?不过其实,下面会讲到https。现在大多数网站,尤其是api,就是浏览器之外的,你的应用使用的时候已经全都是https了,那么安全就交给https,我真的可以把我的用户名和密码直接传过去,因为他们都会被加密的,看不到的。不过呢,他确实还有个安全缺陷,有一点点,就是假如你需要这么做,你就需要把经过base64转化的用户名和密码,或者是base64之前的,保存到本地,这样你下次再去请求才能够自动化这个东西。而不是要用户每次都输入用户名和密码,对吧?你换个页面就让用户输一次,用户不疯了吗?那么你把她存到你本地,不管是存到你电脑,还是存到你手机,假如你这个设备被人给Hacker了,比如你的手机你去获取了root权限,然后root权限你又把他给了某个软件,然后他就可以随便操作你手机了,他把你的东西盗走就是有可能的了。其实说回来,这种安全风险倒还好,其实他把自己的手机root权限获取到,本身就放弃了一定的安全性,对吧,手机被破解了你能怪这个机制不好吗?这是第一种,还是有些软件在用的,而且做得比较大比较重技术的公司也有在用这个的。所以本身在安全上是没问题的。刚才我说的安全风险相对来说还算好吧。设备被破解了才有风险,那叫什么风险呢。这是第一种,不过用的公司还是少一点。挺好用的,挺简单的。

Bearer:

Bearer(持票人),也就是拿着尚方宝剑的人, 你做事需要亮你的尚方宝剑。这种就叫做token,上面的basic长着token这种形式,但是并不能叫token, 你严格说起来也是,你把用户名密码揉起来base64一下也可以用作票根。不过Bearer才是真正的比较形象的token形式,本来我不是那个人,但是那个人给了我权限,那么我拿这个令牌,就可以用这个令牌去获取信息,去操作。这个是很常用的一种方式。他的格式是这个样子:

Authorization:Bearer<Bearer token>

前面也有个头Bearer,表示我这种认证用的不是basic,而是持票这种方式,后面把持票人的token填进来就可以了。而这个token他就不是某种算法得到的,而是需要找授权方给你,有的时候,你会使用github或者使用新浪微博,去给别的软甲授权的时候,并不需要你从这个网站跳过去登录一下,而是直接从你的账户信息里面,会有一个获取token,获取api token,你把这个token复制出来给某个软件就可以了。这是一种方式,token本身就可以拿出来给别人去用。另外一种是OAuth2.

OAuth2:

他是一种第三方认证的机制。OAuth我们现在都是用的2,1 是好几年前的,2和1差别不大,他们核心都是一样的,但是他做了一些工作,让开发者关心的事情更少,同时并不降低安全性。

OAuth2流程:第三方授权示例

首先去github-setting-application里面把掘金的授权回收,

然后现在去掘金点登录,选择三方github,他就会进入这样一个页面。谁是第三方?现在我是github的用户,并不是我是掘金的用户,现在我用github的时候我需要做一个第三方的授权,我要把我的一些权限授给别的网站,比如这个网站叫掘金,这个第三方是掘金,第三方是我从github跳到做认证的地方,这个地方可能会有点迷,额,我不是使用github来登录吗?第三方怎么成了掘金了?这里不是我要强调一些概念,而是你要搞清楚才能理解一些其他东西。记住,第三方是掘金,第一方和第二方是你和github。你要把信息授权给别的网站你要做这么一回事。

那么我要授权给第三方的时候,我现在点一个github登录,我就到了一个github页面了,是谁过来的?是掘金给我带过来的。看上面这个授权页面地址是github.com,而这个里面有一个关键信息,就是client_id,这个client_id是github授予给掘金的一个id,他什么时候授予的呢?掘金的开发者当初找github申请下来的。这个就是github他会对掘金有一个标记,那么这个标记有什么用处呢?他的用处就是当你打开这个页面的时候, 传入client_id,那么github就会自动把掘金的图标,以及这个掘金的名字,以及他需要哪些权限,还有下面这个url地址给你,然后用户看到这些的时候,他就会去判断,我现在需要授权的目标对象,到底是不是我以为的那个对象,因为有的时候网站会做伪造,会做劫持什么的,假如你没这个一步,他可能在授权过程中他给你换了。你以为你授权给掘金了,其实你授权给别的什么坏人网站了,那么坏人就要滥用你的信息了。这个client_id就这个作用,他用来做识别的。

那么接下来,我在github上点那个确定,授权给xitu,然后请求发送,页面消失,登录成功。
那么这一系列过程又发生了什么呢?
我点了之后,这个github就会跳回掘金的网站去,同时跳回去的时候会返回一个授权码(Authorization code)。Authorization code并不是一个token,为什么他不直接给token呢?有个很关键的原因,https这个过程他并不是被强制的,他在OAuth这个过程里面不是强制你要使用https,那么我这个过程可能被拦截了,可能被别人窃取了,窃取到之后,假如Authorization code就是最终的那个码的话,你别人窃取到之后不就可以使用这个权限了吗?还有什么呢?浏览器都是不可靠的,你不知道用户在用什么浏览器,你不知道用户在用什么操作系统,Authorization code传输到第三方以后,还是有可能泄漏。github只是给你一个code,code表示我的用户已经告诉我了,他确实愿意把权限授权给你(掘金),这个是一个证明,他愿意把权限授权给你,可是这并不是钥匙,他只是个证明,你拿这个code给我,跟我要用户数据,我不会给你,你还需要真正的授权的票据,那个token给我,那么token怎么获取?接下来继续说。

现在,我的浏览器已经获取到这个信息了,接下来他还要去找他的服务器,他会把这个code发送给服务器,通过http也好,通过https也好,这个东西不怕被窃取,他只是证明用户愿意授权。

然后,到了服务器以后,服务器就会跟github去做请求了。就是第三方的服务器会去向授权方的服务器请求。请求的时候他会附加授权的code以及一个叫client_secret的东西,这个client_secret是什么呢?他是在第三方,也就是掘金去github申请的时候跟client_id一起发过来的,这两个数据本身没有什么区别,只是他们在实际用处上有点区别,这个secret是绝对保密的,任何地方都不会看到,只有第三方的服务器拿着。这次链接也绝对是https链接,是个绝对安全的链接。那么现在,我有code证明用户愿意授权给我,又有client_secret证明我就是掘金。这个时候github就知道了,他给我足够的身份信息,并且这个信息来得足够安全,他不会被人截获,他通过https过来的,那么这个时候github就足够放心,他把真正的access token返回回去了。

这个时候Server拿到这个token,现在,这个OAuth2的流程已经结束了。他不需要把你的token发给客户端,不需要发给浏览器。用户把他在github上的一些权限授予了掘金,并且掘金已经拿到token了,接下来OAuth就不再参与了。接下来,比如你的Server调取信息,比如用户头像什么的。怎么做呢?Server去请求github.com,同时附加上这个token。怎么附加呢?
假设我的token是abccccc

这个过程是很安全的,但是由于一些事实的限制,或者是一些安全上的不在意,还有一种什么情况呢?Server会把这个token发给客户端,这个不是说不允许,只是他会对安全有一定的影响,就是别人把你这个token拿到了,他也可以去做事。

然后这么请求,也是可以的,很多软件也这么做。不过这么做,就把OAuth流程的好处给浪费掉了,你既然这样,那干脆在用户授权之后直接返回回来不就可以了吗?费这么多事干嘛呀?费这么多事不就是为了让别人截取不到吗?让你的浏览器被人黑掉,你的手机被人黑掉,你的网络被人黑掉都没关系。你的token依然是安全的,对吧?但是你这么做这些东西有一点白费了。但是这种用法还是有一定的使用的概率的,还是有些公司是这么用的。只不过他不太具有OAuth2的安全性。

第三方登录示例:微信登录

说到微信登录,我先说一下使用github登录,刚才我说使用github登录这个第三方授权,他的第三方是掘金。但是我要说,第三方登录这个事比第三方授权要来得晚一点,第三方登录他的第三方真的是github,你在掘金,使用第三方登录,他的第三方真的是github,由于第三方登录这个词的出现,他导致第三方授权这个概念非常非常含糊,非常非常让人难以理解。你应该能明白为什么吧?第三方授权是什么?本来是我跟github的信息,结果分享给你了,那掘金不是第三方吗?而第三方登录是什么呢?本来我要登录掘金的,但是我用了github,那第三方就是github。其实这个登录和授权都是很直观的东西,但是你要知道他们分别是谁,分别是谁不是为了考试,不是为了面试,但是你在思考问题的时候你会非常清晰。你把这些搞明白以后,你再看一些api文档什么的,你脑子会非常清晰,你会比谁都想得明白,这个是重点。

继续说微信登录,他是什么?他是一种第三方登录。比如你有一个手机软件,然后他里面有一个登录按钮, 你可以使用用户名登录,也可以使用第三方登录。比如你可以使用微信登录。那么有些人会做微信的开发,不管你有没有做过,我要说一下微信登录的手机流程是什么。

第一步,你会使用微信给你的api, 你通过这个api调用微信给你的接口,去打开微信的授权界面,那个授权界面叫微信登录。「你看授权登录,第三方授权和第三方登录真的是互相之间没法说。那个界面是微信对你进行第三方授权,微信对这个第三方(你的应用)授权,但其实他叫什么?他叫微信登录。」你点这个之后,微信就会把他的页面关闭,返回给你的软件一个Authorization code(授权码)。

为什么给你授权码?这是一个完整的OAuth2的流程,接下来,正规做法,就是你把这个code告诉你的服务器,然后你的服务器再拿你的这个code,以及你的secret去找微信的服务器,去要你的access token,拿到这个token之后,你们的客户端需要什么数据,你们服务器就去请求什么数据,比如你的客户端需要微信的用户名和他的头像,好,你的服务器就去拿,不是客户端拿。客户端不应该持有token,除非不得以。 就算是不得以,也不能持有secret,你去找微信服务器去拿token的这个过程,一定不能发生在客户端。

我知道有些公司在这么做的,有些公司就在这么做。他们的后端人员可能会推这个事,这个事不应该我们做呀, 你看微信api里面说的明明白白呀,要你去请求,你拿到那个code再去请求不就完了。你要secret吗?我给你呀,我们这存在有啊,你去吧。其实这个过程是不对的。你的客户端拿到code,code交给服务器,其实就完了。这个是为了安全考虑,不是为了省事考虑。如果是为了省事,根本就不需要OAuth了。直接用户同意之后,把token给你就完了。还要什么用code换token的过程啊?用code换token就因为你客户端获取了这个数据,未必足够安全。这个是微信登录。微信登录他是一个完整的OAuth过程。

在自家软件里面使用Bearer token

也是使用这种方式,比如我的软件,有个接口(api.xxx.com/login?username=qiulong&password=123),我输入这些信息,我的服务器就直接给我返回这个token(access_token=bdcj55s),当我再次使用的时候,我不需要附加其他信息,我只要附加(Authorization:Bearer bdcj55s),这就是下次我再请求的时候,我们的做法,这个过程他并没有OAuth的过程,他就是我前面说的做OAuth不要这么干的过程。我把用户名密码传过去,你直接把我要的那个token给我,我说的那个不安全的过程。他就是一个模仿了OAuth2的这种使用token的方式他的token的用法,但是他并不是一个OAuth2的过程。要知道这个并不是OAuth。很多人不懂OAuth2的原因就是这样的。就是有些api,他在用一个简化版本的OAuth2,你再去使用一些第三方OAuth2的过程你会发现,这怎么比我们公司麻烦这么多?好烦啊,他怎么还要code啊?其实是你们公司使用的是一个简化版的流程。你们自己登录自己的账户使用这种简化版是理所应当的,对吧?不然你还用code的话,你自己的Server拿着自己的code和自己的secret去找自己Server去换那个token,那不多此一举吗?
这种过程,他只是使用了Bearer token这种模式,但是他并不是OAuth2的过程。

refresh token

一个刷新的票根。

大概长这个样子。就是服务器返回的时候不只是access_token,还返回了一个refresh_token,他是什么呢?

这个过程中返回的不只是一个access token,还返回一个refresh_token,你的server可以使用refresh_token来找github.com,然后这个github.com就会返回这个新的access_token和一个新的refresh_token,然后之前那个老的access_token就失效了。或者你那个老的access_token在经过一段时间以后,比如七天,十五天后,他也会失效。你的assess_token会自动失效,或者会被refresh_token请求强制失效。那么这个过程是什么作用?他有什么意义呢?我本来有token你为什么要刷一下换一下呢?他其实就是为了安全,就是你的access_token不管怎么样,他还是有一定概率会丢掉的。那么你这个token丢掉之后,你要用户重新过来再认证一次,这就有点不现实,用户都很懒,用户每一个获取成本都很高,喂,你的token失效了,请你过来再认证一次。谁搭理你啊?对吧,这个用户可能就流失了。那么你怎么做,你为了安全你需要快速的把这个token给失效掉,然后你再获取一个新的 token,怎么获取?refresh_token。大致是下面这样的。

然后服务器就会给你返回一个新的token,并且同时把你那个旧的让他失效。这个是refresh_token,他是肯定要https的。他的流程跟获取token的流程他都应该尽量发生在服务端。

2.TCP/IP协议族

他是什么?
他是一大堆网络分层模型,并不是tcp、ip这么两个东西。
为什么要分层呢?
看一下这个模型,你从客户端到服务器可能会很多中间节点,这些节点之间可能绕来绕去的。按照一个完美的、理想化的模型,我怎么传呢?我只用http就够了。比如我要传一个什么报文,一条路传过去。那为什么要分层?分层,就是因为网络的不稳定。假如我在传输的路上,某个节点坏掉了,而不是整个瘫痪了,比如传的过程中,某个节点的路由器被人给炸掉了,那么我这个消息是不是丢了?接下来我需要把这个消息再发一次。通过别的路由器,比如通过下面的路由器传。那么我怎么知道这个东西没有收到呢?我可能有超时什么的,我会知道这个消息他传送失败,那么我再传一次,然后成功了。这是一种很常见的网络模型,不可能要求这个网络是绝对稳定的,比如停电了怎么办?网线插头被拔了怎么办?被踢掉了怎么办?各种问题,不可能稳定,因为网络不可能稳定。重传这个事是一定会发生的。这是百分之百的。但是提到重传就有另外一个问题了。我们的数据不一定是很小很小的。我要传一个大数据,我可能需要传很多次,可能我花了两秒钟才传完。这还是一个例子,实际过程中会出现各种各样的问题。那么网络就会很差很差。网络利用性,网速什么的都会影响,就是因为我们的网络不够稳定,而且数据可能会比较大。那就只有一个办法,那就是把你的东西切成块来传,本来你的东西很大是吧?我把他切成五块,然后这五快分别传,传起来就会比较方便。

比如我有一个数据叫abcdefghijklmnopqrst ,把他切成四块,然后做一个标记,这个时候我还是这么传,

我第一次传1,收到了,
第二次传2,收到了,
第三次传3,没收到,
第三次传4,收到了。
那么过一会我就会发现,怎么三号没给我回应啊?那么我再传一次3吧,传过去了。一共传了5次,大概多传了25%这么多。
如果我们把他们放到一起传,第一次可能直接失败,我再传一次,可能还会失败,那么分块就会把这个问题解决了。这个是分块传输他的好处。那么由于有分块传输,我就需要分层了。
因为上层应用层协议并不只http自己,还有别的,还有传文件的ftp,发邮件的smtp,他们都有这种需求,都有这种需求,我们做编程就知道,怎么做?把这个功能给抽出来,拿一个接口出来,抽出来一层,让这一层只做包的分发(紫色层),然后每次发消息的时候,我不管是发什么消息,不管是发正常的,还是更长的,更短的,我都在应用层切成块,发给分发层,你把他帮我传过去,哪一块丢失了,紫色的这一层会帮我们再传一次。紫色的这一层就叫TCP,TCP叫传输层,为什么我有http,还要拉一层来传呢?就是这个作用。他能够保证网络的稳定传输。

讲了两层了,讲了TCP为什么还要分层呢?你看我是分块的是吧?但是不是所有数据都需要重传的。比如你打游戏,你玩吃鸡,他有什么特点呢?你玩的时候,我的网络卡了,忽然我动不了了,然后我在两秒钟之后才恢复,那么我在卡的过程中,我的数据别人看不到是吧,发送方可能也知道数据没收到,但是,我有必要重传吗?不需要的,我现在网络断了,别人只需要知道我现在在哪?他没有必要知道这个过程我经历了什么。大家都需要最新的信息。这种需求还是比较常见的。吃鸡游戏就是其中一个例子。他们可能并不需要重传。你扔出去就不用管了。这种叫做UDP。我们的网络并不都是像tcp数据完整性要求这么严,但是他们都需要网络,都需要按照这个路上一步一步走过来,都需要这个主机找到那个主机去。那么这个功能怎么办?TCP怎么出现的?他有统一需求,多个应用层都有这个需求,那么抽出来,抽个TCP。那么tcp和udp都有这种网络的需求,怎么办?再抽一层。这一层又把网络传输往下降了。tcp我也不传了,我只是把功能抽一抽,他他切成四块,他第一块个下面,第二块给下面…新抽出来的这一层就只负责蒙头传。我甚至不知道你给我的这四块之间有连续关系,传到没?我不管。传的是啥?我不管。互相有联系没?我不管。我只负责帮你往目标地址去传。到了没?我也不管。这一层就是IP层,网络层。

那么到这个时候,整个网络结构,关系是怎么样的呢?http需要发东西是吧?他不传,告诉tcp我要传这个数据,快点给我传去;然后tcp说好的,tcp也不传,他把数据拆成块,给ip,请你给我传这块。都没有什么你先传后传的,不管。就跟他说你传这块,传那块,他tcp负责编号,负责看顺序,负责检测是否到了。然后传过去,一号,传到对面的ip层,往上移交,tcp收到以后,对ip层说,请帮我发这个消息回去,发什么呢?一个确认信息。然后左边tcp层会知道,一号到了。同时,未必是先后关系,这个二号传过去,然后也会确认。三号传过去往上交,可能三号收到失败,那么他就不会往回返。四号发过去,四号也收到了,然后左边tcp发现三号没到,然后再要ip层传一次,右边ip收到,交给tcp,tcp一看,这不三号吗?全了。之后,做两件事,第一,他会给左边tcp回复,你这三号也到了,同时他也会把这个整个拼装起来,告诉http, 你收到一个消息。这个时候,这个消息到达了。这三层他们的出现,都是因为网络的不稳定,如果网络稳定,你所有东西都能一次性到达,那么tcp、ip都不再需要。只要所有对象的应用层就足够了。另外,还有一层没有说,就下面的数据链路层。这个数据链路层就是我们实际的网络,比如我们的以太网,我们的wifi网络,以太网是什么呢?就是我们用网线连的这种网就叫以太网,因为咱们现在用的以太网已经是一种事实标准了,其实,你物理连线来做一个网络未必需要用以太网这种双绞线,你发明一个八绞线也可以,但是他已经成为一个事实标准了,所以看着我们就只有这一种物理网络一样,并不是的,什么叫以太网呢?用网线连的网就叫以太网。我们用的以太网、wif就是下面的数据链路层(LINK),他什么作用?他为我们网络提供现实世界中的支持。

这是tcp/ip他们的模型,tcp/ip族有四层模型,另外还有七层模型,七层模型因为过于复杂,在一些实际的讨论和讲授中可能会更加麻烦一点,那个把链路层也分两层,一个叫数据链路层,一个叫物理层,数据链路层是我们的以太网、wifi,物理层是我们的网线、交换机。其实四层这种分法很直接,很容易搞明白,不过很多人不理解就是因为没有搞清楚为什么要分层,就是因为网络不稳定。不然只有两层,一层是咱们的设备,一层是上面的应用,太好理解了,为什么有tcp、ip?因为网络不稳定。

为什么要tcp?因为我要拆包。
为什么要ip?有的时候我不需要确认,那么我把我的传输单独分一层,ip不是用来传数据的,真正传数据靠的是数据链路层。他是用来干什么?比如我要寻址,我要找路由器。
ip层怎么寻址呢?你可以看一些介绍,总之他会找出各种路由器之间的表,他会逐渐建立起一个越来越稳定的查询网络。

3.TCP连接

1.什么叫连接?

我们网络上,网线都连着,虽然中间有各种中间节点,什么路由器,网关这些,但是我们两个明明网线都连着的,那么什么叫连接?

连接是tcp的连接,tcp是一种有状态的交互,他是有状态的,http是无状态的,比如我在网上有个服务器,然后有很多主机都要访问我的服务器,他给我发消息的时候并不是,刷,扔过来,我就拿了。tcp有很多很多包,这些包他们需要拼,这个过程其实是需要先建立起来的,我们需要先建立一个互相沟通的确认方案,具体来说就是我的主机确认你要给我发消息了,那么我准备好接受了,你再给我发消息我知道怎么拼。同样的你也需要做这个确认,我们双方建立一个这样的确认的过程,就叫一个tcp链接建立的过程,当这个确认被确定了,就称作我们建立了一个链接了。

2.tcp连接的建立和关闭

建立:三次握手

客户端向服务端发一个消息(这个消息是tcp的消息,不是http的),“我想跟你通信”
“好的,我知道了,另外呢,我也要给你发消息了”
“好的,我知道你要跟我发了”

关闭:四次

为什么要关闭呢?我这个资源是很重要的,不管是电脑还是什么,我资源很重要,我要给你做这么一个确认,我等着给你发消息,他会占用我的电脑资源。当我们不需要通讯的时候,我就要关闭。什么叫关闭?就是我把你忘掉。
客户端:“我不给你发消息了”
服务器:“好的,我知道了”(但是他不会同时说我也不给你发了,原因很简单,他可能还有消息要发,等他消息发完以后,他会单独发一个消息)
服务器:“我不再给你发了”
客户端:“好的,我知道了”
这个时候他们的连接关闭了,连接关闭就表示双方已经把这个资源给释放了。

长连接:

什么叫长连接?

长连接就是我们不释放的连接。连接都是保持的,直到我关闭,直到我忘记。长连接就是我强制不让他关闭。
为什么要长连接呢?他是跟我们的网络有关的。
这是我们想象中的网络,

但是我们的电脑可能并不在公网上,而是在某个内网里面,比如我们的小区网关建了一个内网,然后我们的电脑是在这个网关里面,他并没有公网ip,跟下面一样。网关跟外界通信,我们要跟外界通信得先跟网关通信,然后他帮我们在上面开一个小口,然后这个小口去跟外界通信。这样就导致一个什么结果呢?我们的主机,他其实占用的端口是网关的端口,网关给我们开的端口。这是实际的网络有时候会出现内网。我们手机的网络就是运行在这样的网络里面的。我们手机网络全都是运行在内网里面的。都是某个运行商给我们建立的一个内网。这是我们运行的实际方式。

接下来说到长连接了,我们的手机他用了我们的运行商开的一个内网,而内网要给我们开这些端口,要耗费他的资源,那么他就会想着尽量省资源。省资源是什么方式呢?就是这个端口你不使用一段时间后,我就把他关闭了,那么这就导致,当我们手机上开着一个聊天软件,他通过服务器去连,这是正常的,可是,假如我们有一段时间没有发消息,这个服务器就觉得,他原来这个端口不用了,不需要通知服务器,服务器会检测,过段时间就关了。这个时候外界再想给我发消息,他依然是发到外界网关的端口上,他不知道我是否是在内网,他只是往这发消息,他发现发不动,因为服务器把这个端口给关了,服务器根本就不搭理他,那么这个网络就被切断了,他被限时切断。这就不行了,现实场景中,我们可能随时要接收服务器推送,或者是接收一些服务器的消息,那我五分钟不聊天你就让我再也聊不成,这…那就需要突破这个限制,去建立一个长连接。让这个端口不会被关闭。就是去欺骗你的网关,也就是使用心跳。

长连接实现方式:心跳

不管你本地是不是有消息发送给对方的对象,你每过一段时间,比如你每过一秒钟都发个消息,发个没有用的tcp消息。这个时候你的网关就会发现,这个端口一直在被占用,他就不会帮你关闭掉。这就是心跳包的本质。

了解这些东西的本质之后,去做具体的实现,做各种细节,或者在技术上做一些突破的时候,都会更加明白。我们android开发中用得很少,做长连接谁做呢?那些极光推送这些做推送的公司他们会做,这个技术非常难,很复杂,里面细节非常非常多,你需要对运行商对各种东西了解得非常细致。

4.HTTPS流程

s是安全的意思,https并不是一种单独的协议,http是一种协议,https不是一种单独的协议,他只是http建立在ssl上面。

1.定义

HTTP over SSL/TLS/Secure
SSL:Secure Socket Layer(早期)
TLS:Transport Layer Secure(现在)
都是同一个东西,都是建立在http下面的安全层,他实际就是把你的http消息在发送之前加密,收到之后解密。
他如果要分类的话,他是在http层的下面,tcp层的上面。相对更靠近应用层一点。

2.本质

在客户端和服务器之间协商出一个对称密钥,每次发送之前加密,收到之后解密,达到内容的加密传输。
先用非对称加密传输对称加密的密钥,然后用对称加密传输通信的内容。

3.为什么不直接用非对称加密?

因为非对称加密太慢了,数学上的原理导致他只能很慢。他计算很复杂。所以能用对称,就用对称。可是对称密钥又不能传,怎么办?我先用非对称式的把这个密钥给商讨好了,给确认了,双方都拿到了密钥,就用对称加密传输。这是在安全性和效率上做了一个整合。

4.流程

大致流程:

一,你的客户端去请求一个TLS连接,这个过程是通过tcp,不是通过http。
二,服务器把他的证书发给你。
三,客户端去验证这个服务器证书是不是真的。
四,验证通过,客户端信任服务器,和服务器协商对称密钥。
五,使用对称密钥开始通讯。 只有最后一步才是http通讯,前面都是tcp

具体过程:

1.首先我的客户端会跟服务器说,我要建立连接(Client Hello),发一个非常简单的消息告诉服务器我要建立连接。

同时客户端会附加一个信息,我可以用什么方式沟通,我可以接受的是TLS版本(因为TLS早期还有SSL,他们下层的加密方式都是有版本的),这个是一大堆,好几个,是一个序列,比如我支持TLS 1.0/1.1/1.2,我还支持SSL 3.0,我都给你发过去,你自己选。

同时还会发一个Cipher Suite(加密套件),实际上就是我可以接受的对称加密的方式和非对称加密的方式,以及hash算法。他是一个加密套件,为什么要附加hash算法呢?hash本身不能做加密,但是他会参与到加密过程,他是可以做验证的。

同时,还扔了一个随机数,这个随机数是稍后用来计算机密密钥的。

2.服务器说,好的(Server Hello)什么叫hello呢?他只是发了一个字节,比如client hello好像是1还是几。他是一个具体的字节。

同时,服务器收到之后就会挑,你支持的TLS有哪些,我选一个我最喜欢的,包括后面的算法。实际上后面的三个算法都是打包的,你只能选一组。服务器选好以后就会跟着Server Hello一起发回去。然后双方都持有这个东西。

同时,服务器也会附加一个他的随机数给到客户端,那么双方各有一个随机数。

3.接着服务器会附送一个东西,服务器证书
他发的证书的核心是他的公钥,他的非对称加密的公钥。

客户端需要对这个公钥做验证,因为前面这些都是明文的,他可能会被人截取,那么他需要验证,这个服务器到底是不是我所想访问的服务器,所以服务器发过来的不仅仅是一个公钥,而是一个证书,这个证书里面包含服务器的公钥。他还包含服务器的地址,也就是域名,然后客户端就会去验证这个域名比如我访问的是hencoder.com,我要确认你返回的信息到底是不是我要的信息,还有服务器名称之类的信息。那凭什么你说服务器地址是你的我就相信?我访问hencoder.com,然后中间有个什么坏人把消息给截取了,截完以后他给我发回有个证书,这个证书是属于hencoder.com的,那么我就信了吗?我肯定是不信的,我要是这么容易信了就太容易被人骇客了。所以这一步还是不够的,那么需要什么呢?他还需要提供一个能证明这个东西是真实的东西。他能够证明我的服务器信息是真实的。那需要什么呢?他需要提供一个签名。我能够验证这个签名对了,那么我就能够确认服务器发过来的信息确实是真实的。而且这个签名是对签名所有的信息签名的。所以服务器地址,公钥什么的都可以被证明。

我怎么去验证这个签名呢?服务器会给我发会这个证书签名方的信息,也就是证书机构。我拿着证书机构的公钥,可以对证书签名进行验证的话,可以证明这个服务器的信息确实是真实的。可是这个真实他是有前提的,就是蓝色部分的信息他确实是被黄色证书机构签名的,确实是被这个公钥的私钥持有者签名的。确实被这个公钥的主人签名的,到这你还是不能证明你就是真实的,不然我也造一个证书机构的公钥,证书机构的信息也是我造的,然后蓝色的证书信息也是我造的,都可以,我造一个公钥私钥对不就完了吗?
这个时候只能证明蓝色的信息是黄色的主人签发的。

这个时候还需要最后一步,也就是你的证书机构也需要提供证明信息。他需要提供他是被谁签的。他的签发方信息(循环了?),他的签发方信息,到此为止了。为什么到此为止呢?

我们点开一个https连接的网站,点这个锁,这个锁是他的签名相关的信息,是https相关的信息,然后我点这个证书。

选中部分就是蓝色,中间就是二级的签发机构,也就是黄色部分,最上面这个就是最里面的证书机构的签发方,就是根证书机构,叫做root证书机构,到这就结束了。那么我怎么知道根证书机构就是真的呢?万一这个也是假的怎么办?你给我嵌套三层就安全了?

根证书的认证可以找到可靠来源的。来自哪里?来自操作系统内部。我们的每一个操作系统,不管是ios、android、mac、windows,我们都能找到这个东西。我们电脑或者手机上都存有一个根证书列表。看我机器——钥匙串——系统根证书,然后找到上面网站同类的跟证书。我的系统里面有这个根证书,就可以证明他确实是被这个根证书签的。因为这个根证书里面是有他的公钥的。那么就可以证明黄色部分的证书机构信息确实是被根证书签名的。

那么还有一个问题?你这个根证书怎么就值得被信任呢?根证书是怎么来的?根证书是随着我们的操作系统一起被创进来的。这些根证书列表在当初操作系统被打包的时候,被发放的时候就已经存在了,他是被我们操作系统的研发方所验证了的。也就是微软官方,苹果官方,谷歌官方或者各种浏览器的官方,对这些机构进行了验证,然后把它放到了我们的操作系统,或者浏览器的根证书列表里面,他们的身份,他们的安全,是被浏览器或者操作系统所保证的。那么只要我们的操作系统不被干掉,我们浏览器不被干掉,这个东西就是安全的。

前些年不是有一个事情,就是支付宝要求用户安装根证书,然后这样就能保证安全,有这样一种说法,然后媒体说,其实这样很不安全。安全不安全我觉得还是安全的,因为支付宝他们没必要干这坏事,但是,我只是从事实上分析他不会干坏事,可是如果他想干坏事,我们是阻拦不了的。他想给什么机构去签发,他随便签。他签完这个机构就是安全的,这个网站就是安全的。

另外最近一段时间不是根证书机构直接被加黑名单了吗?其实这个东西怎么说呢?一个信任链总归是有一个地方是不需要任何证明,你需要无条件信任的。这是一个事实,不可能你有一个完整的,单纯靠证明的方式百分百证明他可靠的。总会有一个深处你需要无条件信任。那么我们的根证书列表就是需要我们无条件信任的地方。

回顾一下:证书就是这样子,我证书里面有我的服务器地址,你可以去验证,你验证可以得到我要访问的服务器确实是我要的对象,他确实是hencoder.com,而不是别人拿自己的合法证书来欺骗我,不是这样的,他一定是我的目标对象,然后我怎么保证他确实是真正合法性的呢?他有一个他的签发机构(黄色),你们这个签发机构怎么确认就是真的呢?这个签发机构会去指定他的签发方,而这个签发方他的公钥不是在这,而是在我的系统里面。在系统根证书里面。这个时候我的服务器验证就结束了。中间这个机构其实可以去掉,你直接让签发方给服务器签也行,但是现在大多数方案都是有一个中间机构的,因为根证书机构都很忙。这是服务器证书的验证过程。

4.接下来客户端拿到服务器公钥了,然后他就会去做这个加密过程中唯一一次非对称加密。他会使用这个公钥去加密一个信息,然后发给服务器去。加密什么呢?加密一个叫做Per-master Secret(准主秘密信息)的东西,他也是一个随机数,现在就有三个随机数,他们的名字不一样,他们的身份也不一样。Per-master Secret是通过唯一一次非对称加密传过去的。也是第一次加密。

5.现在双方拿到三个随机信息了。那么这个时候双方都拿到足够多的信息去生产他们的对称密钥了。

这个是标志性的一步,他把这个Per-master Secret发过去了,这个时候他们就可以去生产一个叫做Master Secret的东西,这个Master Secret将直接生产他们的密钥。他并不是密钥,因为密钥相关的东西有好几个。Per-master Secret会跟客户端随机数和服务端随机数三个东西一起来作用,通过一个算法,得到一个新的值,这个值叫做Master Secret。

那么这里有个问题,你为什么要拿那两个随机数去算呢?这到底有啥用呢?你在路上是明文传的,大家都能看见,你拿他们来算干啥用?这个就是跟安全有关的东西,他们从数学上考虑,虽然大家都能看见,但是我加上这两个确实能让我的密钥更安全。(这个知道就行)。

现在他们得到这个Master Secret,就可以用它去计算他们的密钥了。不过这个密钥是四个东西,实际上是6个,不过另外两个没有用。是什么呢?你的客户端加密密钥,服务端加密密钥,客户端做hash的key,服务端做hash的key,一共是四个。

为什么客户端和服务端用两个东西加密?
还是为了防贼,你给我发消息,我给你发消息,用不同的密钥,就能更安全一点。比如,我从客户端给服务器发了一个消息,别人截到他是看不懂,没关系我看不懂我给你捣乱,我不发给服务器,我原封不动地给你发回去,让你以为这是服务器给你响应的消息。那客户端就会觉得懵了,你给我发这个什么意思?而且能解压确实看着没问题。

什么是MAC Secret?
先说一下什么叫HMAC,MAC Secret就是HMAC的secret。
HMAC:Hash-based Message Authenticate Code
他是一个改良版的hash,他是怎么算的?
我们做md5,
MD5(a)=b
HMAC(a)=MD5(fun(a))=c
hmac里面具体做的事会复杂一点,他会对你的原消息加工之后再去做。他会对你的a做一些操作,来保证hash不容易被破解。其中一个重要的点是他往里面掺东西了,就像我们讲的那个hash他会加盐。这个盐只有通讯两方知道,其他人不知道。我的发送方知道,我的接受方也知道,其他人不知道。他们有什么区别呢?我能造出这个hash,其他人造不出这个hash,因为你没我的密码,没我那个Secret。我把这个hash做出来了,就能证明这确实是我发的消息。那么怎么验证呢?就是你有这消息,你是客户端你发消息了,我是服务端,我接收到这个消息以后,我也对这个消息进行有个HMAC,然后我得到这个HMAC,我可以去验证一下客户端连同这个消息一起发过来的HMAC,他们两个是不是一致。如果一致,我就可以确定消息确实是客户端发给我的。
加密密钥是用来加密,MAC Secret是用来验证身份的。
你看我们做非对称加密,你用公钥加密,私钥解密来加密,用私钥加密,公钥解密来做签名和验证。
而对称加密是用加密密钥来加密,用HMAC做签名和验证,相当于是一个签名和验证,实际上不是,但是他们的目的是一样的。都可以用来验证身份。这个Secret不是签名,只是一个用来验证身份的工具。

说这么多,这四个密钥就是用来加密和验证身份的。

5.这个时候客户端可以发加密消息了。这个时候他们需要验证一下加密算法到底能不能用。
客户端说:我要使用加密通讯了。

6.客户端发送:Finished
这个并不是这么一个字母,而且也不想上面的Clinet Hello是一个字节,这个是一大堆消息。他要把前面的内容全都包起来,然后使用加密密钥加密,用HMAC相当于签名的操作,进行一个hash,然后把整个信息发到服务器去。服务器收到以后,他会看一下这个东西是什么,然后我要验证这个签名是否合适。如果他既能看懂,而且签名也对,你们服务器对客户端就可以足够信任了。没有人骗我,没有人捣鬼。客户端是可以给我发消息的。

7.同样的,服务器接下来也会发。服务器说:我要使用加密通讯了。

8.服务器说:Finished,他发这个消息跟客户端那一大堆是比较相近的。只是他包的内容更多一点。然后发给客户端去,然后客户同样的验证方式。我要做一些HMAC。看看我做的HMAC跟你做的是不是同一个值。是的话证明你就是你。另外我要用你的加密密钥,看看这个结果是不是可用。这个时候证明我的加密也可用。

这个时候双方验证完全结束,这个时候客户端就会给服务器发https请求了。这是第一个https请求。然后他是长这个样子的。

从tcp来看,他写的就是这个东西,而从http根本无法解析,就是别人看来,他只知道这是tcp发的一个应用层的消息,但具体是什么我不知道。我甚至不知道这是不是一个http消息。因为他完全被https使用密钥加密了。同理,服务端收到以后,他能看懂,他回消息也是长这样子的。别人只能看到这样子,他连是不是http都不知道,完全看不懂,但他知道这是个tcp消息。因为加密是在tcp的上面加密的。所以你在tcp层面能够读懂。但是也就仅此而已了。

5.在android中的使用

一般正常使用就可以了。

有些时候会不行:
1.自签名证书,证书都挂在网站上的,怎么挂你不需要懂,就像你不需要知道怎么开发一个服务器。挂在网站上,有的时候这个证书他不会附加机构信息,就只放一个自己的公钥什么的就不管了,这是为什么?因为有的时候网页是自签名的。自签名就是你的客户端来验证你的消息,而不是用你的本地的根证书机构。那么这个一般都是用于内网。比如校园网什么的,他们会要求,每个同学请装上我们的证书。然后就可以访问内网了,就是这种工作方式。

2.证书信息不全。你证书没调好,也是有可能的,因为他们说复杂了太复杂,总之就是由于他们一些东西可以省略,所以他们就省略了,但是这个可以省略的内容没有可以从外部提供,完蛋,证书的机构信息缺了,就依然认为不可行。

3.手机操作系统比较旧。比如你用一个12年的操作系统,这些年一直没更新过根证书,然后来了一个比较新的证书机构,18年成立的,他签署的这些证书你的旧手机是无法看懂的,他认为你这个东西就是不合法,因为我系统里面的所有的根证书都没有对他进行签名,那么我认为你不合法。
怎么办?
自己写证书验证过程。google搜索android https。这个网站里面都有https://developer.android.com/training/articles/security-ssl?hl=zh-cn
。如果搞清楚了上面的内容,应该是可以看懂的。可能只是需要点时间而已。

android基础复习笔记——3.登录授权、TCP/IP、HTTPS原理相关推荐

  1. android基础复习笔记——5.从OkHttp的源码来看HTTP

    1.OkHttp的历史: 最初是square觉得android给的那一套方案不是很好用,于是他给做了一下包装,包装以后就好用了,慢慢地,他们把httpclient给剔除了,再后来,他被Google给收 ...

  2. android基础复习笔记——1.http的原理和工作机制

    1.先给个请求示例,大概长这个样子 2.你的url怎么转换成http报文? 协议类型:你是http协议还是ftp协议?这些都是应用层协议 为什么不合起来?暂时先不讲,讲完http的工作方式就知道了. ...

  3. Java基础复习笔记系列 九 网络编程

    Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...

  4. Java基础复习笔记系列 七 IO操作

    Java基础复习笔记系列之 IO操作 我们说的出入,都是站在程序的角度来说的.FileInputStream是读入数据.?????? 1.流是什么东西? 这章的理解的关键是:形象思维.一个管道插入了一 ...

  5. Android webview实现QQ一键登录授权

    Android webview实现QQ一键登录授权 最近公司要求的新需求,要实现webview中的的QQ登录,大脑没经过就习惯的百度,奈何找了两天的资料也没发现个完整的demo,只能自己写,好吧,还要 ...

  6. 【前端】HTML标签基础复习笔记

    不够完美又何妨?万物皆有裂隙,那是光进来的地方. 文章目录 HTML复习笔记 JavaWeb相关概述 HTML概述 HTML语法 基本标签 图片标签 链接 列表标签 块级标签 表格标签 表单标签 HT ...

  7. Android基础知识笔记

    ## Android基础面试题 (⭐⭐⭐) #### 1.什么是ANR 如何避免它? 答:在Android上,如果你的应用程序有一段时间响应不够灵敏,系统会向用户显示一个对话框,这个对话框称作应 用程 ...

  8. 多人网络游戏服务器开发基础学习笔记 II: 帧同步 | 游戏客户端预测原理分析 | FPS 游戏状态同步

    这篇是对书本 网络多人游戏架构与编程 的学习第二篇(第一篇:多人网络游戏服务器开发基础学习笔记 I:基本知识 | 游戏设计模式 | 网游服务器层次结构 | 游戏对象序列化 | 游戏 RPC 框架 | ...

  9. 【踩坑笔记】QtScrcpy 利用tcp/ip把手机投影到电脑上

    文章目录 目的: 准备 下载 编译 原因分析: 错误1 错误2 解决方案: 解决错误1 解决错误2 目的: 利用tcp/ip把手机投影到电脑上,不需要数据线连接,利用同一个局限网,实现无线连接. 我找 ...

  10. Python Web学习笔记之TCP/IP协议原理与介绍

    HTTP.FTP.SMTP.Telnet等等协议,哦!那个HTTP协议啊就是访问网页用的那个协议啊然后那个······其实······你懂得,我们应该从实际来了解他,理解网络协议的作用与功能,然后再从 ...

最新文章

  1. 人脸标记检测:ICCV2019论文解析
  2. 《数学之美》第6章 信息的度量和作用
  3. 高通软件发布版本简称
  4. java编译不了testpad,java – Gradle编译但不运行TestNG测试
  5. 【Oracle Database 12c新特性】ASM Scrubbing Disk Groups
  6. 素数路(prime)
  7. OpenCV中基本数据结构(8)_Complex
  8. 笨办法学 Python · 续 练习 48:`ed`
  9. css修改输入框的placeholder颜色
  10. 用firefox保存网页
  11. linux的mysql不允许连接_linux下允许mysql远程连接
  12. 转:李开复:打造领导力,我的九点思考
  13. nodejs--模块化、模块作用域、导出数据的几种方式、包、包管理、自定义包、模块加载机制
  14. 起底身份倒卖产业:那些被公开叫卖的人生
  15. 大道至简:透过现象看本质
  16. 聚合支付-x-pay
  17. html5 羽毛球,当上班族和羽毛球碰撞到一起,这样的生活才是标配
  18. stm32毕业设计 单片机遥控小车
  19. APISpace 让你快速获取名言警句
  20. 8086CPU相关汇编语言的简单概述

热门文章

  1. 【HAVENT原创】nginx 配置
  2. ubuntu内核版本回退,显卡驱动降级,重装显卡驱动和cuda,cudnn
  3. Idm在B站没有显示下载按钮
  4. Electron 键盘快捷键
  5. 谷歌浏览器无法调用java_怎么才能正常使用谷歌浏览器
  6. java矩形碰撞检测_JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【矩形情况】...
  7. 坚果云+Markor+Typora实现多平台Markdown协同编辑
  8. 为何现在只剩下 风吹乱我的发
  9. aliddns ipv6_利用阿里云ddns动态解析ipv6地址
  10. php新浪博客模板,supersite php模板