HTTPS 学习

HTTPS 学习

运行 https server :

openssl 生成私钥和证书

生成 rsa 私钥 server.key

1
root@ubuntu:~/test# openssl genrsa -out server.key 2048

根据私钥生成 证书申请文件 server.csr

1
root@ubuntu:~/test# openssl req -new -key server.key -out server.csr

image-20220127234247621

指定给 wsl.com 这个域名颁发的证书

然后生成一个 CA 根证书(自签名x509 ):

用私钥对 证书申请进行签名,从而生成证书 server.crt

1
2
3
4
root@ubuntu:~/test# openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650
Signature ok
subject=C = CN, ST = Beijing, L = city, O = company, OU = section, CN = test, emailAddress = test@test.com
Getting Private key

有效期为 10年

**根证书可以直接用作 服务器证书 **

python https server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from http.server import HTTPServer, BaseHTTPRequestHandler
import ssl

class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
self.wfile.write(b'Hello, world!')

httpd = HTTPServer(('0.0.0.0', 4443), SimpleHTTPRequestHandler)

httpd.socket = ssl.wrap_socket (httpd.socket,
keyfile="server.key",
certfile='server.crt', server_side=True)

httpd.serve_forever()

然后访问:

1
2
inhann@ubuntu:~$ curl https://wsl.com:4443 --cacert /home/inhann/test/server.crt
Hello, world!

golang 的 https server:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"net/http"

"golang.org/x/net/http2"
)

type MyHandler struct {
}

func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world!")
}

func main() {
handler := MyHandler{}
server := http.Server{
Addr: "0.0.0.0:4443",
Handler: &handler,
}
http2.ConfigureServer(&server, &http2.Server{})
server.ListenAndServeTLS("server.crt", "server.key")
}

访问:

1
2
inhann@ubuntu:~$ curl https://wsl.com:4443 --cacert /home/inhann/test/server.crt
hello world!

也可以直接忽略:

1
2
inhann@ubuntu:~$ curl https://wsl.com:4443 -k
Hello, world!

使用 openssl 生成证书:

生成根证书:

首先生成 private key :

1
inhann@ubuntu:~/test$ openssl genrsa -out root.key 2048

然后生成一个 CA 证书请求:

1
inhann@ubuntu:~/test$ openssl req -new -key root.key -out root.csr

image-20220128213411064

可以全部都回车

然后自签名生成证书:

1
inhann@ubuntu:~/test$ openssl x509 -req -days 365 -in root.csr -signkey root.key -out root.crt

服务器证书生成:

生成 private key server.key

1
inhann@ubuntu:~/test$ openssl genrsa -out server.key 2048

生成 csr server.csr

1
inhann@ubuntu:~/test$ openssl req -new -key server.key -out server.csr

image-20220128214141261

作为服务器端,最重要的是 Common Name ,这个字段代表了 与服务器关联的 域名,或者是 IP

然后用根证书签发 服务端证书 server.crt

方法一

1
inhann@ubuntu:~/test$ openssl ca -in server.csr -out server.crt -cert root.crt -keyfile root.key

应对报错:

1
2
3
4
mkdir ./demoCA/newcerts -p
touch ./demoCA/index.txt
echo 01 > ./demoCA/serial

image-20220128215015305

方法二

也可以自签的形式,通过 -CA 等参数指定根证书:

1
inhann@ubuntu:~/test$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt -CA root.crt -CAkey root.key -CAcreateserial

实验:

跑一个 https server ,用 server.key 作为 rsa private key ,用 server.crt 作为 服务器证书

1
2
3
4
/home/inhann/test/https.py:12
12: httpd.socket = ssl.wrap_socket (httpd.socket,
13: keyfile="server.key",
14: certfile='server.crt', server_side=True)

可以指定用的根证书为 root.crt 然后访问:

1
2
inhann@ubuntu:~$ curl https://wsl.com:4443 --cacert /home/inhann/test/root.crt
Hello, world!

把根证书 root.crt 安装到浏览器 :

证书颁发机构这边,导入:

image-20220128232705973

可以看到 根证书被导入了:

image-20220128232746929

然后就可以直接 访问 https ,而不会被拦截了:

image-20220129003049173


https 的 加解密机制 ( Public Key Infrastructure , PKI ):

https 保证了 浏览器 和 web server 之间通信的保密性

both types of encryption are used. Asymmetric (public key) encryption is used first to establish the connection, which is then replaced with symmetric encryption (called the session) for the duration.

两种加密方式(对称、非对称)都会使用,非对称主要用于建立连接,对称用于数据的加密传输

以下是浏览器通过 https 和 web server 交互的具体过程:

  1. Your browser reaches out to the website server and requests a connection.

    首先,浏览器向 web server 发起建立连接的请求

  2. The server sends you its public key. It keeps its private key a secret.

    web server 上面保存着一对 public key 和 private key ,web server 把 public key 传给浏览器

  3. Your browser generates a third key called a session key.

    浏览器生成一个 session key ,这个key 是用于对称加密的

  4. The session key is encrypted by your computer using the public key you got from the server

    然后 浏览器把通过 public key 这个 session key 进行加密

  5. The encrypted session key is then shared with the server.

    加密后的 session key 被传输给 web server

  6. The server decrypts the session key that it received from you using the secret private key. Now both ends have the session key that your computer generated.

    web server 用 private key 进行解密,拿到 session key

  7. The public key encryption is terminated and replaced with symmetric encryption.

    public key encryption 此时就结束了,接下来都是对称加密

  8. Now you are in a session with the server using only symmetric encryption, and that’s how it remains until you leave the website.

    现在 server 和 浏览器的 交互都通过 对称加密进行

image-20220128135758193

只使用 一次 非对称加密的理由:

  1. 非对称加密是单向的。所有人都有 public key ,所以 web server 如果用 private key 对数据加密后传输,所有人都能截获然后解密。
  2. 非对称加密要更多算力。非对称加密用的 public key 非常长,处理起来很慢

数字签名:

数字签名生成:

首先对 message 进行摘要算法处理(md5 、sha),生成摘要,然后将 摘要 用 private key 加密,加密后的摘要就是 数字签名

用数字签名确保 message 的完整性和抗否认性:

message 和 数字签名一同到达,接受者 对message 进行 相同的摘要算法,生成摘要A,利用 public key 将数字签名的解密生成B。然后将A 和 B进行对比,看看是否相同,从而可以保证信息的完整性和抗否认性。

image-20220128143510408

域名对应网站的安全性检查:

服务器证书申请:

Certificate Authorities,又叫做 CA 机构,申请者将 身份信息 message 交给 CA 机构,CA 机构在 核实了 信息之后,将 message 进行摘要,然后用 CA private key 将 摘要进行加密,生成 数字签名

如果申请通过,一般申请者会拿到两个东西:

  1. rsa private key ( server.key )(或者其他的,非对称加密算法的 私钥)
  2. 服务端证书 ( server.crt )

服务端证书的内容,包括:

  1. 摘要 message 用的 哈希算法
  2. 生成 数字签名用的 非对称加密算法
  3. CA 机构的名称(颁发者)
  4. 数字证书的有效期
  5. 使用者(一般是一个域名)
  6. rsa public key
  7. 指纹,即 message 的 数字签名
  8. message 本身

image-20220128174428701

服务端证书(server.crt) 会从 web server 发送到浏览器,里面带着 rsa public key

而浏览器需要对 发过来的 服务端数字证书做 有效性验证:

首先判定收到的证书的颁布来源,然后根据颁布来源,在本地 证书库中,找到对应的 根证书(这些证书是浏览器预装的),进行验证:

image-20220128163954241

这些预装的 根端证书(root.crt) 的内容,和服务端数字证书的格式是一样的:

image-20220128180427679

不过这里的 公钥,是和 CA private key (root.key) 对应的 CA public key

验证有效性的方法:

对收到的 server.crt 的指纹部分(即数字签名),用对应的 CA public key 进行解密,然后对 server.crt 的 message 进行摘要,最后比对 二者的结果,如果相同,那就有效,否则收到的数字证书无效


burpsuite 使用 https :

下载 burpsuite 提供的证书,然后装到火狐浏览器上面,可以认为这是一个 根证书

image-20220128165708098

image-20220128165729078

image-20220128235131973

当 burpsuite 处理 https 的时候:

首先浏览器发送的 http 报文被传送到 burpsuite,burpsuite 也会检测到它接下来 要交互的是一个 https server

image-20220129003256093

这时候,浏览器并没有去请求 web server 的 服务器证书:

image-20220129001503163

当点击 forward 之后,burpsuite 会 去完成剩下的 https 请求,并且给浏览器发送个 特殊的、伪造的 服务器证书:

image-20220129001746385

因为已经在浏览器上面安装了 PortSwigger 根证书,因而可以成功通过有效性检测

burpsuite 拿到 response 之后,也会 加密后返回给 浏览器,从而使得浏览器正常拿到回显

参考资料:

https://tiptopsecurity.com/how-does-https-work-rsa-encryption-explained/

https://blog.anvileight.com/posts/simple-python-http-server/

https://www.jianshu.com/p/1de38a3f50f3

https://blog.csdn.net/cowbin2012/article/details/100134114

https://www.jianshu.com/p/c65fa3af1c01