Man In the Middle Attacks and SSL [duplicate]

自古美人都是妖i 提交于 2019-12-21 06:26:38

问题


I am using OpenSSL to connect over HTTPS to one of my servers. However I cannot seem to get server verification to work on the client side. From what I understand, not verifying the certificate leaves me open to Man In the Middle attacks, but the certificate verification is basically looking for the ip address and domain name within the certificate to match. (I am saying a lot of things wrong just to get some full detailed responses :) )

So if it's my server, I know its domain name and ip address, and I am using SSL, should I be worried? Then again, couldn't the man in the middle decrypt my ssl data, insert malicious code, re-encrypt, and then forward me my server's certificate anyway?

Lastly, if MITM attacks are an issue, what if I check the certificate with another library first to verify, and then use OpenSSL just not with verification?

Are there any other attacks that could happen?


回答1:


but the certificate verification is basically looking for the ip address and domain name within the certificate to match

A certificate binds a public key to an entity (an identity like a person or organization). The binding occurs via a signature from an authority. Validation ensures the signature is present, and the entity presenting the certificate is who they say they are.

The way you identify the peer is through DNS names. If DNS is compromised, or the hostname checks are omitted, then the system crumbles.

So you need to trust both the certification authority and DNS. DNS does not provide authenticity assurances (or more correctly, clients don't use the security mechanisms), so you should consider DNS as untrusted input.


However I cannot seem to get server verification to work on the client side.

With OpenSSL, you need to do three things in the client. First, you need to ensure the server presents a certificate. Second, you need to verify the chain. Third, you need to perform hostname matching because OpenSSL doe not do it as part of chain verification.

Server Certificate

You need to verify the server has a certificate because some of the protocols and cipher suites don't require a certificate. You can do that with:

X509* cert = SSL_get_peer_certificate(ssl);
if(cert) { X509_free(cert); }
if(NULL == cert) handleFailure();

Chain Verification

This applies if you have a custom verify callback, but it works with both the standard verification built into OpenSSL and a custom verify callback. To get the verify result from chain verification, perform:

long res = SSL_get_verify_result(ssl);
if(!(X509_V_OK == res)) handleFailure();

Hostname Verification

OpenSSL prior to 1.0.2 does not verify hostnames. You will have to extract the hostnames from the server's certificate and ensure its the site you visited. If you want to borrow the code, take a look at libcurl and the verification procedure in source file ssluse.c.

If you want to perform the manual verification against a spec, see 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).

For completeness, here's how to fetch the DNS names present in the Subject Alternate Names (SAN) of a certificate. You can get the X509* from a function like SSL_get_peer_certificate.

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);    
}

There's a sample program on the OpenSSL wiki at TLS Client. It covers the Server Certificate and Chain Verification. You will have to provide the code for Hostname Verification.


From what I understand, not verifying the certificate leaves me open to Man In the Middle attacks

If you don't perform validation, you might as well save the cycles and choose an anonymous scheme like ADH.


So if it's my server, I know its domain name and ip address, and I am using SSL, should I be worried? ... if MITM attacks are an issue, what if I check the certificate with another library first to verify, and then use OpenSSL just not with verification? ... Are there any other attacks that could happen?

There's a lot to it, and there's no single answer. Since you are building clients that know the server a priori, consider moving to a pinning scheme so you can forgo trusting CAs and DNS. See for example, OWASP's Certificate and Public Key Pinning.

Also, read Peter Guttman's Engineering Security. A significant portion of the book discusses the systemic defects in PKI, SSL, TLS and human behavior; and how you can improve your security posture.




回答2:


Basically there are two verification's for Https:

i) Authenticating certificates provided by the sever/client against each others trust stores. For this you have to implement keystore/truststore for server/client instances and add your certificates to keystore and trusted certificates to trust store. This will accomplish certificate verification.

FYI: Keystore and truststore

ii) On other hand HTTPS will do hostname verification to prevent man in the middle attacks. Basically this verification method will return "true" if ip specified in the https url matches with CommonName presented by the certificate. If you know which ip's to trust you can override this verify method. FYI: Hostname verification



来源:https://stackoverflow.com/questions/21969536/man-in-the-middle-attacks-and-ssl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!