https双向认证

https双向认证,第1张

一、最简单的https
# https.go
package main

import (
	"fmt"
	"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi, This is an example of https service in golang!")
}

func main() {
	http.HandleFunc("/", handler)
	err := http.ListenAndServeTLS(":9090", "server.crt","server.key", nil)
	fmt.Println(err)
}

测试方法:curl curl -k https://127.0.0.1:9090
这个https只是进行了链路加密,并没有进行用户认证,更别说双向认证了。
结合这种链路加密,再加上http协议的basic认证,也能达到用户名密码认证的效果
//验证方法 $ curl -k -v -s --user admin:111111 https://127.0.0.1:9090
package main

import (
	"encoding/base64"
	"fmt"
	"io"
	"net/http"
	"strings"
)

func HelloServer(w http.ResponseWriter, req *http.Request) {
	auth := req.Header.Get("Authorization")
	if auth == "" {
		w.Header().Set("WWW-Authenticate", `Basic realm="Dotcoo User Login"`)
		w.WriteHeader(http.StatusUnauthorized)
		return
	}
	fmt.Println(auth) //Basic YWRtaW46MTExMTEx
	auths := strings.Split(auth," ")
	authMethod := auths[0]
	authB64 := auths[1]
	switch authMethod {
	case "Basic":
		authbyte, err := base64.StdEncoding.DecodeString(authB64)
		if err != nil {
			fmt.Println(err)
			io.WriteString(w, "Unauthorized!\n")
			return
		}
		authstr := string(authbyte) //admin:111111
		fmt.Println(authstr)
		userPwd := strings.Split(authstr, ":")
		username := userPwd[0]
		password := userPwd[1]
		fmt.Println("Username:", username)
		fmt.Println("Password:", password)
		fmt.Println()
	default:
		fmt.Println("error")
		return
	}
	io.WriteString(w, "hello, world!\n")
}
func main() {
	http.HandleFunc("/", HelloServer)
	err := http.ListenAndServeTLS(":9090", "server.crt",
		"server.key", nil)
	fmt.Println(err)
}

二、双向认证的https,即客户端要验证服务端的证书是否合法,服务端也要验证客户端的证书是否合法

证书是什么? 我们知道非对称密码中,用户A有一个私钥和一个公钥,私钥加密后的信息,只有用公钥才可以解密,同理,公钥加密后的信息,只能用私钥才可以打开。

你拿到了A的公钥,就可以和A进行安全通讯,也可以确保对方就是A。问题是,如何确认这个就是A的公钥,而不是其他人伪造的呢? 通过线下U盘拷贝,可以确保这一点。但显然不太方便,比如A目前米国,我需要去米国把这个公钥拷贝回来。

证书,就是签了名的公钥。谁签名,你才会放心?全球有几家顶级CA认证中心,他们是可信的,他们签名或授权二级CA签名,就是可信的。

他们是收费的,那我们就自己建立一个CA认证中心吧。

1、生成私钥文件(这个文件中应该包含了公钥文件。 git自带了openssl,比较方便)
openssl genrsa -out server.key 1024
2、生成证书草稿
openssl req -new -key server.key -out server.csr

3、进行证书签名
3.1 openssl ca -in server.csr -out server.crt -days 365

打印下面的错误,说没有CA的私钥
Using configuration from C:/Program Files (x86)/Git/mingw32/ssl/openssl.cnf
Error opening CA private key ./demoCA/private/cakey.pem
868:error:02001003:system library:fopen:No such process:bss_file.c:398:fopen('./demoCA/private/cakey.pem','rb')

3.2 我们自己做CA,做自己的私钥
创建./demoCA/private/目录
openssl genrsa -out cakey.pem 2048

3.3 继续签名
openssl ca -in server.csr -out server.crt -days 3650
缺少CA的证书
Using configuration from C:/Program Files (x86)/Git/mingw32/ssl/openssl.cnf
Error opening CA certificate ./demoCA/cacert.pem
9592:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('./demoCA/cacert.pem','rb')

3.4 自己给自己做一个自签名的证书
openssl req -new -x509 -key cakey.pem -out cacert.pem -days 365

3.5 继续签名
openssl ca -in server.csr -out server.crt -days 3650
缺少目录 --自己新建目录
./demoCA/newcerts: No such file or directory
Using configuration from C:/Program Files (x86)/Git/mingw32/ssl/openssl.cnf
I am unable to access the ./demoCA/newcerts directory

3.6 继续签名 
openssl ca -in server.csr -out server.crt -days 3650
缺少这个文件  --新建一个空文件,必须是0字节
./demoCA/index.txt: No such file or directory
Using configuration from C:/Program Files (x86)/Git/mingw32/ssl/openssl.cnf
unable to open './demoCA/index.txt'
10864:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('./demoCA/index.txt','rb')

另外,还需要这个文件 echo "01" > serial  //为证书生成序列号

3.7 好,最终签名成功了。
 注意,做证书时,要求填写 国家,省份,城市,公司,部门,用户名
 第一次时,CA的国家和用户的国家不一致,导致签名失败。最后都写成 cn
 另外,用户肯定也不可以相同。

下面改造一下程序,做双向认证

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net/http"
)
type myhandler struct {
}
func (h *myhandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hi, This is an example of http service in golang!\n")
}

func main(){
	pool := x509.NewCertPool()
	caCrt, err := ioutil.ReadFile("demoCA/cacert.pem") //这里之前server.crt写错了
	if err != nil {
		fmt.Println("ReadFile err:", err)
		return
	}
	pool.AppendCertsFromPEM(caCrt)

	//初始化一个server 实例。
	s := &http.Server{
		//设置宿主机的ip地址,并且端口号为8081
		Addr:    ":8081",
		Handler: &myhandler{},
		TLSConfig: &tls.Config{
			ClientCAs:  pool,
			ClientAuth: tls.RequireAndVerifyClientCert,
		},
	}
	err2 := s.ListenAndServeTLS("server.crt", "server.key")
	fmt.Println(err2)
}

第一次测试:curl -k https://127.0.0.1:8081
curl: (35) error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate 

服务端打印 2021/03/21 16:30:39 http: TLS handshake error from 127.0.0.1:61503: tls: client didn't provide a certificate

说明现在服务端要求客户端必须提供证书。

第二次测试:curl -k https://127.0.0.1:8081 --cert server.crt --key server.key
 Hi, This is an example of http service in golang!

把服务端的证书给他,当然通过。不过这不符合现实

我们用客户端证书试一下(先让客户端自签名吧)

openssl genrsa -out client.key 1024
openssl req -new -x509 -key client.key -out client.crt -days 365

第三次测试:curl -k https://127.0.0.1:8081 --cert client.crt --key client.key
curl: (35) error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate

服务端打印2021/03/21 16:40:17 http: TLS handshake error from 127.0.0.1:61672: tls: failed to verify client's certificate: x509: certificate signed by unknown authority
 

上面说明自己签名的不行,还是让CA签名吧

openssl req -new -key client.key -out clientca.csr
openssl ca -in clientca.csr -out clientca.crt -days 365

试了一下,服务端还是打印 2021/03/21 16:50:16 http: TLS handshake error from 127.0.0.1:61754: tls: failed to verify client's certificate: x509: certificate signed by unknown authority

查看一下证书,也没有问题啊

openssl x509 -in demoCA/cacert.pem -noout -text
openssl x509 -in clientca.crt -noout -text

最后发现问题了,代码中,根证书写错了,应该是

pool := x509.NewCertPool()
caCrt, err := ioutil.ReadFile("demoCA/cacert.pem")

不对,上面测试的是单向认证。 curl中的-k就表示不验证服务端的证书

If you'd like to turn off curl's verification of the certificate, use the -k (or --insecure) option.

双向认证这样写

 curl https://127.0.0.1:8081 --cert clientca.crt --key client.key --cacert demoCA/cacert.pem
curl: (51) SSL: certificate subject name 'gaofeng' does not match target host name '127.0.0.1'
修改host文件吧, C:\Windows\System32\drivers\etc\hosts 中增加     127.0.0.1       gaofeng

再来一把,大功告成。

curl https://gaofeng:8081 --cert clientca.crt --key client.key --cacert demoCA/cacert.pem
Hi, This is an example of http service in golang!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/995799.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存