帮助理解客户端证书验证

信息安全 tls 验证 客户端
2021-08-30 14:33:54

我正在创建一个只有某些计算机才能访问的 API。服务器和客户端之间将通过 SSL 进行通信。为了验证客户端是否具有访问权限,我想为每个客户端创建一个由服务器签名的证书。任何不提供由服务器签名的证书的客户端都应该被拒绝访问。

我有来自 GoDaddy 的 SSL 证书和密钥。我认为我应该能够使用此信息创建客户端证书,但是无论我看哪里,似乎我都需要 CA 证书(来自 GoDaddy)来签署客户端证书,而不是我的特定服务器的证书/密钥。

这对我来说没有意义,因为我必须去 GoDaddy 并为每个客户获取新证书似乎很奇怪。我想情况并非如此,我要么做错了什么,要么不完全理解。

那么-如何创建由我的服务器证书/密码签名的客户端证书?

如果您可以提供命令(我正在使用 openssl)从我的服务器证书生成客户端证书,那也将不胜感激。

谢谢!

3个回答

为了签署客户端证书,您将需要您控制的 CA 证书。在大多数情况下,购买一个证书是不可能的,因为全球信任的 CA 证书对 Internet 的其余部分来说是一种安全隐患。因此,在这些情况下,您必须创建自己的 CA 并创建自己的服务器和客户端证书。

因此,让我们从一个基本的openssl.conf文件开始,我们将使用它来生成所有这些证书:

[ ca ]
default_ca  = CA_default                # The default ca section

[ CA_default ]
certs          = certs                  # Where the issued certs are kept
crl_dir        = crl                    # Where the issued crl are kept
database       = database.txt           # database index file.
new_certs_dir  = certs                  # default place for new certs.
certificate    = cacert.pem             # The CA certificate
serial         = serial.txt             # The current serial number
crl            = crl.pem                # The current CRL
private_key    = private\cakey.pem      # The private key
RANDFILE       = private\private.rnd    # private random number file

x509_extensions  = v3_usr               # The extentions to add to the cert
default_days     = 365
default_crl_days = 30                   # how long before next CRL
default_md       = sha256               # which md to use.
preserve         = no                   # keep passed DN ordering
policy           = policy_match
email_in_dn      = 

[ policy_match ]
commonName      = supplied

[ req ]
default_bits        = 2048
default_keyfile     = privkey.pem
distinguished_name  = req_distinguished_name
x509_extensions     = v3_ca

[ v3_ca ]
basicConstraints     = CA:TRUE
subjectKeyIdentifier = hash

[ v3_usr ]
basicConstraints     = CA:FALSE
subjectKeyIdentifier = hash

[ server ]
basicConstraints       = CA:FALSE
nsCertType             = server
nsComment              = "Server Certificate"
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage       = serverAuth
keyUsage               = digitalSignature, keyEncipherment

[ client ]
basicConstraints       = CA:FALSE
nsCertType             = client
nsComment              = "Client Certificate"
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage       = clientAuth
keyUsage               = digitalSignature

[ req_distinguished_name ]

此配置文件用于从批处理脚本自动生成证书。如果您需要更多控制或命名选项,则需要根据您的情况进行调整。

因此,要生成 CA,请转到要创建 CA 的目录,将 openssl.conf 放在那里,然后:

PASSWORD="PUT_YOUR_CA_PASSWORD_HERE"

# Make the config CA specific
cat openssl.conf > use.conf
echo "CN=PUT_CA_NAME_HERE" >> use.conf

# Create the necessary files
mkdir keys requests certs 
touch database.txt
echo 01 > serial.txt

# Generate your CA key (Use appropriate bit size here for your situation)
openssl genrsa -aes256 -out keys/ca.key -passout pass:$PASSWORD 2048

# Generate your CA req
openssl req -config use.conf -new -key keys/ca.key -out requests/ca.req -passin pass:$PASSWORD

# Make your self-signed CA certificate
openssl ca  -config use.conf -selfsign -keyfile keys/ca.key -out certs/ca.crt -in requests/ca.req -extensions v3_ca -passin pass:$PASSWORD -batch

# Cleanup
rm requests/ca.req use.conf

现在生成服务器证书(例如为您的 Web 服务器):

PASSWORD="PUT_YOUR_CA_PASSWORD_HERE"
NAME="PUT_THE_NAME_OF_SERVER_TO_GENERATE_HERE"

# Make the config Server specific
cat openssl.conf > use.conf
echo "CN=$NAME" >> use.conf

openssl req -new -nodes -extensions server -out "requests/$NAME.req" -keyout "$NAME.key" -config use.conf -passin pass:$PASSWORD )
openssl ca -batch -extensions server -keyfile keys/ca.key -cert certs/ca.crt -config use.conf -out "certs/$NAME.crt" -passin pass:$PASSWORD -infiles "requests/$NAME.req"

# Cleanup
rm "requests/$NAME.req" use.conf

现在生成客户端证书:

PASSWORD="PUT_YOUR_CA_PASSWORD_HERE"
NAME="PUT_THE_NAME_OF_CLIENT_TO_GENERATE_HERE"

# Make the config Client specific
cat openssl.conf > use.conf
echo "CN=$NAME" >> use.conf

openssl req -new -nodes -extensions client -out "requests/$NAME.req" -keyout "$NAME.key" -config use.conf -passin pass:$PASSWORD )
openssl ca -batch -extensions client -keyfile keys/ca.key -cert certs/ca.crt -config use.conf -out "certs/$NAME.crt" -passin pass:$PASSWORD -infiles "requests/$NAME.req"

# Cleanup
rm "requests/$NAME.req" use.conf

为客户端和服务器生成密钥和证书之间的唯一区别是,它可以防止被盗的客户端证书也可用于播放服务器并“欺骗”其他客户端连接到它(这只有在您的应用程序支持客户端时才有效)和证书中的服务器扩展)。

认证机构是颁发证书的实体您想(向客户端)颁发证书,因此您想成为 CA。

任何试图验证证书的人都需要信任 CA 密钥(这是先验信任:想想在软件或操作系统中硬编码的 CA 公钥)。在您的情况下,您希望您的服务器验证证书,因此您的服务器必须保留 CA 公钥的副本。

像 GoDaddy 这样的现有 CA 成功地将其公钥的副本导入所有 Web 浏览器——他们的 CA 受到所有人的信任。为了实现这一点,他们必须向浏览器供应商(例如微软)证明他们是值得信赖和认真的(私钥在掩体中,他们有一切程序,他们有足够的财务支持以确保运营的连续性......)而且它很昂贵,这就是为什么他们不会免费(甚至便宜)为您提供 sub-CA 电力。但是,在您的情况下,您并不关心 CA 密钥是否为全世界所知:您只需要您的服务器(您完全控制的)将信任的 CA。您自己维护的 CA 就可以了。

EJBCA是一个免费的开源 CA 实现,应该易于使用。或者,您可以围绕OpenSSL将一些脚本放在一起。

注意:证书是用来认证的,不是用来授权的。它们旨在识别用户。我建议您将服务器中的两个角色分开:

  • 当您向客户端 X 颁发证书时,请在证书中输入名称“X”。
  • 在服务器上保留一个“允许的客户端”表(按名称)。
  • 当客户端连接时,验证其证书,然后从证书中提取客户端名称,并检查允许客户端表中的名称。

在您想要撤销给定客户端的访问权限的那一天,这种分离将非常有用。

据我所知,您无法使用从 GoDaddy 购买的 SSL 创建有效的客户端证书。其背后的原因与 GoDaddy 的 CA 证书的私钥有关,他们不会有充分的理由给出。

现在,如果您拥有所有计算机在您的控制之下,最简单、最便宜的做法就是生成您自己的 CA 证书并签署您的客户。将您的 CA 添加到每台计算机上的每个受信任的根存储。

您可以让 CA 签署允许您成为 CA 的证书,但是,这些证书并不便宜,如“联系我们获取报价”。

如果您需要一个工具,我相信XCA是一个 GUI,可以让您更轻松。