文章目录
一、构造HTTP请求
我们如何通过代码来构造HTTP请求呢?
主要有以下两种方式:
(1)基于HTML和JavaScript来构造。方式也分为以下两种:
- 基于form表单
- 基于Ajax
(2)基于Java
- 基于socket,注意,这个方案是完全可行的,但在实际开放中用的不如上面的方式多。
1.通过form表单构造HTTP请求
form (表单) 是 HTML 中的一个常用标签. 可以用于给服务器发送 GET 或者 POST 请求。
1.1.form 发送 GET 请求
form 的重要参数:
- action: 构造的 HTTP 请求的 URL 是什么.
- method: 构造的 HTTP 请求的 方法 是 GET 还是 POST (form 只支持 GET 和 POST)。这也是input 的重要参数。
- type: 表示输入框的类型. text 表示文本, password 表示密码, submit 表示提交按钮。
- name: 表示构造出的 HTTP 请求的 query string 的 key. query string 的 value 就是输入框的用户输入的内容。
- value: input 标签的值. 对于 type 为 submit 类型来说, value 就对应了按钮上显示的文本。
<form action="http://www.sogou.com/index.html" method="get"><!-- action表示把请求提交给哪个服务器 --><!-- method 表示是按照get来提交(参数放在query string)还是post来提交(参数放在body) --><!-- 这里method的取值,只能是get或者post,不区分大小写 --><input type="text" name="username"><input type="password" name="password"><input type="submit" value="提交"></form>
页面展示的效果:
在输入框随便填写数据:
点击 “提交”, 此时就会构造出 HTTP 请求并发送出去。我们打开Fiddler进行抓包。
我们画一个图来体会 form 代码和 HTTP 请求之间的对应关系。
- form 的 action 属性对应 HTTP 请求的 URL。
- form 的 method 属性对应 HTTP 请求的方法。
- input 的 name 属性对应 query string 的 key。
- input 的 内容 对应 query string 的 value。
当前上面这里是把我们这样的请求直接提交给搜狗主页了,搜狗的服务器中并没有处理我们传递的参数。
1.2.form 发送 POST 请求
这个时候,我们只需把 form 的 method 修改为 POST。
我们会发现,其实这里的效果是差不多的。
不过在这里,我们会发现传递的信息被放在body里面,
因此,小结区别:
- method 从 GET 变成了 POST
- 数据从 query string 移动到了 body 中
2.通过 ajax 构造 HTTP 请求
通过form表单来构造HTTP请求,实际上是一个更加原始的构造方式,因为使用form一定会涉及到“页面跳转",这是浏览器就需要加载出全新页面。但是这个事情就是非常的不科学了,尤其是页面非常复杂的时候。
随着前端页面越来越复杂,我们就希望,能够让页面不去整个全部加载,而是只加载其中需要变化的某个小部分,这个情况,就可以使用ajax了。通过js 代码,来构造出 HTTP请求。再通过js代码来处理这里的响应,并且把得到的一些数据给更新到页面上。通过 ajax的方式来构造的 HTTP 请求,功能更强大。
ajax 全称 Asynchronous Javascript And XML, 是 2005 年提出的一种 JavaScript, 给服务器发送 HTTP 请求的方式。特点是可以不需要刷新页面/页面跳转就能进行数据传输。在 JavaScript 中可以通过 ajax 的方式构造 HTTP 请求。
我们以前学过synchronized,知道这个单词是同步的意思,而这里的Asynchronous 就是异步的意思。
【注意】这里所说的同步和加锁里面说的同步非同一个东西,这是一个计算机术语,在不同的上下文中,表示的意思可能不相同。 下面,我们来介绍一下这两个概念。
2.1.异步与同步分别是什么
同步,就是说你的程序在执⾏某⼀个操作时⼀直等待直到操作完成。
最常见的例⼦就是 SendMessage。该函数发送⼀个消息给某个窗⼝,在对⽅处理完消息之前,这个函数不返回。当对⽅处理完毕以后,该函数才把消息处理函数所返回LRESULT值返回给调⽤者。
异步,就是说程序在执⾏某⼀个操作时,只是发出开始的指令;由另外的并⾏程序执⾏这段代码,当完成时再通知调⽤者。
当⼀个客户端通过调⽤ Connect函数发出⼀个连接请求后,调⽤者线程⽴刻可以朝下运⾏。当连接真正建⽴起来以后,socket底层会发送⼀个消息通知该对象。
举个例子:
追女生:
同步:他先给A⼥写了封信,然后发了出去。等了好⼏天 A⼥给他回了信,之后他才给B⼥写信。就是说等到⼀个任务返回或者结束,他才继续往下做他想做的任务。
异步:他先给A⼥写了封信,然后发了出去,马上⼜给B⼥写了封信 也发了出去。 就是说不⽤等到⼀个任务结束就去做下⼀个任务。
但是如果第⼀个任务需要第⼆个任务的返回值 那就得⽤同步让第⼀个任务等待第⼆个任务结束后,获取第⼆个任务的返回值,再继续往下做。
** 总结来说,同步和异步的区别:请求发出后,是否需要等待结果,才能继续执行其他操作。**
2.2.阻塞与非阻塞
阻塞和非阻塞是进程在访问数据的时候,数据是否准备就绪的一种处理方式,阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。
阻塞:当数据没有准备的时候阻塞,往往需要等待缓冲区中的数据准备好过后才处理其他的事情,否则一直等待在那里。
非阻塞:当我们的进程访问我们的数据缓冲区的时候,如果数据没有准备好则直接返回,不会等待。如果数据已经准备好,也直接返回。
阻塞调用:是指调用结果返回之前,当前线程被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用:是指在不能立即得到结果之前,该调用不会阻塞当前线程。
阻塞和非阻塞,区别是等的过程中,能不能干别的事情。
2.3.三种等待
同步阻塞等待、非阻塞等待、异步等待。
举个例子,比如说来到店里,让老板来个蛋炒饭。
- 同步阻塞等待:我就蹲在前台这里,盯着后厨来做饭,直到饭做好,我自己端走
- 同步非阻塞等待:我在前台这看一眼,发现饭没做好,我出去溜达一圈,过一会又来到前台这里看,发现饭还是没做好,我去玩会手机,经过若干次之后,发现饭好了,于是自己端走。
- 异步等待:我就直接啥都不管了,就找个角落左下,玩手机,该干啥干啥,等到饭好了之后,人家直接给我端上来了。
第二和第三两种方式,都是属于等的过程中可以干别的事情的。
区别就在于2种方式对于调用者来说开销要更大,需要反复去查询结果,第3种方式往往是更优的。
ajax就是属于基于异步等待的方式来进行的。
2.4.ajax构造HTTP请求
基本过程:
首先构造出一个HTTP请求,发给服务器,但是浏览器会不确定服务器啥时候才有响应,于是就先不管了。浏览器里面就继续执行其他代码.(该干啥干啥)等到服务器的响应回来了之后,再由浏览器通知咱们对应的JS代码,以回调函数的方式来处理响应。
基于jQuery中Ajax来进行操作。
(一)引入jQuery。
- 先在搜索引擎中搜索jquery cdn查询词。
- 在结果中,找一个合适的cdn的url
- 打开对应的url,加载出jquery本体。
- 复制占贴内容到本地文件 这里我们创建一个js文件,把上面内容复制放入其中。
不过,当我们打开这个网页,打开控制台之后,会发现这里有报错。
可是,我们通过Fiddler抓包却发现,这里是显示成功的。
那么,这里问题是出在哪呢?
答案就是浏览器禁止ajax进行跨域访问,跨域访问指的是跨越多个域名/多个服务器进行访问。我们当前页面处在的服务器,是本地文件,而页面中ajax请求的URL,域名是www.sogou.com,不属于本地文件,这样就触发了跨域操作。如果对方服务器返回的响应中带有相关的响应头,允许跨域操作,就是可以正常被浏览器显示的,如果没有,则不行。
因此,当下咱们构造的ajax请求是无法被正确处理的。那么啥时候才能正确处理?这就需要咱们自己有一个服务器,让页面和ajax的地址都是这一个服务器就行了。
二、HTTPS
1.HTTPS是什么
HTTPS (全称:Hyper Text Transfer Protocol over SecureSocket Layer),是以安全为目标的 HTTP 通道,在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性 。HTTPS在HTTP 的基础下加入SSL,HTTPS 的安全基础是 SSL,因此加密的详细内容就需要 SSL。 HTTPS 存在不同于 HTTP 的默认端口及一个加密/身份验证层(在 HTTP与 TCP 之间)。这个系统提供了身份验证与加密通讯方法。
简单来说, HTTPS就是HTTP的孪生兄弟,因为HTTPS是在 HTTP的基础之上,引入了一个加密层,这个加密的东西就是SSL,也叫做TLS(SSL是旧的教法,TLS是新的叫法)。
HTTP虽然使用极为广泛, 但是却存在不小的安全缺陷, 主要是其数据的明文传送和消息完整性检测的缺乏, 这就导致在传输过程中出现一些被篡改的情况。而这两点恰好是网络支付, 网络交易等新兴应用中安全方面最需要关注的。
2.运行商劫持
不知道大家有没听说过或者经历过“运营商劫持”这样的事情。
运营商劫持:
运营商是指那些提供宽带服务的ISP,包括三大运营商中国电信、中国移动、中国联通,还有一些小运营商,比如长城宽带、歌华有线宽带。运营商提供最最基础的网络服务,掌握着通往用户物理大门的钥匙,目前运营商劫持也很普遍,百度一下,可以发现有大量反馈反馈这个问题,各种广告弹窗,甚至还可能会窃取用户因素,令人憎恨。
网络运营商为了卖广告或者其他经济利益,有时候会直接劫持用户的访问,目前,运营商比较常见的作恶方式有两种,分别是DNS劫持、HTTP劫持。这里不细讲。
我们这里举一个网上的例子,图片也来源网上,来源不详。
如果我们下载一个天天动听,未被劫持的效果, 点击下载按钮, 就会弹出天天动听的下载链接。
如果是已被劫持的效果, 点击下载按钮, 就会弹出 QQ 浏览器的下载链接,下载的内容也变成了QQ浏览器了。
发生这种情况的原因:
由于我们通过网络传输的任何的数据包都会经过运营商的网络设备(路由器, 交换机等),那么运营商的网络设备就可以解析出你传输的数据内容, 并进行篡改。
点击 “下载按钮”, 其实就是在给服务器发送了一个 HTTP 请求, 获取到的 HTTP 响应其实就包含了该 APP的下载链接,运营商劫持之后, 就发现这个请求是要下载天天动听, 那么就自动的把交给用户的响应给篡改成 “QQ浏览器” 的下载地址了。
同学们,你们知道为啥运营商要进行劫持?
天下熙熙,皆为利来,天下攘攘,皆为利往。
实际上,不止运营商可以劫持,其他的 黑客 也可以用类似的手段进行劫持, 来窃取用户隐私信息, 或者篡改内容。在互联网上, 明文传输是比较危险的事情!!!HTTPS 就是在 HTTP 的基础上进行了加密, 进一步的来保证用户的信息安全。
3.“加密”与“解密”
加密就是把明文 (要传输的信息)进行一系列变换,生成密文 。
解密就是把 密文 再进行一系列变换,还原成明文 。
在这个加密和解密的过程中,往往需要一个或者多个中间的数据,辅助进行这个过程, 这样的数据称为密钥。
加密和解密这个事情, 本身是一个和数学密切相关的事情。我们这里只能简单讨论"流程",无法讨论加密解密的"实现细节"。
需要注意的是,加密之后,我们的数据也不是就绝对安全。只是说破解起来计算量很大,成本很高。有些数据经过加密之后,哪怕使用当前最强的计算机,破解起来也需要个几十年,上百年的,当破译的成本高于了数据本身的成本,这时我们就认为这个加密数据是安全的。
比如,有个犯罪团体做假钞,做一张假钞的成本是110元,而真钞的面值也才100,这时,就没必要去制作假钞了。
4.HTTPS 的工作过程
为了保证数据安全, 就需要进行 “加密”。网络传输中不再直接传输明文了,而是传输加密之后的 “密文”。加密的方式有很多,但是整体可以分成两大类:对称加密 和 非对称加密。
前面我们提过,我们HTTPS引入的加密层,称为SSL/TLS。在SSL里面,涉及到的加密操作,主要是两种方式:
- 对称加密:加密和解密的密钥使用的是同一个。
- 非对称加密:与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。
4.1.对称加密
对称加密其实就是通过同一个 “密钥” , 把明文加密成密文, 并且也能把密文解密成明文。
一个简单的对称加密, 按位异或。假设 明文 a = 1234, 密钥 key = 8888,则加密 a ^ key 得到的密文 b 为 9834。然后针对密文 9834 再次进行运算 b ^ key,得到的就是原来的明文 1234。对于字符串的对称加密也是同理, 每一个字符都可以表示成一个数字。当然,按位异或只是最简单的对称加密,HTTPS 中并不是使用按位异或。
引入对称加密之后, 即使数据被截获, 由于黑客不知道密钥是什么, 因此就无法进行解密, 也就不知道请求的真实内容是啥了。
在这里,客户端和服务器持有同一个密钥。客户端传输的数据(HTTP请求的header和body )都通过这个密钥进行对称加密,我们在网络上传输的实际上是密文,服务器收到密文之后,接下来就可以根据刚才的密钥,来进行解密,进而拿到明文。
但是上面的这个过程,看起来挺美好的,但是存在一个致命缺陷,你如何保证客户端和服务器,持有的是同一个密钥?尤其是一个服务器,对应很多很多客户端的时候。
我们的服务器同一时刻其实是给很多客户端提供服务的,这么多客户端, 每个人用的秘钥都必须是不同的,如果是相同那密钥就太容易扩散了, 黑客就也能很容易拿到,因此服务器就需要维护每个客户端和每个密钥之间的关联关系,如果每一个这样的关联关系都要维护,就会很麻烦。
这里的一个较好的解决方, 就是在客户端和服务器建立连接的时候, 双方协商确定这次的密钥是什么。
上面这个图里面,是假设客户端生成的密钥,客户端就需要把密钥通过网络告诉服务器,客户端生成了密钥888888,客户端就得告诉服务器,咋们的密钥是888888。
但是如果直接把密钥明文传输, 那么黑客也就能获得密钥了,此时后续的加密操作就形同虚设了。
因此密钥的传输也必须加密传输!但是要想对密钥进行对称加密 ,仍然需要先协商确定一个 “密钥的密钥”。这就成了 "先有鸡还是先有蛋"的问题了。 此时密钥的传输再用对称加密就行不通了,就需要引入非对称加密。
4.2.非对称加密
非对称加密要用到两个密钥, 一个叫做 “公钥”, 一个叫做 “私钥”。
- 公钥:人人都能获取到。
- 私钥:只有自己才知道。
公钥和私钥是配对的。但其最大的缺点就是运算速度非常慢,比对称加密要慢很多。
- 通过公钥对明文加密, 变成密文。
- 通过私钥对密文解密, 变成明文。
也可以反着用
- 通过私钥对明文加密, 变成密文。
- 通过公钥对密文解密, 变成明文。
举个例子,直观上理解公钥私钥:
很多小区,单元门口,有一个"信箱",你有一把钥匙,和很多把锁头。你把这些锁头发给送信小哥,每个送信的小哥都可以凭这个锁头,把信锁到你的信箱里,只有你自己持有着这把钥匙能够开箱,拿出信。此处锁头,就相当于公钥,你自己手里的钥匙,就是私钥。
基于非对称加密,就可以让服务器自己生成一对公钥和私钥,公钥发出去(人人都能拿到),私钥自己保存。客户端生成一个对称密钥,然后客户端就可以使用服务器的公钥,对对称密钥进行加密,然后把数据传给服务器。服务器再通过私钥进行解密。(如下图)
- 客户端在本地生成对称密钥, 通过公钥加密, 发送给服务器。
- 由于中间的网络设备没有私钥, 即使截获了数据, 也无法还原出内部的原文, 也就无法获取到对称密钥。
- 服务器通过私钥解密, 还原出客户端发送的对称密钥。并且使用这个对称密钥加密给客户端返回的响应数据。
- 后续客户端和服务器的通信都只用对称加密即可。由于该密钥只有客户端和服务器两个主机知道,其他主机/设备不知道密钥即使截获数据也没有意义。
思考:既然非对称加密这么好使,为何还要使用对称加密,直接使用非对称加密不就好了嘛?
答:实际在实现中,对称加密的计算开销远远小于非对称加密的,而且对称加密的效率比非对称加密高很多,因此只是在开始阶段协商密钥的时候使用非对称加密,后续的传输仍然使用对称加密。
上述过程看起来好像很完美了,实际上这里仍然存在一个非常巨大的漏洞——服务器把自己的公钥返回给客户端的这个操作中,可能会涉及到一个非常经典的“中间人攻击"。也就是说,
正常情况下,如下图:
非正常情况:在客户端、网络设备、服务器三者之间,
- 黑客入侵了网络设备,截取了客服端发过来的公钥,然后自己伪造一个公钥发送给服务器,从而获取到服务器发来的私钥。
- 由于客户端不知道接收到的公钥是黑客伪造了,也傻傻的返回了一个对称密钥密文。
- 然后黑客把这个对称密钥的密文返回服务器,服务器拿到这个密文之后,就可以顺利的解密了。
在这里面的整个过程,客户端和服务器都不知道有黑客这个第三者,已经获取到它们之间的信息。
那么,我们如何解决这个问题呢?也就是如何解决下面两个问题:
- 客户端如何获取到公钥?
- 客户端如何确定这个公钥不是黑客伪造的?
很简单,就是引入一个第三方认证。
4.3.引入证书
(这部分内容来源网络,具体来源不详)
在客户端和服务器刚一建立连接的时候, 服务器给客户端返回一个证书。这个证书包含了刚才的公钥, 也包含了网站的身份信息。
这个证书就好比人的身份证, 作为这个网站的身份标识.。搭建一个 HTTPS 网站要在CA机构先申请一个证书。就比如我们去公安局办理身份证。
这个 证书 可以理解成是一个结构化的字符串, 里面包含了以下信息:
- 证书发布机构
- 证书有效期
- 公钥
- 证书所有者
- 签名
- …
当客户端获取到这个证书之后, 会对证书进行校验(防止证书是伪造的):
- 判定证书的有效期是否过期;
- 判定证书的发布机构是否受信任(操作系统中已内置的受信任的证书发布机构);
- 验证证书是否被篡改: 从系统中拿到该证书发布机构的公钥, 对签名解密, 得到一个 hash 值(称为数据摘要), 设为 hash1. 然后计算整个证书的 hash 值, 设为 hash2. 对比 hash1 和 hash2 是否相等。如果相等, 则说明证书是没有被篡改过的。
我们可以查看浏览器的受信任证书发布机构。
(1)Chrome 浏览器, 点击右上角的 选择 “设置”, 搜索 “管理证书” , 即可看到以下界面。
(1)理解数据摘要 / 签名
以后我们参加工作后, 经常会涉及到 “报销” 的场景. 你拿着发票想报销, 需要领导批准. 但是领导又不能和你一起去找财务。那咋办?很简单, 领导给你签个字就行了。 财务见到领导的签字, “见字如见人”。
因为不同的人, “签名” 的差别会很大。使用签名就可以一定程度的区分某个特定的人。类似的, 针对一段数据(比如一个字符串), 也可以通过一些特定的算法, 对这个字符串生成一个 “签名”,并保证不同的数据, 生成的 “签名” 差别很大。
这样使用这样的签名就可以一定程度的区分不同的数据。常见的生成签名的算法有: MD5 和 SHA 系列
以 MD5 为例, 我们不需要研究具体的计算签名的过程, 只需要了解 MD5 的特点:
- 定长: 无论多长的字符串, 计算出来的 MD5 值都是固定长度 (16字节版本或者32字节版本)
- 分散: 源字符串只要改变一点点, 最终得到的 MD5 值都会差别很大,
- 不可逆: 通过源字符串生成 MD5 很容易, 但是通过 MD5 还原成原串理论上是不可能的。
正因为 MD5 有这样的特性, 我们可以认为如果两个字符串的 MD5 值相同, 则认为这两个字符串相同。
(2)理解判定证书篡改的过程: (这个过程就好比判定这个身份证是不是伪造的身份证)。
- 假设我们的证书只是一个简单的字符串 hello, 对这个字符串计算hash值(比如md5), 结果为BC4B2A76B9719D91
- 如果 hello 中有任意的字符被篡改了, 比如变成了 hella, 那么计算的 md5 值就会变化很大,BDBD6F9CF51F2FD8
- 然后我们可以把这个字符串 hello 和 哈希值 BC4B2A76B9719D91 从服务器返回给客户端, 此时客户端如何验证 hello 是否是被篡改过?那么就只要计算 hello 的哈希值, 看看是不是 BC4B2A76B9719D91 即可。
但是还有个问题, 如果黑客把 hello 篡改了, 同时也把哈希值重新计算下, 客户端就分辨不出来了呀。
所以被传输的哈希值不能传输明文, 需要传输密文。这个哈希值在服务器端通过另外一个私钥加密(这个私钥是申请证书的时候, 证书发布机构给服务器的, 不是客户端和服务器传输对称密钥的私钥)。
然后客户端通过操作系统里已经存的了的证书发布机构的公钥进行解密, 还原出原始的哈希值, 再进行校验。
下面是一个完整过程:
左侧都是客户端做的事情, 右侧都是服务器做的事情
5.小结
HTTPS 工作过程中涉及到的密钥有三组:
- 第一组(非对称加密): 用于校验证书是否被篡改。服务器持有私钥(私钥在注册证书时获得),客户端持有公钥(操作系统包含了可信任的 CA 认证机构有哪些, 同时持有对应的公钥)。服务器使用这个私钥对证书的 签名进行加密。 客户端通过这个公钥解密获取到证书的签名, 从而校验证书内容是否是篡改过。
- 第二组(非对称加密): 用于协商生成对称加密的密钥。服务器生成这组 私钥-公钥 对, 然后通过证书把公钥传递给客户端。然后客户端用这个公钥给生成的对称加密的密钥加密, 传输给服务器, 服务器通过私钥解密获取到对称加密密钥。
- 第三组(对称加密): 客户端和服务器后续传输的数据都通过这个对称密钥加密解密。
- 其实一切的关键都是围绕这个对称加密的密钥,其他的机制都是辅助这个密钥工作的。
- 第二组非对称加密的密钥是为了让客户端把这个对称密钥传给服务器。
- 第一组非对称加密的密钥是为了让客户端拿到第二组非对称加密的公钥。
本文完!
版权归原作者 十叶知秋 所有, 如有侵权,请联系我们删除。