How to prevent just anyone sending a request to my web service - c#

I have an app in C# which serializes an object into xml into a http stream to my server. The server has some php which runs a stored procedure in mysql with the xml data as its only parameter.
The problem is that someone could very easily just send up an xml of the same format with a whole lot of entires that would ruin the database with crap data. What are my options to prevent this from happening?
I'm pretty new to web requests so I don't even know where to start.

We require a username and password to be supplied to all input parameter lists which is validated against our back-end user login system before a request is processed. Low tech, but works for us.

You should use some form of authentication and authorization. In SOAP based services there's the WS-Security extension. Here's another article on MSDN that explains how this works. However I have no idea what is the support for those standards on the PHP side. If you are using some custom protocol you could simply require a username/password to be sent along with the request and verified on the server side.

Are you planning on having this client out-there in public hands on the internet? If so it may be impossible to prevent people using different software as they could always reverse engineer the application to find out what security mechanism you are using. As a result your only defence will be to validate the data thoroughly on the server.
You might get around this by modifying the client to require a user name and password that gets sent with data to your server using HTTPS, that way at least you know who did the damage. If however you have a more closed audience you could use some kind of client certificate system or IP filtering.

Our solution (and we're hopelessly naive in this respect) is that we generate a unique key per session on the server in a non-uniform manner (ie. it is difficult to predict what the "next" value would be), and give that to the client code as part of its login process. It is then required to pass that value back to use for each request as the first parameter.
This ensures that:
Logging out invalidates the authentication key
Username and password is not sent in cleartext for the web service requests
This does not ensure that:
Only our application code can talk to the server (the user might intercept the request, copy the key, and generate his own requests, as long as the key is still considered valid.)
What you're going to find is that as long as code on the users machine is talking to your server, you have no control over the code on that machine, only the code on that server. So if the users machine is sending you requests originating from a different program, that looks just like they would and should if your code generated them, you're going to have a hard time figuring out that this is what is happening.

Related

"Safely" store (on client side) tokens for reuse?

I'm trying to create a desktop application that will send updates to a web-service I am developing.
Ideally, the application would be configured only once and deployed to a network share. When configuring the application, the user will enter a password that is used to authenticate within the web-service. After that, a token will be created to be used on future connections.
This would allow any computer with access to the network share (even if it is not the computer in which the app was configured) to just run the application (which will connect to the web-service) without entering any credentials (because the token has been saved).
Question is: How should I protect this token?
I know that storing it client-side will never be completely secure, but I want to make it as hard as possible for someone to gain access to the plaintext token.
I'm looking for an answer that, preferably, does not depend on any operational-system resource (since the application can be executed from different devices).
Assume I have full control over the application and the web-server
I'm developing the console application using C#, but I believe this to be more of a theoretical question (not tied to any specific language)
Here are a few things I've tried/thought about:
Serializing the token using something like C#'s SecureString and storing it on a file: it's the best I've come with. But obviously, very trivial to reverse if someone gains access to the key file.
This answer suggests to use the Windows Data Protection API (DPAPI) (in C#, the ProtectedData class), but apparently, this would allow only the user who initially saved the credentials to access them, which would not work because I have to access the protected data from multiple users/devices.
Pass the token as a parameter to the application: this just changes where I'm going to store the token (on a batch file or OS task that calls the program, for example), but I don't think it makes it any more secure.
Since the user is not an administrator of the machine (this is a fundamental hypothesis), there are many ways to hide things from her.
What I propose is:
Make sure the main app runs under different credentials than the
logged user, a "special user".
Write another end-user app, just for setup, that talks to this app (using any interprocess communication you see fit, TCPIP, whatever, maybe secure but I wouldn't care too much at this). This app is used only to gather credentials and send them to the first app
Now, the main app can write the token anywhere the logged user has no access, but I recommand protected data because it's very easy to use
Here is some graphical explanation:
Since data encrypted using protected data (Windows Data Protection) can only be decrypted by the Windows user who has encrypted it, the logged on user will not be able to read the "special user" data.
I would suggest using JWT.
Your server would generate a Token after a successful authentication. The token would be sent to the client. Each subsequent call to the server would send the token in the header to the server. The server would then verify the token. If verified, the server knows the client has been authenticated.
No need to store usernames/passwords on the client.
There is no bullet-proof way to solve this problem, the client finally needs access to the server, and so can do an attacker with enough privileges on the client.
What you describe is a typical scenario for the OAuth2 protocol, since you have control over the server. With OAuth2 you cannot avoid the need to store a secret on the client, but by exchanging it for a token, you can protect the original password and you can guarantee that the token is very strong (user passwords tends to be weak).
To store the token/password on the client one could encrypt it before storage, but this immediately raises the question of where to store the key for this encryption. An attacker could extract it from the client. There are some ways, which can improve security for the key storage.
Depending on your situation you may consider the usage of a Hardware security module (HSM).
You can use an OS specific key-store like you mentioned with the data-protection-api. A key-store can only help protecting a key, because it has the support of the operating system (I think this is what you meant with SO-independend?). With the DPAPI you can not only restrict access to the logged in user, rather you can restrict it to the local machine. Key-stores are available on other operating systems as well.
Instead of storing the password on the client, it can be requested from the user each time the client starts. This can be reduced to the startup of the device, the password can then be hold exclusively in the memory.
Well, you can't protect anything in client side. Once it's there, anyone with privileged access can see it.
What you can do is make this piece of information useless without something else.
The best approach here would be to store a kind of public key in the client side and use this public key to create a hash to authenticate the user via webservice.
When the user configure the application, the server send this public key that the application stores locally. When the application call the server it will create a hash using this public key and a private key that is only known by the application and the server. Then the server can check if the hash is correct using its private key.
To improve security, you can use a timestamp in the hashing too, so it will change overtime and prevent the reuse of keys. Or it could send a new public key with the each webservice answer.
I would suggest you to use IdentityServer4 as it provides RFC compliant protocols and depending on the GrantType a client application is given in your context your desktop application.
Even though the token is in plaintext it is protected in the webservice where the Access Control(Issuer of token) validates that a token is being received from the correct client by checking the Origin in the clients request and the one stored in the database.

How to protect a webservice in .NET from outer world except a single application?

I have a website with architecture (HTML + JSON + webservice (C#)) installed on a server which is open to internet. Now, my webservices are opened to the whole world so anyone can access it and may try to malfunction.
What I would like to do is to make my webservice to work limitedly to my application only instead of other applications. Like when a website is on open internet but its web services are private to the website only and not to the whole internet.
Right now there's a big data security concern.
The primary way would be to add some sort off login/account system. That then of course needs to be managed and all that.
The other posters' approaches of just putting some key or certificate into it will only work if it is not that important. Anything you store in the application is invariably reverse-engineerable. So if someone is decently determined, that level of protection is easy enough to overcome.
If the number of possible consumers is small enough, another approach might work:
Make it only reachable from the local network (IP adress ranges associated with Local Networks). Then use a approach like VPN so clients can connect to you local Network. Basically you move the account part to another System. But such a approach can have security issues, especially if that VPN connection goes straight into your DMZ.
In the end it really depends how critical that is. Security exists in flavors from "anybody reading his computers network traffic with Wireshark can break it" to "reasonably secure for high grade private data". We have no idea what level of security you need and what level of skill you have, so we can not give a useful answer just yet.
I would suggest you look into using Certificates to encrypt your webservice, then your application will call it using that same loaded certificate. Only an entity with your server certificate key will be able to decrypt your calls.
Accessing a web service and a HTTP interface using certificate authentication
Calling a rest api with username and password - how to
Edit: If you cannot use the certificate method because you are calling from say the browser directly, you might want to look at an authorization cookie of some sort, So that lets say on your login pages the request might be open to public but on all subsequent request you require authentication and once the user has logged in you rely on the authorization cookie or token to validate whether they have access.
Another method: IdentityServer for instance has provider token stores, so you can request a token from the store, then only with the issued token you can access the API. And your API would also then query the store to check the token is valid.
I found a very easy solution to it.. by getting ip address of the remote client's in web service i can validate whether the request is coming from my webserver or not
so anytime if any spamming client try to request my web service i will retrieve its ip on every request inside webservice and reject the request for ex :
if (HttpContext.Current.Request.UserHostAddress.ToString() == "127.0.0.1")
{
return "my server";
}
else
{
return "invalid client or spammer"
}

Secure authentication and requests with C# through a PHP REST api

Introduction
Okay so I've got a website (PHP) with a database (MySQL). You can create an account on this website and edit your details and so on (let's say date of birth, real name, address, and so on).
Now, what I wanna do is to create a desktop application (most likely c# with WPF) that interacts with a REST api (in PHP) from the website, which will allow to :
Create accounts directly from the application
Log in to your account
Be able to edit your details directly from the application
As of now I only want to do a desktop application, but it might evolve into a mobile app. I don't think that is relevant though.
Creating accounts and logging in
I'm struggling with the create account / log in part. I want it to be as secure as possible. On the website, I'm using password_hash(PASSWORD_BCRYPT) with a cost of 10 to store passwords in the database, and password-verify to check log ins.
Regarding the application, I imagine the way to go is to pass the username and password to the REST api and do the encryption directly on the server side. But sending the password itself sounds terrible so I thought about encrypting it with a secret key that only the application and the website know, so the website can figure out the password and encode it correctly in the database.
If I'm right, what encryption algorithm should I use? If not, how should I do that?
Edit your details directly from the application
I'm thinking about doing the following : Let's say the user has logged in through the application. If the authentication is successful, the server randomly generates a token (I'll probably use ircmaxell's Random-Lib) and send it as a reply to the application. From then onward, when the application wants to make a request to the api, it adds the username to the datas string, and generates a hash (sha256 for example) with the data string plus the token; then the server can repeat the exact process using the token stored in database to make sure the user actually has the right to access/modify his details, and nobody is trying to pretend to be an user he isn't.
I feel like the problem is, if someone listens to the first api reply after the authentication, he gets the token and can use it to act as if he was the user. Would encrypting it with the same process used for the password be enough to make sure this can't happen?
Last but not least, if I want the user to be able to be directly logged in the next time he starts the application, I guess I have to give the token a permanent durability and store it in a file or something on the computer. But that doesn't sound really safe because anyone could just read the file content and figure out the token.
Final questions
So. What do you think ? Does it sound good or am I completely off the tracks?
The website hosting is in http://* so I guess using HTTPS communications is not an option here. I know that's a big problem to create something really secured, but I'd still like to make something as safe as possible with what I have.
Thanks a lot for your advices. :)
Btw I tried to make this as clear as possible, hope it worked. I have close to pretty little knowledge of security, encryption, ... so you'll have to speak like to a 3 years old to me.
I think the first, most important piece of advice I could give is to never try to roll your own security code, unless you are an absolute expert. You'll want to put together a solution based on the frameworks that .net provides for you.
First things first - your REST API. I'd suggest building on top of ASP.NET Web API. HTTPS is mandatory here - if your hosting provider can't give it to you, you need a new hosting provider. It also conveniently takes care of encryption for you.
There are various security options available for ASP, I'd read this for a detailed overview: https://docs.asp.net/en/latest/security/. Using the existing ASP options will also take care of your requirements around user account creation and self-service.

Is there a way to hide the posted Form data when the form submit is intercepted in Burp Suite or any similar tool

Is there a way to hide the keys and values that are posted back on form submit.As these key values can be tampered with by the Hacker using Security testing tools such as burp suite?
While HTTPS is used to secure data in transit, there is no practical way to prevent a user from tampering with data on their machine. Pretty much every modern browser now has built-in or add-on developer tools that allow a user to pause script execution, change client script variables, modify HTML, and so on.
One method that CAN be used for data that is round-tripped back and forth from the client to the server and doesn't change (such as a UserID) would be to encrypt the data prior to sending, and then decrypt when it returns to the server. Another mechanism would be to take all of your round-trip values that aren't expected to change and compute a hash against them which could be stored in a hidden field on the page. Then when they return, recompute the hash and make sure that everything matches up. Then "BobLimitedUser" couldn't change his username to "Administrator" by manipulating HTML without breaking the hash.
All of that being said, the underlying fact is simply that you should consider data coming from a system not under your control as untrusted. Final input validation should always be performed server-side (in addition to any client-side validation performed). Because of this "double validation" requirement, for complex validation routines, I'll actually use a webservice/AJAX call to perform the client-side validation. Then my client script and my server code can simply call the same routine, once during and once after submission.
If you take the approach that you will validate all input at both ends (so to speak), then tampering really shouldn't be an issue. If BobLimitedUser wants to manipulate HTML so he can change a dropdown value from one value to another value he has access to, that is his time to waste. If he manages to change something to a value that causes data integrity or security issues, that is what the server-side validation is there to protect against.
In Short
Never trust anything generated by client script. It is simply too easy to manipulate (or even have some old script get cached by the browser, become outdated, and break something)
Client side validation is for responsiveness and usability. Server side validation is for data integrity and security
Don't pass sensitive information to the client and trust it to come back intact. If you must, then use encryption to protect it, or hashing to validate it.
Don't even bother trying to encrypt/hash stuff client-side
Do use HTTPS to protect data during transport
Implement logging/alerting of security related errors. That way, if you get alerts every day that BobLimitedUser is attempting to exploit your app, you can talk to your IT security department and either get the virus removed from his machine, or he can be dealt with appropriately
Data validation is a big topic of discussion, and I would recommend reviewing the OWASP reference guide (simply too much information to replicate here): https://www.owasp.org/index.php/Data_Validation
One last bit to think on... if you have a client-script application, then I assume you are using AJAX and web services to transmit data. Regardless of what client script you write, what prevents a malicious user from simply using something like Fiddler to bypass not only the client script, but the browser itself, to send requests directly to your web service? The only way to ensure security is to validate everything at the server.
This assumes you are trying to prevent a malicious user from modifying values - if you just want to prevent man in the middle attacks, use HTTPS as Richard suggests.
Assuming you want the user to be able to post values, the short answer is no.
If you don't want the user to be able to modify these values, then just store them in session state and don't return them to the user (or read them back from session if you need them to be passed between the client and the server).
You can also validate the returned data on the server side, i.e. remove tags etc.
Essentially, you can't trust client supplied data. HTTPS won't stop a malicious user intercepting the request and changing their firstName to "alert(1)" (for example).
If the user needs to supply values, check they are safe and match your rules for content on the server side. Always check authorization etc. on the server side, don't trust user supplied data.
You can't stop a malicious user from modifying data before it's sent to your server, but you can verify data before your server uses it.
When Burp Suite is used as a proxy server, it allows the user to manipulate the traffic that passes through it, i.e. between the web browser i.e. client and the web server. This is typically referred to as a Man-in-the-middle (MITM) type attack architecture.
My suggestion is that you encrypt the data that you would want to keep untampered on the client side and store it separately in a hidden form field before posting it to the server, and then decrypt it on the server side and compare it with the value(data that may have been tampered with by a Man-in-the-middle) that was posted to the server.
This way you would know if there was any change made to the data you would want to keep safe.
P.S: As mentioned in almost all the answers here, use of HTTPS is highly recommended in such cases.
Use HTTPS instead of HTTP. HTTPS will stop man-in-the-middle-attacks and prevents an attacker from seeing the plain text.

What is point of SSL if fiddler 2 can decrypt all calls over HTTPS?

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.

Categories

Resources