问题描述
使用命令行网站下载程序,例如wget
,curl
或任何其他…在脚本中…
我拥有网站的SHA-1和SHA-256认证指纹。出于安全方面的考虑(1)(2),我不想使用公共SSL证书颁发机构系统。指纹必须经过硬编码。
像应用程序这样的wget可以检查SSL指纹吗?
wget没有这种功能。 (3)
使用wget --ca-certificate
或curl --cacert
我将不得不运行自己的本地证书颁发机构,我想防止这样做,因为这会增加很多复杂性。这也非常困难,而且从未有人做到过。 (4)
没有像download --tlsv1 --serial-number xx:yy:zz --fingerprint xxyyzz https://site.com
这样的工具吗?
当然,该解决方案必须不容易受到TOCTOU的攻击。 (5)MITM可以让openssl客户端请求返回一个有效的指纹,并篡改以下wget请求。
最佳方案
安装所需的软件:
apt-get install ca-certificates curl
下载公共SSL证书:
openssl s_client -connect torproject.org:443 -CAfile /usr/share/ca-certificates/mozilla/DigiCert_Assured_ID_Root_CA.crt >./x.cert </dev/null
或更好:
echo -n | openssl s_client -connect torproject.org:443 -CAfile /usr/share/ca-certificates/mozilla/DigiCert_Assured_ID_Root_CA.crt | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./torproject.pem
获取SHA-1指纹:
openssl x509 -noout -in torproject.pem -fingerprint -sha1
获取SHA-256指纹:
openssl x509 -noout -in torproject.pem -fingerprint -sha256
使用torproject.org FAQ: SSL手动比较SHA-1和SHA-256指纹。
.
(可选)使ca-certificates对测试无效。在这里使用curl,但是wget有一个Bug错误,并且仍然使用ca-files。
sudo mv /usr/share/ca-certificates /usr/share/ca-certificates_
使用curl和固定的证书下载:
curl --cacert ./torproject.pem https://check.torproject.org/ > check.html
次佳方案
在tcsh中:
echo | openssl s_client -connect host.example.com:443 |& openssl x509 -fingerprint -noout
第三种方案
这也足够了:
openssl x509 -fingerprint -in server.crt
第四种方案
使用openssl
命令及其客户端功能非常容易做到。
以下小脚本将使用给定的域(没有https前缀)和SHA-1指纹,如果检索到的指纹匹配,则退出且没有错误(0),如果没有匹配,则退出代码为1。然后,您可以通过简单地测试最后一个退出代码$?
将其合并到脚本中:
#!/bin/bash
FPRINT=`echo -n | openssl s_client -connect $1:443 2>/dev/null \|
openssl x509 -noout -fingerprint | cut -f2 -d'='`
if [ "$2" = "$FPRINT" ]; then
exit 0
else
exit 1
fi
第五种方案
#!/usr/bin/perl
# https://security.stackexchange.com/questions/20399/how-to-verify-the-ssl-fingerprint-by-command-line-wget-curl
# Code snippets taken from Net::SSLeay documentation and mildly modified.
# Requires a newer version of SSLeay (tested with 1.48)
# Needless to say, verify correct $host and $fingerprint before testing!!!
use Net::SSLeay qw(get_https3);
$host = "www.google.com";
$port = 443;
$fingerprint = "C1:95:6D:C8:A7:DF:B2:A5:A5:69:34:DA:09:77:8E:3A:11:02:33:58";
($p, $resp, $hdrs, $server_cert) = get_https3($host, $port, '/');
if (!defined($server_cert) || ($server_cert == 0)) {
warn "Subject Name: undefined, Issuer Name: undefined";
} elsif (Net::SSLeay::X509_get_fingerprint($server_cert, "sha1") ne $fingerprint) {
warn 'Invalid certificate fingerprint '
. Net::SSLeay::X509_get_fingerprint($server_cert, "sha1")
. ' for ' . Net::SSLeay::X509_NAME_oneline(
Net::SSLeay::X509_get_subject_name($server_cert));
} else {
print $p;
}
如Net :: SSLeay文档中概述的那样,此方法意味着在HTTP事务之后进行验证,因此如果要在发送数据之前验证自己正在与正确的服务器通信,则不应使用此方法。但是,如果您要做的只是确定是否信任刚刚下载的内容(听起来像是来自参考文献4),那就很好了。