中间人攻击和 SSL [重复]
Posted
技术标签:
【中文标题】中间人攻击和 SSL [重复]【英文标题】:Man In the Middle Attacks and SSL [duplicate] 【发布时间】:2014-03-25 00:57:21 【问题描述】:我正在使用 OpenSSL 通过 HTTPS 连接到我的一台服务器。但是我似乎无法让服务器验证在客户端工作。据我了解,不验证证书会让我容易受到中间人攻击,但证书验证基本上是在证书中寻找 IP 地址和域名来匹配。 (我说了很多错误的事情只是为了得到一些完整的详细回复:))
所以如果它是我的服务器,我知道它的域名和 IP 地址,而且我正在使用 SSL,我应该担心吗?话说回来,中间的人就不能解密我的ssl数据,插入恶意代码,重新加密,然后再转发我的服务器证书吗?
最后,如果 MITM 攻击是一个问题,如果我先用另一个库检查证书以进行验证,然后使用 OpenSSL 而不进行验证呢?
还有其他可能发生的攻击吗?
【问题讨论】:
您需要了解公钥和签名。 en.wikipedia.org/wiki/Public_key_infrastructure SSL and man-in-the-middle misunderstanding 和 ***.com/questions/11760901/… 的可能重复 【参考方案1】:但是证书验证基本上是在证书里面找ip地址和域名来匹配
证书将公钥绑定到实体(个人或组织等身份)。绑定通过权威机构的签名进行。验证确保签名存在,并且出示证书的实体就是他们所说的那个人。
您识别对等方的方式是通过 DNS 名称。如果 DNS 被破坏,或者主机名检查被忽略,那么系统就会崩溃。
因此您需要信任两者证书颁发机构和 DNS。 DNS 不提供真实性保证(或者更准确地说,客户端不使用安全机制),因此您应该将 DNS 视为不受信任的输入。
但是我似乎无法让服务器验证在客户端工作。
使用 OpenSSL,您需要在客户端中做三件事。首先,您需要确保服务器提供证书。其次,您需要验证链。第三,您需要执行主机名匹配,因为 OpenSSL 不会将其作为链验证的一部分。
服务器证书
您需要验证服务器是否有证书,因为某些协议和密码套件不需要证书。你可以这样做:
X509* cert = SSL_get_peer_certificate(ssl);
if(cert) X509_free(cert);
if(NULL == cert) handleFailure();
链验证
这适用于您有自定义验证回调的情况,但它适用于 OpenSSL 内置的标准验证和自定义验证回调。获取链式验证的验证结果,执行:
long res = SSL_get_verify_result(ssl);
if(!(X509_V_OK == res)) handleFailure();
主机名验证
OpenSSL 1.0.2 之前的版本不验证主机名。您必须从服务器的证书中提取主机名,并确保它是您访问的站点。如果要借用代码,请看libcurl和源文件ssluse.c
中的验证程序。
如果您想根据规范执行手动验证,请参阅 RFC 6125,Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)。
为了完整起见,以下是获取证书的Subject Alternate Names
(SAN) 中存在的 DNS 名称的方法。您可以从 SSL_get_peer_certificate
之类的函数中获取 X509*
。
void print_san_name(X509* const cert)
GENERAL_NAMES* names = NULL;
unsigned char* utf8 = NULL;
do
if(!cert) break; /* failed */
names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
if(!names) break;
int i = 0, count = sk_GENERAL_NAME_num(names);
if(!count) break; /* failed */
for( i = 0; i < count; ++i )
GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
if(!entry) continue;
if(GEN_DNS == entry->type)
int len1 = 0, len2 = -1;
len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
if(!utf8) continue;
len2 = (int)strlen((const char*)utf8);
/* If there's a problem with string lengths, then */
/* we skip the candidate and move on to the next. */
/* Another policy would be to fail since it probably */
/* indicates the client is under attack. */
if(len1 != len2)
fprintf(stderr, "Strlen and ASN1_STRING size do not match
"(embedded null?): %d vs %d\n", len2, len1);
/* Potential problem with the DNS name. Skip it */
/* TODO: test against IDNs */
OPENSSL_free(utf8), utf8 = NULL;
continue;
/* Perform matching here */
fprintf(stdout, " SAN: %s\n", utf8);
OPENSSL_free(utf8), utf8 = NULL;
else
fprintf(stderr, " Unknown GENERAL_NAME type: %d\n", entry->type);
while (0);
if(names)
GENERAL_NAMES_free(names);
if(utf8)
OPENSSL_free(utf8);
在 OpenSSL wiki TLS Client 上有一个示例程序。它涵盖了服务器证书和链验证。您必须提供主机名验证的代码。
据我了解,不验证证书会使我容易受到中间人攻击
如果你不执行验证,你还不如保存循环并选择像ADH
这样的匿名方案。
所以如果它是我的服务器,我知道它的域名和 IP 地址,而且我正在使用 SSL,我应该担心吗? ...如果 MITM 攻击是一个问题,如果我首先使用另一个库检查证书以进行验证,然后使用 OpenSSL 而不进行验证怎么办? ... 是否还有其他可能发生的攻击?
有很多问题,而且没有单一的答案。由于您正在构建了解服务器的客户端先验,因此请考虑迁移到固定方案,以便您可以放弃信任 CA 和 DNS。例如,请参阅 OWASP 的 Certificate and Public Key Pinning。
另外,请阅读 Peter Guttman 的 Engineering Security。本书的很大一部分讨论了 PKI、SSL、TLS 和人类行为中的系统缺陷;以及如何改善您的安全状况。
【讨论】:
【参考方案2】:Https基本上有两种验证方式:
i) 对服务器/客户端提供的证书与彼此的信任存储进行身份验证。 为此,您必须为服务器/客户端实例实施密钥库/信任库,并将您的证书添加到密钥库并将受信任的证书添加到信任库。这将完成证书验证。
仅供参考:Keystore and truststore
ii) 另一方面,HTTPS 将进行主机名验证以防止中间人攻击。基本上,如果 https url 中指定的 ip 与证书提供的 CommonName 匹配,则此验证方法将返回“true”。如果您知道要信任哪个 ip,则可以覆盖此验证方法。 仅供参考:Hostname verification
【讨论】:
Common Name
已弃用。 DNS 名称应出现在 Subject Alternate Name
(SAN) 中。
是的,它已被弃用,但仍被广泛使用。更好的方法是先检查 SAN,如果它不存在,然后去 CN。
如果存在 CN,那么它也必须列在 SAN 中。见Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates。它也可能出现在RFC 6125 中(但我没有检查)。
@noloader,准确地说,如果有任何 SAN DNS 条目,则必须忽略 Subject DN 中的 CN(措辞不同,但 RFC 6125, section 6.4.4 和 RFC 2818 中的原则相同)。
@Bruno - CN 是与主题 DN 不同的字段。 Common Name 的 OID 为 2.5.4.3,并在 X.520 中分配。在 OpenSSL 中,它的 OBJ_commonName
。 OpenSSL 中的专有名称是 OBJ_distinguishedName
。以上是关于中间人攻击和 SSL [重复]的主要内容,如果未能解决你的问题,请参考以下文章
ReactNative 中使用SSL Pinning防止中间人攻击