通过一个例子说明客户端如何验证HTTPS服务端的证书信息。

类型浏览器如何验证WEB服务器的证书信息。

生成服务器端证书,以及CA证书

# generate ca certificate

$ openssl genrsa -out ca-key.pem 2048

$ openssl req -new -x509 -days 365 -key ca-key.pem -out ca-cert.pem -subj "/CN=ca"

# generate server certificate

$ openssl genrsa -out server-key.pem 2048

$ openssl req -new -key server-key.pem -out server-csr.pem -subj "/CN=localhost"

$ openssl x509 -req -days 3650 -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem

生成服务端证书server-cert.pem,(注意证书的common name是localhost),这个证书是通过CA证书ca-cert.pem签名的。

服务器端代码

$ cat server.go

package main

import (

"fmt"

"log"

"flag"

"net/http"

"crypto/tls"

"encoding/json"

"github.com/gorilla/mux"

)

var (

port int

hostname string

keyfile string

signcert string

)

func init() {

flag.IntVar(&port, "port", 8080, "The host port on which the REST server will listen")

flag.StringVar(&hostname, "hostname", "0.0.0.0", "The host name on which the REST server will listen")

flag.StringVar(&keyfile, "key", "", "Path to file containing PEM-encoded key file for service")

flag.StringVar(&signcert, "signcert", "", "Path to file containing PEM-encoded sign certificate for service")

}

func startHTTPSServer(address string, keyfile string, signcert string, router *mux.Router) {

s := &http.Server{

Addr: address,

Handler: router,

TLSConfig: &tls.Config{

MinVersion: tls.VersionTLS12,

},

}

err := s.ListenAndServeTLS(signcert, keyfile)

if err != nil {

log.Fatalln("ListenAndServeTLS err:", err)

}

}

func SayHello(w http.ResponseWriter, r *http.Request) {

log.Println("Entry SayHello")

res := map[string]string {"hello": "world"}

b, err := json.Marshal(res)

if err == nil {

w.WriteHeader(http.StatusOK)

w.Header().Set("Content-Type", "application/json")

w.Write(b)

}

log.Println("Exit SayHello")

}

func main() {

flag.Parse()

router := mux.NewRouter().StrictSlash(true)

router.HandleFunc("/service/hello", SayHello).Methods("GET")

var address = fmt.Sprintf("%s:%d", hostname, port)

fmt.Println("Server listen on", address)

startHTTPSServer(address, keyfile, signcert, router)

fmt.Println("Exit main")

}

编译运行

$ go build

$ ./server -port 8080 -signcert ./server-cert.pem -key ./server-key.pem

运行服务器在端口8080,这个服务器提供验证的证书是server-cert.pem,客户端(浏览器将验证这个证书的有效性)。

客户端代码

$ cat client.js

fs = require('fs');

https = require('https');

options = {

hostname: 'localhost',

port : 8080,

path : '/service/hello',

method : 'GET',

ca : fs.readFileSync('ca-cert.pem')

};

req = https.request(options, (res) => {

console.log('statusCode:', res.statusCode);

console.log('headers:', res.headers);

res.on('data', (d) => {

process.stdout.write(d);

});

});

req.on('error', (e) => {

console.error(e);

});

req.end();

运行

$ node client.js

{"hello":"world"}

完整的访问地址格式就是 https://localhost:8080/service/hello

这里客户端必须提供CA证书ca-cert.pem,用他来验证服务端的证书server-cert.pem是有效的。

另外这里客户端访问的地址是localhost,这个值和服务器证书server-cert.pem的common name域是一样的,否则验证就会失败。

例如,我们修改客户端请求中hostname值真实到机器名(假定机器名为saturn)。

options = {

hostname: 'saturn',

port : 8080,

path : '/service/hello',

method : 'GET',

ca : fs.readFileSync('ca-cert.pem')

};

$ node client.js

{ Error: Hostname/IP doesn't match certificate's altnames: "Host: saturn. is not cert's CN: localhost"

at Object.checkServerIdentity (tls.js:199:17)

at TLSSocket. (_tls_wrap.js:1098:29)

at emitNone (events.js:86:13)

at TLSSocket.emit (events.js:185:7)

at TLSSocket._finishInit (_tls_wrap.js:610:8)

at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:440:38)

这说明client使用URL的主机名和证书的Common Name域进行比较,作为证书是否有效的一个证据。

另外Common Name可以是一个短名(saturn),也可以长域名(saturn.yourcomp.com.cn),但不管短名还是长名都必须是URL请求中的主机名一样。即

SAN证书

SAN是另一种解决证书和URL主机名匹配的办法。

SAN = subjectAltName = Subject Alternative Name

具体用法步骤:

修改openssl.cnf

[ req ]

req_extensions = v3_req

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE

keyUsage = nonRepudiation, digitalSignature, keyEncipherment

subjectAltName = @alt_names

[alt_names]

DNS.1 = saturn

DNS.2 = saturn.yourcomp.com.cn

生成证书

# generate ca certificate

openssl genrsa -out ca-key.pem 2048

openssl req -new -x509 -days 365 -key ca-key.pem -out ca-cert.pem -subj "/CN=ca"

# generate server certificate

openssl genrsa -out server-key.pem 2048

openssl req -new -key server-key.pem -out server-csr.pem -subj "/CN=localhost"

openssl x509 -req -days 3650 -in server-csr.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extensions v3_req -extfile openssl.cnf

对比和前面不使用SAN的差别。其实就是在使用CA根证书对服务器证书签名的时候,指定extensions属性。

运行客户端

options = {

hostname: 'localhost',

port : 8080,

path : '/service/hello',

method : 'GET',

ca : fs.readFileSync('ca-cert.pem')

};

$ node client.js

{ Error: Hostname/IP doesn't match certificate's altnames: "Host: localhost. is not in the cert's altnames: DNS:saturn"

看到了吗?localhost已经验证不过了,尽管他在common name的值没有变化,但是由于使用了SAN,证书验证的时候就使用SAN的值,而忽略common name的值。

使用客户端saturn

options = {

hostname: 'saturn',

port : 8080,

path : '/service/hello',

method : 'GET',

ca : fs.readFileSync('ca-cert.pem')

};

$ node client.js

{"hello":"world"}

使用saturn就通过了。当然使用saturn.yourcomp.com.cn也能通过。

总结

客户端验证服务端证书分两种情况:

不使用SAN,那么验证证书的common name和URL的主机名一致。

主机名是否是common name中的一个。

使用SAN,那么验证证书的SAN值和URL的主机名一致。

主机名是否就是SAN值中的一个。

服务器客户端证书,客户端如何验证HTTPS服务端证书信息相关推荐

  1. HTTPS|SSL笔记-SSL双向认证失败(客户端证书信任库不含服务端证书)握手过程(含wireshark分析)

    这里我把客户端证书信任库里面清空,及没放服务端证书,Java报错不一样,但抓包是一样的,在此记录下过程. 1. 前3个包是TCP三次握手,在此不解析,对应的包如下: 2. 握手成功后,客户端发送自己支 ...

  2. HTTPS|SSL笔记-SSL双向认证失败(服务端证书信任库不含客户端证书)握手过程(含wireshark分析)

    这里我把服务端信任库添加了其他证书,不含客户端的证书,这时SSL认证失败报错如下.下面来分析下: 1. 首先是TCP三次握手,对应的包如下: 2. 握手成功后,客户端发送自己支持的加密套,和随机数给服 ...

  3. 微软服务器搭建ngrok,ngrok搭建(Windows服务端+Windows客户端)

    1.go环境搭建(需要Linux系统) 1)下载源码,可以在http://www.golangtc.com/download 2)将其解压到/usr/local目录下: tar -C /usr/loc ...

  4. 自制CA证书,自制客户端,服务端证书

    自制CA证书,客户端.服务端证书 参考资料:HTTPS证书生成原理和部署细节 废话不多讲,我们直入正题. 首先我假设你的系统已经安装了openssl.使用openssl version -a即可查看当 ...

  5. Java IOS客户端上传多张图片到服务端

    Java IOS客户端上传多张图片到服务端 业务场景:用户相册需要上传多张图片到服务器,上限为12张.本文主要介绍Java服务端的文件和流的处理. 下图为iOS端和服务端最终结果一览.  iOS端 : ...

  6. 客户端、前端、后端、服务端的区别分别是什么?

    客户端.前端.后端.服务端的区别分别是什么? 客户端是指开发面向客户的程序,分很多平台,比如Windows 安卓 苹果,还有游戏客户端也算一类. 前端指的是通过浏览器和用户交互的那部分. 后端是在服务 ...

  7. Asp.net webApi 通过WebSocket推送消息给客户端,搭建一个即是服务端又是客户端的服务

    Asp.net webApi 通过WebSocket推送消息给客户端,搭建一个即是服务端又是客户端的服务_IT_ziliang的博客-CSDN博客 WebSocket是一种在单个TCP连接上进行全双工 ...

  8. java 网络编程(二) tcp传输实现客户端和服务端进行信息交流

    1.使用Tcp从一台电脑往另一台电脑上发送文本数据 客户端: import java.io.*; import java.net.*; /**** 客户端,* 通过查阅socket对象,发现在该对象建 ...

  9. 浅析客户端渲染(CSR)与服务端渲染(SSR)

    最近刚好公司有项目需要用到服务端渲染,于是花了些时间了整理了关于服务端渲染与客户端渲染的知识,现在记录下来,希望能帮助大家提升对浏览器渲染,服务端渲染的理解,在项目选型上做出正确的决策. 本文会涉及这 ...

最新文章

  1. JavaScript 复习之 Array 对象
  2. matlab 设计 18db,基于混沌理论的微弱MPSK信号解调方案设计
  3. 学生信息管理系统中遇到的问题解析
  4. 简单快速的用SpringBoot访问静态资源(图片、html)
  5. svn 服务器的搭建以及客户端的使用
  6. URL Safe base64 与 base64相互转换
  7. SQL*Plus 系统变量之32 - NEWP[AGE]
  8. MySQL Workbench中PK,NN,UQ,BIN,UN,ZF,AI,G字段类型标识说明
  9. RDIFramework.NET ━ .NET快速信息化系统开发框架 V2.8 版本━新增岗位管理-WinForm部分
  10. bootstrap, boosting, bagging
  11. HBuilderX 开发工具
  12. ENVI App Store
  13. C语言 统计元音字母个数
  14. Linux kernel Panic后自动重启机器的设置
  15. Python标准库:内置函数divmod(a, b)
  16. 车载以太网协议:SOME/IP (layer5-7)简介
  17. 怎么渗透验证 mysql_mysql-渗透测试
  18. AD中PCB布局与布线的一般原则
  19. 用海伦公式计算三角形面积
  20. Voyager下的关系模型

热门文章

  1. SAP标准功能重复制造计划编制表实现生产排产初步分析
  2. 解决win10学习汇编工具的烦恼——汇编Debug的下载和使用(包含可用下载链接)
  3. 视频压缩编码和解码(转)
  4. 计算机修改users用户名,笔记本电脑更改用户名_笔记本电脑更改user
  5. 主成分分析时,如果矩阵秩亏,会发生什么后果?
  6. matplotlib 入门之Sample plots in Matplotlib
  7. 线下沙龙 | EOS入门及最新技术解读
  8. matplotlib的Text、FontProperties对象、字体(font)属性|中文字体的设置|图像标题、label字体的设置
  9. 20165334 学习基础与c语言学习心得
  10. POS 打印机编程控制