我马上道歉,如果这是不正确的,所以(信息安全或加密)。无论如何,我试图弄清楚如何在Python中验证SSL证书客户端。我发现了一个回调函数here,它看起来与我在网上看到的其他函数相似。然而,在我的代码中,我不确定如何验证。(或者为什么)它工作了。当我运行代码时,它似乎工作了,但是为什么(在PyCharm中)前四个参数是灰色的,只有第五个是白色的?有没有一种方法可以使用这个回调函数来检查特定的证书错误?
这是我运行它时的输出
Certs are fine
Certs are fine
Certs are fine
b'HTTP/1.1 200 OK\r\nDate: Tue, 12 Apr 2016...etc
字符串
我假设每一行“证书都很好”验证了链中的每个证书?
import socket
from OpenSSL import SSL
HOST = "www.google.com"
PORT = 443
def verify_callback(connection, x509, errnum, errdepth, ok):
if not ok:
print("Bad Certs")
else:
print("Certs are fine")
return ok
context = SSL.Context(SSL.TLSv1_2_METHOD)
context.load_verify_locations("cacerts.pem")
context.set_options(SSL.OP_NO_SSLv2)
context.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback)
# create socket and connect to server
sock = socket.socket()
sock = SSL.Connection(context, sock)
sock.connect((HOST, PORT))
sock.do_handshake()
sock.sendall("GET / HTTP/1.1\r\n\r\n")
型
2条答案
按热度按时间sqserrrh1#
关于这个函数的pyOpenSSL文档非常少,但是这个函数是相应OpenSSL函数的 Package 器,它的文档是much better。
verify_callback函数用于控制设置SSL_VERIFY_PEER标志时的行为。它必须由应用程序提供,并接收两个参数:preverify_ok表示所讨论的证书的验证是否通过(preverify_ok=1)或未通过(preverify_ok=0)。x509_ctx是指向用于证书链验证的完整上下文的指针。
从最深的嵌套级别开始检查证书链(根CA证书)并向上工作到对等方的证书。在每个级别上,都会检查签名和颁发者属性。只要发现验证错误,错误号存储在x509_ctx中,并使用preverify_ok=0调用verify_callback。通过应用X509_CTX_store_* 函数verify_callback可以定位有问题的证书并执行其他步骤(请参见示例)。如果没有发现证书错误,则在前进到下一级别之前使用preverify_ok=1调用verify_callback。
verify_callback的返回值控制进一步验证过程的策略。如果verify_callback返回0,则验证过程立即停止,并处于“验证失败”状态。如果设置了SSL_VERIFY_PEER,则向对等端发送验证失败警报,并终止TLS/SSL握手。如果verify_callback返回1,则继续验证过程。如果verify_callback始终返回1,TLS/SSL握手将不会因验证失败而终止,并将建立连接。然而,调用进程可以使用SSL_get_verify_result(3)或通过维护由verify_callback管理的自己的错误存储来检索最后一个验证错误的错误代码。
如果未指定verify_callback,则将使用默认回调。其返回值与preverify_ok相同,因此如果设置了SSL_VERIFY_PEER,则任何验证失败都会导致TLS/SSL握手终止并发出警报消息。
文档中还有一个解释得很好的示例验证函数,用于检查被验证的链是否太长。如果链太长,则会记录错误,然后根据用户设置的值,回调返回0以导致验证失败,或者返回1(即忽略错误并进行验证)。
此外,this blog post有一个pyOpenSSL示例,它只是检查几个特定的错误,并在错误发生时验证失败。
eiee3dmh2#
有几件事需要澄清
VERIFY_FAIL_IF_NO_PEER_CERT
只是被忽略,特别是在客户端上下文中。因此它可以被删除。这只在服务器上下文中使用。ok
属性是一个“预验证代码”,如果预验证成功,ok=1,如果不成功,ok=0。强调预验证,验证尚未完成,这是此函数的目的。即,按原样返回它将有效地跳过验证(您可能永远不调用set_verify
,而是使用context.verify_mode
)。verify_callback
的第四个属性是证书深度,而不是errdepth
,没有错误,它只是让您知道这是哪个对等体证书的深度(请参见第4点)1.您的
verify_callback
将被多次调用,链中的每个对等证书调用一次。顺序是由openssl为您预先确定的,因此您不需要将subjectKeyIdentifier
与对等证书authorityKeyIdentifier
进行匹配,您还没有在此枚举中看到该对等证书。您可以相信openssl已为您完成了此检查,并且您所需要做的只是根据您的情况进行一些其他检查。又有什么意义呢?
我们正在进行我们自己的客户端证书验证,即,我们需要对照客户端知道是可信的信息来检查某些服务器响应信息,即,服务器响应是 * 可信的 *。
客户知道什么样的事情?
depth
(参见第3点),即深度3是可接受的,4及以上是不可接受的。我们可能知道我们有3个对等证书;根CA(在根信任存储中)、服务器证书签名者(您为证书付费的人)和服务器证书(拜特签名证书的CA生成)。因此,如果dpeth为3,则4或以上应返回0
sock.get_client_ca_list()
阅读,但如果您盲目使用它,它可能是一个重新路由到恶意服务器的请求,也就是说,为了使客户端证书身份验证具有任何安全特性,我们必须自己进行验证,而不考虑任何潜在的恶意影响。(如果发送了意外的值,则可能表示存在漏洞),并且您必须根据您所知道的信息而不是要求您信任的信息提供相应的证书(如果失败,则会安全地失败,并且不会连接到恶意服务器)