如何在Ruby的SSLServer中实现SSL证书的自定义验证?

时间:2013-02-28 22:46:12

标签: ruby ssl openssl

我正在使用SSL在两个对等体之间形成可信连接。每个对等方都知道它希望在给定时间连接到(或接受连接)的人。它应该只接受有效的证书,而且,它应该只接受具有某些属性的证书(可能通过检查规范名称)。

到目前为止,基于the example in this question, and its answer,我可以让双方进行交谈。每一方都可以打印出另一方提供的证书。

但是,我不确定验证这些证书的正确方法是什么。显而易见的方法是在建立连接后查看证书,如果不符合我们的期望,则删除连接。

有更正确的方法吗?是否有一个回调给出了同行提供的证书,可以给它竖起大拇指或大拇指向下?或者在完成SSL工作后处理它是正确的吗?

2 个答案:

答案 0 :(得分:1)

  但是,我不确定验证这些证书的正确方法是什么。   显而易见的方法是在查看之后查看证书   建立连接并断开连接,如果它不符合我们的要求   期望。

对此有很多,其中一些并不明显。我打算将答案分成几部分,但所有部分都试图回答你的问题。


首先,您可以验证证书是否格式正确。在Web环境中负责的小组是CA / Browser论坛。他们对创建证书有基准和扩展要求:

在基线文档中,您会发现,例如,列为公用名(CN)的IP也必须列在主题备用名称(SAN)中。在扩展文档中,您会发现私有IP(按RFC 1918保留)不能出现在扩展验证(EV)证书中;和EV证书不能包含通配符。


其次,您可以根据RFC 5280, Internet X.509公钥基础结构证书和证书吊销列表(CRL)配置文件http://www.ietf.org/rfc/rfc5280.txt执行常规验证。

常规检查包括主机名匹配,时间段有效性检查以及验证终端实体或叶证书(客户端或服务器证书)链回到根。在使用CA的浏览器中,有数百个可信任的根或中间体。

如果您选择执行吊销检查,那么您可能会对您的应用程序执行操作(这是多么明显!)。 3G网络上的移动客户端无法下载和处理30MB CRL - 它肯定会挂起应用程序。当URL错误时,应用程序无法执行OCSP查询 - 这肯定会失败。

此外,如果您正在执行包含通配符的主机名匹配,则必须注意正确处理ccTLD。 ccTLD类似于* .eu,*。us或இலங்கை(nic.lk)。其中大约有5000个左右,Mozilla在http://publicsuffix.org/提供了一个列表(或者https://mxr.mozilla.org/mozilla-central/source/netwerk/dns/effective_tld_names.dat?raw=1)。


第三,CA不保证任何内容,因此您从CA获得的答案毫无价值。如果您不相信我,请查看他们的认证实践声明(CPS)。例如,以下摘自Apple的Certification Authority Certification Practice Statement(2013年9月18日,第6页):

2.4.1. Warranties to Subscribers
The AAI Sub-CA does not warrant the use of any Certificate to any Subscriber.

2.4.2. CA disclaimers of warranties
To the extent permitted by applicable law, Subscriber agreements, if applicable,
disclaim warranties from Apple, including any warranty of merchantability or
fitness for a particular purpose

这意味着他们不会通过发行人的签名保证公钥与组织的约束。这就是X509的全部目的!


第四,DNS不提供真实的答案。所以你可能会从DNS得到一个糟糕的答案,并愉快地前进到你的对手控制的服务器。或者,受美国控制的13个根DNS服务器中的10个可能串通,以美国国家安全的名义给出错误的答案。

尝试从非美国服务器获得真实的响应几乎是不可能的。 "安全DNS"件(无DNSSEC)仍在不断发展,我不知道任何主流实现。

在联合美国服务器的情况下,法定人数不会起作用,因为美国占绝大多数。


这里的问题是您根据外部服务(CA和DNS)的输入做出安全决策。从本质上讲,你也必须相信不值得信任的演员。

PKI和PKIX问题的一个很好的解决方法是Peter Gutmann博士的工程安全,网址是www.cs.auckland.ac.nz/~pgut001/pubs/book.pdf 。一定要阅读第1章和第6章.Gutmann博士有一种诙谐的幽默感,所以它不干嘛。另一本伟大的书是http://www.cl.cam.ac.uk/~rja14/book.html的罗斯安德森的安全工程


你有几个防御措施,包括PKI,PKIX和CA引起的所有问题。首先,您可以运行私有PKI,您可以在其中拥有自己的证书颁发机构。在这种情况下,你不信任局外人。应该捕获错误的DNS答案和恶意服务器,因为服务器的证书不会形成有效的链。

其次,您可以采用安全多元化战略。 Gutmann在他的工程安全一书中写到了这一点,你应该访问"通过多元化的安全性"从第292页开始,以及"互联网应用的风险分散"第296页的部分。

第三,您可以采用首次使用信任(TOFU)或密钥连续性策略。这类似于Wendlandt,Anderson和Perrig的 Perspectives:使用多路径探测改进SSH风格的主机认证或SSH的StrictHostKeyChecking选项。在此策略中,您执行常规检查,然后固定证书或公钥。您还可以询问其他人对证书或公钥的看法。意外的证书或密钥更改应引发警钟。

OWASP在https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning处理证书和公钥固定。注意:有些地方每隔30天左右轮换一次证书,所以如果可能的话,你应该把公钥固定好。频繁旋转器的列表包括谷歌,其中一个原因是证书巡逻等工具产生如此大的噪音。

答案 1 :(得分:1)

  

在这种情况下,我是CA,因此信任CA不是问题。我   代表我的用户签署这些证书。规范名称   甚至不是域名。用户连接点对点。我想要   我分发的客户端软件,用于验证连接用户是否有   证书我签了,是正确的用户。

听起来你正在运行私人PKI。只需使用SSL_CTX_load_verify_locationsSSL_load_verify_locations将信任链的根加载到OpenSSL中。

请务必使用SSL_PEER_VERIFY确保OpenSSL执行验证。该调用可能看起来像SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);。如果对等验证失败,则connect将失败。

有一些方法可以确保connect成功,然后再发现错误。诀窍是设置验证回调,让验证回调始终返回1,然后在建立连接后调用SSL_get_verify_result。有关示例,请参阅SSL/TLS Client

注意:在所有情况下,您仍然需要手动执行名称检查。 OpenSSL目前没有这样做(它在HEAD for OpenSSL 1.1.0中)。有关您可以翻录的代码,请参阅libcurl或PostgreSQL。

OpenSSL在其wiki上提供了SSL / TLS客户端的示例。见SSL/TLS Client。目前没有服务器代码或示例。