137.https是否能够发送http的请求
也许你也曾碰见这种问题,在一个https的网页里面,出于某些原因,想要发送http协议的请求.
一、问题的答案:https是否能够发送http请求
首先这种https混杂着http的情况叫做:混合内容.
- 主动混合内容不可以(与页面交互的部分,下载的JS、iframe、样式表、flash和代码等,例如:用script标签引入http的js链接,script本身会加载链接的内容)
- 被动混合内容可以(图片、视频、音频内容,例子:用img标签引入http的js链接,img本身是不可交互的,仅供展示)
未来随着浏览器的升级,可以预见被动混合内容也将不被允许发请求。因为这样是不安全的。
Chrome81,消灭混合内容,消灭https发http请求的情况
查阅书籍。
todo.
二、原因
原因显而易见,为了安全。
http为什么不安全
http为什么不安全?
现象:
- 1、无限wifi攻击,http的传输是明文,截获了就什么都知道了
- 2、垃圾广告攻击
原因:
- 1、http的传输是明文,需要加密
- 2、无法验证身份;只要请求正确,就给返回,返回的还是明文。给了中间人空间
- 3、数据易篡改,因为传输要跳节点,某个节点可能被安插广告
继续查阅书籍。
todo.
三、案例(会Node可尝试,语言:Node.js,服务器框架:Express)
a.服务端和客户端各有一对公钥和私钥,使用公钥加密的数据只能用私钥解密,建立https传输之前,客户端和服务端互换公钥。
b.客户端发送数据前使用服务端公钥加密,服务端接收到数据后使用私钥解密,反之亦如此。
c.然后如果只是用 公钥 + 私钥,还会遇见一个中间人攻击的问题(简单点说,用户点进了骗子网站,比如一个仿淘宝的网站,就能很容易地获取到用户的淘宝账号、密码;现在的指纹登录从某种程度上也防止了这种攻击)。所以有一个签名证书,来确保服务端发给客户端的公钥是来自服务端,服务端可信任。
通过 a 和 b,解决了上面的http不安全的原因1-传输明文。
通过 c的认证,解决了上面的http不安全的原因2-中间人攻击,让钓鱼网站,模仿了真正的服务端也没用,它无法使用认证机构的私钥进行签名。(确保服务端正确)
3.1.让我们先开一个https的服务器
-
3.1.1 安装openssl,然后进入安装目录下的bin目录
-
3.1.2 使用openssl生成公钥和私钥
// 生成服务器端私钥 $ openssl genrsa -out server.key 1024 //生成服务端公钥 $ openssl rsa -in server.key -pubout -out server.pem
-
3.1.3 认证公钥
//生成CA私钥 $ openssl genrsa -out ca.key 1024 //生成csr文件 $ openssl req -new -key ca.key -out ca.csr //生成自签名证书 $ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt //生成server.csr文件 $ openssl req -new -key server.key -out server.csr //生成带有ca签名的证书 $ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
-
3.1.4 使用Express开启我们的https服务器
const express = require('express') const fs = require('fs') const app = express() const https = require('https') // 对比普通的http const http = require('http') // 这里放https的配置文件,如果这里没有配置项的话,https页面会报:【此网页无法提供安全连接】 const option = { // 公钥 key: fs.readFileSync('./key/server.key'), // 证书 cert: fs.readFileSync('./key/server.crt') } // 静态文件资源服务器,将网页挂在这里,然后用网页发起主动 http 请求、被动 http 请求 // 这是为了方便我们测试的 app.use(express.static('public')) app.get('/', (req, res, next) => { res.send('hello, world') }) const httpsServer = https.createServer(option, app) const httpServer = http.createServer(option, app) httpsServer.listen(443) httpServer.listen(3000)
然后我们创建一个 public 文件夹,在里面创建一个 test.html,之后分别打开我们的端口:
A:https://localhost:443/test.html
B:http://localhost:3000/test.html
test.html内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- jquery的https-cdn,是合法的请求 --> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script> <!-- jquery的http --> <script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script> </head> <body> <header>我是hh.html</header> <img src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js" alt=""> </body> </html>
3.2.我们主动、被动地发同一个http请求
地址:https://localhost:443/test.html
打开Chrome浏览器,输入地址,按F12,查看Network:
错误信息
Mixed Content: The page at 'https://localhost/test.html' was loaded over HTTPS, but requested an insecure script 'http://libs.baidu.com/jquery/2.1.1/jquery.min.js'. This request has been blocked; the content must be served over HTTPS.
完整截图:
从结果上看,https页面的Network只报了一个http请求错误。
从代码上看,我们两处使用了http的请求
3.3.总结答案
https通常无法发送http的请求。
会被浏览器阻止。
出于安全考虑。
图片的链接、视频的链接、音频的链接等被动请求是特殊情况。
未来也许连特殊情况也不会存在。
todo.