# 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!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)