一个安全、可信的系统应该是全方位的,既要考虑通信加密,也要考虑存储的安全性(甚至包括磁盘损坏,数据丢失这种安全),还有社会工程方面的安全性,还要考虑接口本身的安全性,不管是业务的安全性,比如幂等性,还是软件的安全性,比如使用了内存溢出这种不安全的编码、不安全的开源软件等等。是一个非常复杂的系统性工程。
得益于计算机科学的开放性,不管是前沿研究,还是营利性的公司或者个人,都愿意分享自己的创造成果。系统安全性也有一系列的开源密码算法、配置和系统。
本文将介绍和安全相关一些主要概念,常用算法。常见的一些密码常见,应该选择什么样的密码算法。
一、非对称加密算法
目前加密算法大概分为对称加密和非对称加密两大类。
非对称加密可以用在网络这种不安全的情况下,传递密钥等场景,大部分非对称加密算法基于数学原理,理论上安全,但是不排除通过可以通过一些逼近算法等手段降低破解所需算力,当然这是最顶尖的数学家才能办到的,对于我们屁民来说,达到足够强度的算法,就是足够安全的,毕竟普通个人不会被国家机构盯上的。常见的有RSA、ECC、SM2、SM9、DH、DSA、Rabin
非对称加密安全的加密算法 RSA 4096位以上,ECC使用secp384r1曲线
二、对称加密算法
对称加密一般速度快,比如https使用非对称加密算法完成密钥交换后,就会使用对称加密,来对通信数据加密。常见的又DES IDEA AES还有国密的SM1,SM4。DES和3DES已经不够安全,应该避免使用。
对称加密又有两大类型,分组加密和流加密。
常见的流加密算法有RC4、ZUC、ChaCha20等,这些流加密算法又有很多变种,除了CHACHA20-POLY1305,其他所有流式加密算法都不应该使用。
分组加密,有SM1/SCB2、SM4/SMS4、SM7DES、IDEA、AES、RC5、RC6等N多算法。分组加密存在多种模式,比如ECB、CBC、、PCBC、CFB、OFB、CTR、GCM等等一系列模式。分组密码对明文分组时,假如最后的分组和密码长度不一致时,则需要填充,填充又有PKCS7、PKCS5等
为什么要这么多模式,都是为了安全性,以及计算性能等,比如原图
对于对称加密,推荐只使用AES 256 GCM,CHACHA20-POLY1305
三、哈希、MAC和HMAC
- 哈希就是对于原文,使用哈希算法后产生一个长度和内容不变的随机字符串。哈希算法有多种,比如MD5、SHA1、SHA2,SHA2包括SHA224、SHA256、SHA384、SHA512。
- MAC在哈希的基础上,对原文按照某种算法,用一个密钥进行加密,得到一个长度和内容不变的随机加密串。hash只能验证数据完整性,无法保证数据被篡改,而MAC不但可以验证数据完整性,也可以验证数据没有被篡改。
- HMAC是MAC的一种。也就是2中的某种算法就是hash算法
四、证书和PKI体系
todo
五、保存格式
todo
格式 | 说明 |
---|---|
二进制证书 | 使用可辨别编码规则 (DER) ASN.1 编码的原始格式二进制证书。 |
ASCII PEM 格式 | PEM 证书 (.pem) 文件包含以 -----BEGIN CERTIFICATE----- 开头且以 -----END CERTIFICATE----- 结尾的 Base64 编码证书。 上传某些证书时(如设备证书),IoT 中心需要 PEM 格式(X.509 证书最常见的格式之一)。 |
ASCII PEM 密钥 | 包含 Base64 编码的 DER 密钥,可以选择包含有关用于密码保护的算法的其他元数据。 |
PKCS #7 证书 | 一种用于传输已签名或已加密数据的格式。 它可以包括整个证书链。RFC 2315 定义此格式。 |
PKCS #8 密钥 | 私钥存储的格式。RFC 5208 定义此格式。 |
PKCS #12 密钥和证书 | 一种复杂的格式,可以存储和保护密钥和整个证书链。 它通常与 .p12 或 .pfx 扩展名一起使用。 PKCS #12 等同于 PFX 格式。RFC 7292 定义此格式。 |
X.509
PEM: base64编码,可保存证书,可保存私钥
PKCS7: 只包含证书文件.p7b, .p7c
PKCS8:
PKCS12: PFX, p12,证书和私钥存在一个 PFX 文件中。一般用于 Windows 上的 IIS 服务器,有一个密码用于保证私钥的安全
JKS: JAVA 的专属格式,利用 JAVA 的一个叫 keytool
的工具可以进行格式转换
X.690
BER:
CER:
DER: 二进制原始格式,没有任何编码,所以不需要解码,直接使用,只保存证书,不保存私钥,Java 和 Windows 服务器偏向于使用这种编码格式。
.key: 文件后缀PEM格式的私钥
.pub: PEM格式公钥
.crt: PEM或者DER格式的公钥证书,不保存私钥
cer: PEM或者DER格式的公钥证书
.crs: PEM或者DER格式的CSR(证书请求)文件
文件名后缀并不是编码格式,而是使用中,用来区分文件用途
openssl rsa -in private.pem -text
openssl rsa -in ca/ca.key -text -noout
############################################################################
openssl x509 -in cert.crt -outform der -out cert.der # pem转der
openssl x509 -inform der -in certificate.cer -out certificate.pem # der转pem
openssl pkcs12 -in for-iis.pfx # 查看p12
openssl pkcs12 -in for-iis.pfx -out for-iis.pem -nodes # p12转pem
openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx #pem转p12
openssl pkcs7 -print_certs -in certificate.p7b -out certificate.pem #p7转pem
openssl crl2pkcs7 -nocrl -certfile server.crt -out server.p7b #pem转p7
openssl rsa -inform pem -in rsa_private.pem -text -noout #查看pem
openssl rsa -inform der -in rsa_private.der -text -noout #查看der
六、TLS与HTTPS
todo
七、nginx ssl配置
7.1 HSTS
浏览器在访问站点的时候,如果没有指定 HTTPS 访问,默认使用 HTTP,所以我们会将 HTTP 重定向(301或302)到 HTTPS。这样看起来没有问题,但是当使用重定向进行跳转时,网站就存在被劫持的可能。因此有了 HSTS, 采用 HSTS 协议的网站将保证浏览器始终连接到网站的HTTPS版本。浏览器将在访问https网站前,先看看网址在不在HSTS Preload List, 如果网站在这里面,将直接使用https访问。因此网站拥有者需要手动把网站加入到HSTS preload list。
7.2 OCSP Stapling
OCSP (Online Certificate Status Protocol) 通常是 CA 提供来实时验证证书是否合法有效的。客户端就可以根据证书中的 OCSP 信息,发送查询请求到 CA 的在线验证地址来查询证书是否有效。OCSP 的问题在于,对 CA 机构的验证接口高可用性有要求,增加了浏览器握手的延时。
OCSP Stapling 技术是对 OCSP协议 的进一步升级。服务器事先模拟浏览器对证书链进行验证,然后将 OCSP 验证结果缓存到本地。这样,当浏览器访问站点时,在握手阶段,可以直接拿到 OCSP 响应结果和证书链,就不需要再向 CA 请求接口,对访问速度有明显提升。
7.3 nginx配置
https://blog.xiedeacc.com/archives/best-nginx-configuration
八、制作自签名证书
# 初始化
rm -rf ~/src/cert
mkdir -p ~/src/cert/ca
mkdir -p ~/src/cert/certs
mkdir -p ~/src/cert/ca/root
mkdir -p ~/src/cert/ca/intermediate
*******************************************************************************************
# 创建根证书
cd ~/src/cert/
rm -rf ~/src/cert/ca/root
mkdir -p ~/src/cert/ca/root
cd ~/src/cert/ca/root
mkdir crl csr private
chmod 700 private
touch index.txt
echo 1000 > serial
cat > ./openssl.cnf << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /root/src/cert/ca/root
new_certs_dir = /root/src/cert/certs
crldir = \$dir/crl
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
private_key = \$dir/private/root.key
certificate = /root/src/cert/certs/ca.root.cert
crlnumber = \$dir/crlnumber
crl = \$crldir/crl.key
crl_extensions = crl_ext
copy_extensions = copy
name_opt = ca_default
cert_opt = ca_default
default_days = 1095
default_crl_days= 30
default_md = sha256
preserve = no
policy = policy_strict
[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ v3_intermediate_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical,CA:true
keyUsage = critical,digitalSignature,cRLSign,keyCertSign
EOF
openssl genrsa -aes256 -out private/root.key 4096
chmod 400 private/root.key
openssl req -key private/root.key -new -x509 -days 1095 -sha256 \
-subj "/C=CN/ST=GD/L=SZ/O=xiedeacc/CN=xiedeacc Root CA" \
-addext subjectKeyIdentifier=hash \
-addext authorityKeyIdentifier=keyid:always,issuer \
-addext basicConstraints=critical,CA:true \
-addext keyUsage=critical,cRLSign,keyCertSign,digitalSignature \
-out /root/src/cert/certs/ca.root.cert
chmod 444 /root/src/cert/certs/ca.root.cert
openssl x509 -noout -text -in /root/src/cert/certs/ca.root.cert
openssl verify -CAfile /root/src/cert/certs/ca.root.cert /root/src/cert/certs/ca.root.cert
*******************************************************************************************
# 创建中间证书
rm -rf ~/src/cert/ca/intermediate
mkdir -p ~/src/cert/ca/intermediate
cd ~/src/cert/ca/intermediate
mkdir crl csr private
chmod 700 private
touch index.txt
echo 1000 > serial
echo 1000 > crlnumber
cat > ./openssl.cnf << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /root/src/cert/ca/intermediate
new_certs_dir = /root/src/cert/certs
crldir = \$dir/crl
database = \$dir/index.txt
serial = \$dir/serial
RANDFILE = \$dir/private/.rand
private_key = \$dir/private/ca.intermediate.key
certificate = /root/src/cert/certs/ca.intermediate.cert
crlnumber = \$dir/crlnumber
crl = \$crldir/crl.key
crl_extensions = crl_ext
copy_extensions = copy
name_opt = ca_default
cert_opt = ca_default
default_days = 1095
default_crl_days= 30
default_md = sha256
preserve = no
policy = policy_loose
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ server_cert ]
basicConstraints = CA:FALSE
nsCertType = server
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
[ usr_cert ]
basicConstraints = CA:FALSE
nsCertType = client,email
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical,nonRepudiation,digitalSignature,keyEncipherment
extendedKeyUsage = clientAuth,emailProtection
[ crl_ext ]
authorityKeyIdentifier=keyid:always
[ ocsp ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,OCSPSigning
EOF
openssl genrsa -aes256 -out private/intermediate.key 4096
chmod 400 private/intermediate.key
openssl req -new -sha256 -key private/intermediate.key \
-subj "/C=CN/ST=GD/L=SZ/O=xiedeacc/CN=xiedeacc Intermediate CA" \
-out intermediate.csr
openssl ca -config /root/src/cert/ca/root/openssl.cnf -extensions v3_intermediate_ca \
-days 1095 -notext -md sha256 \
-in intermediate.csr \
-out /root/src/cert/certs/ca.intermediate.cert
chmod 444 /root/src/cert/certs/ca.intermediate.cert
openssl x509 -noout -text -in /root/src/cert/certs/ca.intermediate.cert
openssl verify -CAfile /root/src/cert/certs/ca.root.cert /root/src/cert/certs/ca.intermediate.cert
cat /root/src/cert/certs/ca.root.cert \
/root/src/cert/certs/ca.intermediate.cert > /root/src/cert/certs/ca-chain.cert
chmod 444 /root/src/cert/certs/ca-chain.cert
*******************************************************************************************
rm -rf /root/src/cert/xiedeacc.com
mkdir -p /root/src/cert/xiedeacc.com
cd /root/src/cert/xiedeacc.com
openssl genrsa -aes256 -out xiedeacc.com.key 4096
openssl req -new -sha256 -key xiedeacc.com.key \
-subj "/C=CN/ST=GD/L=SZ/O=xiedeacc/CN=code.xiedeacc.com" \
-addext subjectAltName="IP:127.0.0.1,IP:::1,DNS:localhost,DNS:127.0.0.1,DNS:::1,DNS:code.xiedeacc.com,DNS:ceph.xiedeacc.com" \
-out xiedeacc.com.csr
openssl ca -config /root/src/cert/ca/intermediate/openssl.cnf \
-extensions server_cert -days 375 -notext -md sha256 \
-in xiedeacc.com.csr \
-out /root/src/cert/certs/xiedeacc.com.cert
chmod 444 /root/src/cert/certs/xiedeacc.com.cert
openssl x509 -noout -text -in /root/src/cert/certs/xiedeacc.com.cert
openssl verify -CAfile /root/src/cert/certs/ca.chain.cert /root/src/cert/certs/xiedeacc.com.cert
九、使用acme申请Let's Encrypt证书
curl https://get.acme.sh | sh
cd ~/.acme.sh/
sudo chown -R ubuntu:ubuntu /usr/local/nginx/conf/ssl
./acme.sh --upgrade --auto-upgrade
./acme.sh --register-account -m xiedeacc@gmail.com
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=xxx
./acme.sh -f --issue --ocsp --dns dns_aws -d "youkechat.net" -d "*.youkechat.net"
./acme.sh --installcert -d "youkechat.net" -d "*.youkechat.net" --key-file /usr/local/nginx/conf/ssl/youkechat.net.key --cert-file /usr/local/nginx/conf/ssl/youkechat.net.cer --ca-file /usr/local/nginx/conf/ssl/youkechat.net.ca.cer --fullchain-file /usr/local/nginx/conf/ssl/youkechat.net.fullchain.cer
export AWS_ACCESS_KEY_ID=xxx
export AWS_SECRET_ACCESS_KEY=xxx
./acme.sh -f --issue --ocsp --dns dns_aws -d "xiedeacc.com" -d "*.xiedeacc.com"
./acme.sh --installcert -d "xiedeacc.com" -d "*.xiedeacc.com" --key-file /usr/local/nginx/conf/ssl/xiedeacc.com.key --cert-file /usr/local/nginx/conf/ssl/xiedeacc.com.cer --ca-file /usr/local/nginx/conf/ssl/xiedeacc.com.ca.cer --fullchain-file /usr/local/nginx/conf/ssl/xiedeacc.com.fullchain.cer
./acme.sh --renew-all --force
./acme.sh --installcert -d "xiedeacc.com" -d "*.xiedeacc.com" --key-file /etc/nginx/ssl/xiedeacc.com.key --cert-file /etc/nginx/ssl/xiedeacc.com.cer --ca-file /etc/nginx/ssl/xiedeacc.com.ca.cer --fullchain-file /etc/nginx/ssl/xiedeacc.com.fullchain.cer
十、部署证书
- Java
keytool.exe -import -trustcacerts -keystore "C:\Program Files\Java\jdk1.8.0_321\jre\lib\security\cacerts" -storepass changeit -noprompt -alias xiedeacc.com -file C:\Users\tiger\Desktop\ca.chain.cert
- Windows
- Git
- Ubuntu
十一、tips
- 对于AES258,密钥长度为256位,即32字节,但是我们日常密码肯定不会有32个字符长,那怎么使用AES256算法的呢?
- AES实际上是没有PKCS5填充模式的,国内很多资料这一点是错误,包括和阿里广告系统对接过程中,他们也犯了这错误。如果强行使用的话,实际上指定的是AES128的PKCS7填充模式
- 非对称加密安全的加密算法 RSA 4096位以上,ECC使用secp384r1曲线
- 对称加密,推荐只使用AES 256 GCM,CHACHA20-POLY1305
十二、reference
- https://zhuanlan.zhihu.com/p/558881344
- https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation
- practical cryptography for developers
- 密码学系列之:PEM和PKCS7,PKCS8,PKCS12
- HTTPS优化总结
- https://www.ssllabs.com/ssltest/ 检查网站https配置是否正确
- https://hstspreload.org/
- https://wsgzao.github.io/post/acme/
- https://github.com/crypto101/book
- https://en.wikipedia.org/wiki/X.690
- https://learn.microsoft.com/zh-cn/azure/iot-hub/reference-x509-certificates
- https://juejin.cn/post/7082214905780109326
- https://jamielinux.com/docs/openssl-certificate-authority/index.html 自签名证书最好的文档,没有之一