中间人攻击和SSL



我正在使用OpenSSL通过HTTPS连接到我的一台服务器。然而,我似乎无法让服务器验证在客户端工作。据我所知,不验证证书使我容易受到中间人攻击,但证书验证基本上是在证书中寻找匹配的ip地址和域名。(我说了很多错误的话,只是为了得到一些完整详细的回复:)

所以,如果它是我的服务器,我知道它的域名和ip地址,并且我正在使用SSL,我应该担心吗?再说一遍,中间的人不能解密我的ssl数据,插入恶意代码,重新加密,然后转发我的服务器证书吗?

最后,如果MITM攻击是一个问题,那么如果我先用另一个库检查证书以进行验证,然后使用OpenSSL而不进行验证,该怎么办?

还有其他可能发生的袭击吗?

但证书验证基本上是在证书中查找与匹配的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();

主机名验证

1.0.2之前的OpenSSL不会验证主机名。您必须从服务器的证书中提取主机名,并确保它是您访问的站点。如果您想借用代码,请查看源文件ssluse.c中的libcurl和验证过程。

如果您想根据规范执行手动验证,请参阅RFC 6125,在传输层安全性(TLS)上下文中使用X.509(PKIX)证书在互联网公钥基础结构中表示和验证基于域的应用程序服务标识。

为了完整起见,以下是如何获取证书的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 %dn", 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: %sn", utf8);

OPENSSL_free(utf8), utf8 = NULL;
}
else
{
fprintf(stderr, "  Unknown GENERAL_NAME type: %dn", entry->type);
}
}

} while (0);

if(names)
GENERAL_NAMES_free(names);

if(utf8)
OPENSSL_free(utf8);    
}

TLS客户端的OpenSSL wiki上有一个示例程序。它涵盖了服务器证书和链验证。您必须提供主机名验证的代码。


据我所知,不验证证书使我容易受到中间人攻击

如果您不执行验证,您还可以保存周期并选择像ADH这样的匿名方案。


所以,如果它是我的服务器,我知道它的域名和ip地址,并且我正在使用SSL,我应该担心吗。。。如果MITM攻击是一个问题,那么如果我先用另一个库检查证书以进行验证,然后使用OpenSSL而不进行验证呢。。。还有其他可能发生的袭击吗?

这里面有很多,没有单一的答案。由于您正在构建先验地了解服务器的客户端,请考虑转移到固定方案,这样您就可以放弃信任CA和DNS。例如,请参阅OWASP的证书和公钥固定。

此外,请阅读彼得·古特曼的《工程安全》。该书的重要部分讨论了PKI、SSL、TLS和人类行为中的系统性缺陷;以及如何改进您的安全态势。

Https基本上有两个验证:

i) 对服务器/客户端提供的证书进行相互信任存储的身份验证。为此,您必须为服务器/客户端实例实现密钥库/信任库,并将证书添加到密钥库,将受信任证书添加到信任库。这将完成证书验证。

仅供参考:密钥库和信任库

ii)另一方面,HTTPS将进行主机名验证,以防止中间人攻击。基本上,如果https url中指定的ip与证书提供的CommonName匹配,则此验证方法将返回"true"。如果您知道要信任哪个ip,则可以覆盖此验证方法。仅供参考:主机名验证

相关内容

  • 没有找到相关文章

最新更新