如何用Python复现openssl s_client -connect ip_addr:port -servername url命令
用Python复现
openssl s_client -connect ip_addr:port -servername url的实现 这条OpenSSL命令的核心行为是:与指定的ip_addr:port建立TCP连接,在TLS握手阶段通过SNI(Server Name Indication)指定目标域名url,验证服务器证书合法性,并完成握手获取相关TLS信息。以下是匹配该行为的Python实现:
import socket from OpenSSL import SSL def openssl_s_client(ip_addr, port, servername): # 初始化兼容TLSv1.2/TLSv1.3的SSL上下文,匹配OpenSSL默认配置 context = SSL.Context(SSL.TLS_METHOD) # 加载系统默认CA证书,覆盖常见系统路径 ca_paths = [ '/etc/ssl/certs/ca-certificates.crt', '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem', '/usr/local/etc/openssl/cert.pem' ] for ca_path in ca_paths: try: context.load_verify_locations(cafile=ca_path) break except Exception: continue # 开启严格证书验证,对应OpenSSL默认验证规则 context.set_verify(SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, lambda *args: None) # 建立TCP连接 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) sock.connect((ip_addr, port)) # 包装为SSL连接并设置SNI ssl_conn = SSL.Connection(context, sock) ssl_conn.set_tlsext_host_name(servername.encode('utf-8')) # 执行TLS握手并处理结果 try: ssl_conn.do_handshake() print("TLS握手成功") # 输出服务器证书核心信息,贴近OpenSSL输出格式 peer_cert = ssl_conn.get_peer_certificate() print("\n服务器证书信息:") print(f"主题: {peer_cert.get_subject()}") print(f"颁发者: {peer_cert.get_issuer()}") print(f"有效期起始: {peer_cert.get_notBefore().decode('utf-8')}") print(f"有效期结束: {peer_cert.get_notAfter().decode('utf-8')}") # 验证证书链完整性 verify_result = ssl_conn.verify_certificate() print("\n证书验证通过" if verify_result is None else f"\n证书验证失败: {verify_result}") except SSL.Error as e: print(f"TLS握手或证书验证失败: {str(e)}") finally: ssl_conn.shutdown() sock.close() # 使用示例 if __name__ == "__main__": openssl_s_client(ip_addr="1.1.1.1", port=443, servername="cloudflare.com")
关键匹配点说明:
- 区分IP与SNI:连接目标为
ip_addr,SNI字段单独设置为servername,完全对应原命令的参数逻辑 - 证书验证:开启
SSL.VERIFY_PEER强制验证服务器证书,对齐OpenSSL默认的严格验证行为 - 系统CA加载:遍历常见系统CA路径,确保使用与OpenSSL一致的信任根证书
- 信息输出:补充握手状态、证书核心信息和验证结果,贴近原命令的输出内容
内容的提问来源于stack exchange,提问作者Arindam Choudhury
相关产品推荐
相关产品推荐

