Man In the Middle Attacks and SSL
This question already has an answer here:
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 %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);
}
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.
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
链接地址: http://www.djcxy.com/p/21730.html上一篇: SSL如何从MITM攻击中获得安全保护?
下一篇: 中间人攻击和SSL