I'm building a .net app, and I'd like to make the web calls secure enough that its not easy to monitor the the traffic thru something like fiddler. I'd like to be able to know that the certificate from the server isn't as expected and then never send out a full request with the request data.
Twitter's iOS app does this. Someone I think would have to somehow make a copy of the twitter's https certificate and make that fiddler's certificate. I havn't done it myself, but i think that's how I understand it. What you see in fiddler is that the tunnel has been created, but no request was actually set out. Its same scenario when you don't have the fiddler's HTTPS certificate installed on the device and you open a browser to google.com / a tunnel is created and then the browser knows 'uhoh untrusted server' and displays a message to the user. I'd like to just make it more secure and only allow 1 certificate / my server's certificate.
Make sense? I think i figured out how to do it with making a separate full dummy request / but thats not ideal.
What you're asking is "How do I implement certificate pinning in my client application?"
The way to do that would be to attach a validation callback on the Service Point responsible for making your HTTPS requests. Your validation callback would override the default behavior ("Accept any certificate trusted by Windows") and would instead validate that the received certificate is EXACTLY the one you expect.
Now, before you go that route, keep in mind a few things:
An attacker with Admin or Debug privileges can easily change your code in memory to remove your validation. This is called the "Trusted client" problem.
Your validation will break if the code is ever run in a corporate environment where an security appliance is doing HTTPS inspection (e.g. BlueCoat, ISA TMG, etc)
Your validation will prevent "certificate agility" -- if the server cert needs to change, you will need to update the application. If you ever want to use a load-balanced configuration with multiple certificates, or a public HTTPS CDN, you would need to update your validation logic.
Related
is it possible to connect to SSL via a web client so that it can not be decrypted later by programs like Charles or Fiddler?
My Problem is, I have a Application white a Login, if the Password and Username from a User is correct, the Server returns Success. But if the user reads the response, he can easily fake it white Charles and „bypass“ my Login.
That depends on what you are trying to do, and why. Fiddler decrypts traffic by installing a root certificate on your computer, and then uses that basically make a man in the middle attack. Or in other words, with the users permission it subverts the security model of windows. So if you rely on windows to validate the SSL certificate used, there is nothing you can do about it.
If you only have one server that you really want toconnect to, you can validate that the certificate you are getting is the one and only one that you do indeed trust. This is known as certificate pinning.
If you are worried about someone storing the traffic and later using Fiddler to decrypt it, you can stop worrying.
So here is my scenario:
There is a website that needs a cert for client authentication, unfortunately we cannot provide that cert to everyone. Also, protecting the website with the cert is not something we can change.
More details if above statements are somewhat confusing:
Website X (Not developed by me) needs a client authentication cert to authenticate
I can have the cert installed on a VM which only i have permissions to login to.
I want others to access Website X but cant provide the cert to them
Is there a feasible way to do this?
Here is what i think might work but not sure how to do and even if thats possible:
Host a website (Website Y) on the server VMWhen someone opens that website : The ASP.Net code reads the cert calls into the Website XPresent the cert for client authentication to website X
Gets the response
Shows the response as it is to the user?
But the problem with this approach is the website might just return the raw html and may have its own custom code doing something when people selects a drop down or something?How do i address that?
Anyone has an idea on how i can achieve this?
My Apologies if i am not clear or if i shouldn't be asking such questions on the forum.
You can use a reverse proxy like nginx to solve this issue. Run nginx on your server VM and listen for connections on port 80. On the upstream side, use proxy_pass to connect to 'website X'. Present the certificate as part of the SSL handshake to perform certificate validation. Once the validation is complete, the rest of session will proceed normally.
With this approach, you shouldn't have to worry about 'website X' changing, since nginx will simply proxy all the responses back to the client.
I asked a question here a while back on how to hide my http request calls and make them more secure in my application. I did not want people to use fiddler 2 to see the call and set up an auto responder. Everyone told me to go SSL and calls will be hidden and information kept safe.
I bought and installed an SSL Certificate and got everything set up. I booted up fiddler 2 and ran a test application that connect to an https web service as well as connected to an https php script.
Fiddler 2 was able to not only detect both requests, but decrypt them as well! I was able to see all information going back and fourth, which brings me to my question.
What is the point of having SSL if it made zero difference to security. With or without SSL I can see all information going back and fourth and STILL set up an auto responder.
Is there something in .NET I am missing to better hide my calls going over SSL?
EDIT
I am adding a new part to this question due to some of the responses I have received. What if an app connects to a web service to login. The app sends the web service a username and a password. The web service then sends data back to the app saying good login data or bad. Even if going over SSL the person using fiddler 2 could just set up an auto responder and the application is then "cracked". I understand how it could be useful to see the data in debugging, but my question is what exactly should one do to make sure the SSL is connecting to the one it was requesting. Basically saying there cannot be a middle man.
This is covered here: http://www.fiddlerbook.com/fiddler/help/httpsdecryption.asp
Fiddler2 relies on a "man-in-the-middle" approach to HTTPS interception. To your web browser, Fiddler2 claims to be the secure web server, and to the web server, Fiddler2 mimics the web browser. In order to pretend to be the web server, Fiddler2 dynamically generates a HTTPS certificate.
Essentially, you manually trust whatever certificate Fiddler provides, the same will be true if you manually accept certificate from random person that does not match domain name.
EDIT:
There are ways to prevent Fiddler/man-in-the-middle attack - i.e. in custom application, using SSL, one can require particular certificates to be used for communication. In case of browsers, they have UI to notify user of certificate mismatch, but eventually allow such communication.
As a publicly available sample for explicit certificates, you can try to use Azure services (i.e. with PowerShell tools for Azure) and sniff traffic with Fiddler. It fails due to explicit cert requirement.
You could set up your web-service to require a Client-side certification for SSL authentication, as well as the server side. This way Fiddler wouldn't be able to connect to your service. Only your application, which has the required certificate would be able to connect.
Of course, then you have the problem of how to protect the certificate within the app, but you've got that problem now with your username & password, anyway. Someone who really wants to crack your app could have a go with Reflector, or even do a memory search for the private key associated with the client-side cert.
There's no real way to make this 100% bullet proof. It's the same problem the movie industry has with securing DVD content. If you've got software capable of decrypting the DVD and playing back the content, then someone can do a memory dump while that software is in action and find the decryption key.
The point of SSL/TLS in general is so that the occasional eavesdropper with Wireshark isn't able to see your payloads. Fiddler/Burp means that you interacted with the system. Yes, it is a very simple interaction, but it does require (one) of the systems to be compromised.
If you want to enhance the security by rendering these MITM programs useless at such a basic level, you would require client certificate authentication (2-way SSL) and pin both the server and client certificates (e.g. require that only the particular certificate is valid for the comms). You would also encrypt the payloads transferred on the wire with the public keys of each party, and ensure that the private keys only reside on the systems they belong to. This way even if one party (Bob) is compromised the attacker can only see what is sent to Bob, and not what Bob sent to Alice.
You would then take the encrypted payloads and sign the data with a verifiable certificate to ensure the data has not been tampered with (there is a lot of debate on whether to encrypt first or sign first, btw).
On top of that, you can hash the signature using several passes of something like sha2 to ensure the signature is 'as-sent' (although this is largely an obscure step).
This would get you about as far in the security way as achievable reasonably when you do not control (one) of the communicating systems.
As others mentioned, if an attacker controls the system, they control the RAM and can modify all method calls in memory.
I am wondering how is Google able to show messages like Cannot connect to the real mail.google.com or similar? Are the IP addresses of Google servers simply hard-coded within Chrome or is it possible to do a similar thing? This could help making sure clients are not visiting phishing or scams websites.
This errors only shows when trying to access Google related websites, nothing else.
Here is a sample of what Google Chrome shows when trying to connect to Gmail without providing the proxy credentials.
PS: I usually use C# & ASP.NET. I am open to suggestions.
EDIT :
Following the answer from SilverlightFox, is there any way to "request" the pinning of my website certificate? And/Or how to add it to the "STS preloaded list"?
As #Ted Bigham mentioned in comments, this will be achieved via Certificate pinning:-
One way to detect and block many kinds of MITM attacks is "certificate pinning", sometimes called "SSL pinning". A client that does certificate pinning adds an extra step to the normal TLS protocol or SSL protocol: After obtaining the server's certificate in the standard way, the client checks the server's certificate against trusted validation data. Typically the trusted validation data is bundled with the app, in the form of a trusted copy of that certificate, or a trusted hash or fingerprint of that certificate or the certificate's public key. For example, Chromium and Google Chrome include validation data for the *.google.com certificate that detected fraudulent certificates in 2011. In other systems the client hopes that the first time it obtains a server's certificate it is trustworthy and stores it; during later sessions with that server, the client checks the server's certificate against the stored certificate to guard against later MITM attacks.
From What is certificate pinning?:-
some newer browsers (Chrome, for example) will do a variation of cerficiate pinning using the HSTS mechanism. They preload a specific set of public key hashes into this the HSTS configuration, which limits the valid certificates to only those which indicate the specified public key.
HTTP Strict Transport Security (HSTS) is a technology that is implemented via a HTTP response header (sent via HTTPS only) that tells a browser to "remember" that a website is to only be accessed via HTTPS for a period of time. If HSTS is set on www.example.com and the user visits http://www.example.com before max-age has expired, the browser will request https://www.example.com instead and no request will be sent via plain HTTP. HSTS requires that the user has already visited the site in order to have received the header, however a workaround has been implemented by Google in their Chrome browser code:
Google Chrome and Mozilla Firefox address this limitation by implementing a "STS preloaded list", which is a list that contains known sites supporting HSTS. This list is distributed with the browser so that it uses HTTPS for the initial request to the listed sites as well.
Update following question edit
Following the answer from SilverlightFox, is there any way to "request" the pinning of my website certificate? And/Or how to add it to the "STS preloaded list"?
According to this blog post you should contact the browser developers to be included in the HSTS list and have your public key (or CA's) pinned in the browser:
is this domain HSTS-preloaded in Chrome? For now it is hardcoded in the binary and will hopefully grow. You can contact Chromium to have your site included in that list.
and
So right now, the only solution to pin public keys of CAs signing your website certificates would be to contact Chromium team to be included in the code.
The only way to fight the man-in-the-middle is to have some pre-shared knowledge. In this case those are hardcoded certificates of a couple of root authorities that your browser trusts. These root certificates are used by their authority to sign certificates of other authorities which in turn become trustworthy too. A chain of trust is built until you hit the certificate of mail.google.com.
When you go to mail.google.com you are automatically redirected to the HTTPS (note the S!) version of the site. HTTPS means certificates. Your browser downloads the certificate of that site and inspects if the signing chain is rooted by some of the authorities your browser trusts. If not: Big fat warning! Possibly man-in-the-middle spoof going on!
Another thing that might happen is that the redirect from HTTP to HTTPS fails because some firewall between you and Google blocks HTTPS. That might be the warning you are getting.
I'm creating a Windows Forms application that uses an embedded WebBrowser control to view an intranet web page. The page is provided via https, using a self-signed certificate. I want the certificate to be valid in the context of my application, but don't want to mess with the client's machine itself (by permanently installing a trusted certificate).
Is there any way to programmatically trust a certificate for the lifetime of an application, rather than for the system as a whole?
You can certainly do that. But you may need to do it in two steps. Make a https request first and get the Server certificate and create a truststore on the fly and import the certificate into the truststore. This would be a onetime activity. You may cache this truststore to the filesystem so that you need not do this everytime. Make another https request and use this truststore for validating the subsequent https requests that you will make.