Introduction
When calling a Web Service using HTTPS and SSL, Host Verification and Peer Verification are to be handled for security. This article shows and explains how Peer Verification can be done successfully when calling a Web Service via HTTPS that is secured by SSL.
Using the Code
Mostly Web Services are hosted on HTTPS and are secured by SSL so others can't use it. Many times when we surf an HTTPS site, we get a certificate dialog asking us to trust the provider. This is the Server Certificate that is sent by the web server. We accept the certificate and proceed ahead. In desktop applications, when we perform a similar task like accessing a Web Service which uses HTTPS and SSL, we can't receive any dialog to trust the certificate and there comes the problem.
This can be easily achieved by creating our own CertificatePolicy
class that implements the ICertificatePolicy
interface. For instance, such a class could be written as:
public class MyPolicy : ICertificatePolicy {
public MyPolicy() {
}
public bool CheckValidationResult(ServicePoint srvPoint,
X509Certificate certificate,
WebRequest request, int certificateProblem)
{
return true;
}
}
And can set:
ServerCertificateValidationonCallback = MyPolicy();
The above code can also be written using a delegate of System.Net.ServicePointManager.ServerCertificateValidationonCallback
.
System.Net.
ServicePointManager.ServerCertificateValidationCallback = {
(Object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors) {
return true;
}
};
The above code accepts the Server Certificate (the dialog that pops up on the browser to trust the provider). It implicitly returns true
, that means it accepts any server certificate and proceeds ahead accessing the Web Service.
This is so simple and easy. But if SSL is specially meant for security and cryptography and can be bypassed so easily, then what sense does SSL make? Nothing, right?
When our client verifies this server certificate against any certificate file, i.e., without verifying the verify certificate to verify the server certificate, the client can't access any Web Service from the provider. This is like providing a password or authenticating password. Without actually authenticating, a Web Service that gives and takes data should be easy to fake. Thus we need to verify the Server Certificate using a "Right" version of the verification certificate*. Verification Certificate is just a CA file that compares the server certificates data. If both match, it returns true
and lets us access Web Services, else it returns false
and doesn't let us access a Web Service and its confidential data.
Note *: The certificate used to verify is not the same as Client Certificate, both are different and so are their roles. A Client Certificate is passed to the server if the server needs a Client Certificate. It can be set using the request.ClientCertificates
property.
Now comes the point: how do we verify that the server certificate is correct or the server certificate matches the verify certificate? Fake users can change the Server Certificate or the certificate used to verify, so we got to take care on both sides.
Here is the code that helps you to accept the server certificate and also verify the certificate against a CA file.
Remember: Acceptance of Server Certificate code should be set only once in the whole application life cycle. And it will be called automatically whenever a request is made. So for ease of coding, we will separate the SSL Certificate part with the request part.
Here is the code to set and handle the SSL Certificate part:
private X509Certificate2 verifyCert = null;
private void setSSLCertificate() {
veriftCert = new X509Certificate2("ca_verify.crt");
ServicePointManager.ServerCertificateValidationCallback += new
System.Net.Security.RemoteCertificateValidationCallback(
customCertificateValidation);
}
public bool customCertificateValidation(Object sender,
X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
switch(sslPolicyErrors) {
case RemoteCertificateChainErrors:
case RemoteCertificateNameMismatch:
case RemoteCertificateNotAvailable:
break;
}
return verifyCert.Verify();
}
That's it. This is how Peer Verification is handled and should be taken care of without any hard coding or comparing in code.
Now whenever any request is performed, first customCertificateValidation()
will be called and if that returns true
, then the request will be able to proceed, else a WebException
will be caught.
private void SendPost(String post_data) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
<a href="https://ae-q01.com/">https:
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
byte[] postBytes = Encoding.ASCII.GetBytes(psot_data);
Stream requestStream = null;
try {
request.ContentLength = postBytes.Length;
requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
} catch (WebException we) {
} catch(Exception e) {
} finally {
if (requestStream != null)
requestStream.Close();
}
}
Don't forget to call setSSLCertificate()
at the start of the application or whenever appropriate before calling any Web Service.
That's all for SSL Peer Verification. I am sure this will definitely help more developers who actually cross-check SSL verification and not just accept the server certificate blindly.
Let me know how it works.
Points of Interest
I wanted to perform SSL Peer Verification. I Googled and asked questions in forums a lot, but could only find how to accept a Server Certificate, not how to verify it, which is most important when you are accessing a Web Service that implements SSL security. Finally, when I figured out the solution, I thought about sharing it with all to make others' work a bit easier.
History
This is my first article on CodeProject. If I have made any mistakes, kindly let me know of it; any tips for improvements are appreciated.