中间人攻击和SSL

这个问题在这里已经有了答案:

  • SSL和中间人误解5个​​答案

  • 但证书验证基本上是寻找证书内的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不验证主机名。 您必须从服务器的证书中提取主机名并确保其访问的网站。 如果您想借用代码,请查看libcurl和源文件ssluse.c的验证过程。

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

    为了完整起见,下面介绍如何获取证书的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 Client上的OpenSSL wiki上有一个示例程序。 它涵盖了服务器证书和链式验证。 您将必须提供主机名验证的代码。


    根据我的理解,不验证证书让我开放给中间人攻击

    如果您不执行验证,则最好保存周期并选择匿名方案,如ADH


    所以如果它是我的服务器,我知道它的域名和IP地址,并且我使用SSL,我应该担心吗? ......如果MITM攻击是一个问题,如果我先用另一个库检查证书来验证,然后使用OpenSSL而不是验证,那该怎么办? ...有没有可能发生的其他攻击?

    这有很多,而且没有单一的答案。 由于您建立了认识服务器的客户端,因此可以考虑转向固定方案,这样您就可以放弃信任CA和DNS。 例如,请参阅OWASP的证书和公钥密码。

    另外,请阅读Peter Guttman的工程安全。 本书的重要部分讨论了PKI,SSL,TLS和人类行为中的系统性缺陷; 以及如何改善您的安全状况。


    基本上有两个验证的Https:

    i)鉴别由服务器/客户端提供的针对彼此信任存储库的证书。 为此,您必须为服务器/客户端实例实施密钥库/信任库,并将证书添加到密钥库和可信证书以信任商店。 这将完成证书验证。

    供参考:密钥库和信任库

    ii)另一方面,HTTPS将执行主机名验证以防止中间人受到攻击。 基本上,如果https URL中指定的IP与证书颁发的CommonName匹配,此验证方法将返回“true”。 如果您知道哪个ip要信任,则可以覆盖此验证方法。 FYI:主机名验证

    链接地址: http://www.djcxy.com/p/21729.html

    上一篇: Man In the Middle Attacks and SSL

    下一篇: Libgdx use ScreenUtils asynchronously and don't stop the game loop