I have developed a .Net 3.5 windows forms application. I also want to design a website that has a webservice with multiple Webmethods to query the database on the host machine. I want the webservice to be called ONLY through my winapp and my website! And I don't want any other people to be able to call and use my webservice but only some people who have access to the windows application that I have developed.
I need a good security scenario for this! I truly appreciate anyone who can help me because this is my first experience of developing a webservice and I really need it to be as secure as I mentioned!
What you're talking about is going to be difficult to do for several reasons, but primarily this:
If you put anything in code on your WinForms app, it can be decompiled very easily. You can obfuscate the code all you like, but it can be de-compiled.
Because of that, any code that you have in your app can be read by anyone with access to the code. You should always treat any WinForms app as if it's completely compromised, and ensure that the security at the server end compensates.
Because of this, you can't simply store usernames and passwords in configuration files or in code. You have to come up with something else. You CAN use authentication and prompt the user to enter a username/password on program launch, and use that. However, people tend to share these things, so you may want to go for extra protection.
You can put the connection info, or secrets into the app.config and encrypt it, but anyone who can de-compile the code, can recompile it, and add code to decrypt it at will.
You can provide signed keys with your app, and use that in an authentication mechanism, but that can be bypassed.
You can restrict your IP address to specific IP addresses, but those can be spoofed.
However...
By layering all of the above techniques, you can make it difficult for an attacker to bypass your precautions. We did the following in one of our apps where we had a similar requirement:
We set up a database that holds a GUID record for each authorized customer, and IP addresses allowed for that customer.
Every web method expects a CustomerKey parameter. (the guid mentioned above) Each call to a web service checks the key against the IP address.
If it matches, valid data is returned.
If it fails, valid looking data is returned. We actually return what looks like good data, but it's really not. This makes it harder for an attacker to know if they've actually broken through the defenses.
In the WinForms app, the key is stored in the app.config, which is encrypted in the main() event (the entry point for WinForms apps). This is to prevent the casual reader from accessing it.
The program is launched automatically on install, so that the encryption happens at startup, to minimize the chance someone can read the file before it's encrypted.
Also, the code is obfuscated.
Layering the defenses, hopefully, will discourage the average attacker.
Microsoft has some guidelines as well: http://msdn.microsoft.com/en-us/library/ff648643.aspx
Related
As I developped a WPF .NET Core Application that interacts with an online MySQL Database using EntityFramework, I noticed I had absolutely no way of protecting my Database from being read or modified using the easily accessible connection string if my app was deployed and someone code reversed it.
I searched a bit and found these few possible solutions:
Storing the connection string in an encrypted app.config using aspnet_regiis (but .NET Core seems to be more oriented on .json configuration files, and therefore cannot be encrypted using aspnet_regiis)
Obfuscating the source code using an c# obfuscator like ConfuserEx (if I understood correctly it's just making the connection string harder to read, but it remains possible to get it and mess with the DB right?)
Building and interacting with API instead that would do the changes to the DB (but even then how to make sure the API requests are truly coming from my WPF app and not from a malicious user?)
If you know any more precisions about these solutions or perhaps have another way of making it secure and safe to connect to an online Database, detailed steps/links are very welcome!
Building and interacting with API instead that would do the changes to the DB
This would be the recommended approach.
(but even then how to make sure the API requests are truly coming from my WPF app and not from a malicious user?)
You can't really.
When you embed some kind of access key or a public URL in a client application that you expose publicly, you basically accept the fact that it may be exposed. You should assume that a malicious user can extract the key/URL from the client app regardless of any obfuscation.
The service may reject requests from IP addresses that it considers to be misusing the API but it will still need to handle those requests.
Managing a public API is not trivial. You may want to consider hosting your app in a managed cloud.
After some researches and tests, I found that the proper way to prevent a malicious user from reading and messing up with the connected database (even if he gets access to the connection string) is by Limiting my app to only execute Stored Procedures that will give the minimum data required. And for stored procedures that will read or change a user's sensitive data, also by having in their required parameters the user's secret token, which would be a random string generated in SQL the same time the user registers.
The only issue remaining is if the hacker spams requests to try to bruteforce (even if it's almost impossible to bruteforce a very long and safe token), it might still makes the MySQL server overload or even crash. To prevent that from happening the only solution seems to use an API.
There is a ton of material available for encryption in general, and I've been reading through it. But this question will not be about the actual encryption...it's how to secure the thing I use to do the encrypting.
I feel like the problem I am trying to solve is a simple one: my application needs to connect to a MySQL database on a website to fetch some information. That requires credentials to log into the database.
The application needs to have those credentials at the ready, so that means storing them securely, such as in app.config. I can encrypt those items and then store them easily enough. I even took a stab at doing that, using aspnet_regiis -pef to encrypt the section of the app.config where those were stored, but that seems to be a non-portable solution (e.g. worked on my dev PC, failed to decrypt on another computer). So if I am wrong about that, then let that be my question: how might that have failed me?
Otherwise, my question is this: how am I supposed to secure the key with which I encrypted the credentials? Is there an established best practice for making the key available to the application, while still protecting it in some way?
"You cant hide secrets"
Realistically you cannot secure anything you distribute. Your connection string is distributed in your app.config to potentially millions of customers, or at least can be copied millions of times. Your encryption algorithm may be very complex, but you must at least contain the decryption code in your .net application; which can be readily decompiled. All the hacker has to do is work out how/where your store your key. If they user doesn't supply it as part of the login process then you can't really secure the connection.
In the web application world we keep the connection string in web.config encrypted using the application pool service account credentials; only the app pool service account can read it. The user of the web site never gets access to the web.config, and if they did, the firewall between the DMZ and the database server would prevent them from attempting a connection. You lack any of these safeguards in a client-server application.
Ideally you would provide your end user with a SQL Server login based on their windows account credentials, or a username/password; you secure their SQL account rather than the ability to attempt to connect. This is reasonably secure in an intranet scenario, as SQL Server can delegate authentication lockout etc to the Windows Server allowing you to do three-strikes based login policies; but you cannot secure the attempt to connect - only the success of the connection attempt.
To be honest, you're not going to have a failsafe way of doing what you want - anyone you're distributing the app to can decompile and examine what you've sent them. Literally any security scheme you can think up, the attacker can simply read the code for.
Instead, I think you should put some minor security on that end (block the casual/curious people with some straight-forward hard-coded-key encryption, knowing that you're not going to stop a determined attacker) - and instead focus on locking down the SQL end as much as possible. Those account credentials you're giving out through your app? Give it the bare minimum of Stored Procedures it needs to do its job, and then lock it out of all the other tables/views/etc. Connect in to the SQL database as your app's account user, and try to see if you can perform anything malicious - screwing with table data, dropping objects, etc - and then take steps to mitigate/remove those vulnerabilities.
If that's not sufficient, your next best bet is to program a middle layer. Make a web service, and have it be the one to connect in to SQL. The WPF App doesn't hook into SQL at all, and has to go through the web service to get/change/etc the data. But it's important to realize that an attacker can still screw around with your data - they can directly call your web service instead of going through the WPF app. The only thing you gain is that the attacker doesn't have a SQL login.
I am using c# (VS2010 FrameWork:v4.0) and SqlServer 2012 to build an application. I searched online to find ways to prevent copying this system and I thought the only part that needs to be protected from copying is the database.
I would like you to provide me with some advises about the issue. And I need answers/opinions about the following :
Do I need to protect also the application (executive file) from copying with the database? If yes, does this mean I have to provide the user with a new copy to install it if the user looses the application files?
One Idea I have in my mind to protect the DB is to save some passwords/keys in DB (in the form of varbinary) and when the device is logged in (runs the app) the application checks for (the MAC address) of the device if it is not saved then the app asks for a key. once the key is used, the device mac address is saved with the key. Is this a right thing to do? is there any advice about it?
If I need to protect the app part from copying, is there any idea how to do it?
I have also read about installing SQLExpress on client PC and That should protect the DB files from manipulation, so I have to provide a way to upgrade/ update DB scripts in the future rather than replacing client's DB with a new one. And I thought to provide a form in the app protected by a password, and I can write a script in a textbox in the form (__For Example: Alter Proc_ ...), and Save it. Can I do this? or would that be a stupid thing to do?
Thanks in advance
You cannot. Any claim to the contrary is snake oil.
The only way to protect your application is to offer it as a service, hosted on hosts you own/control.
To find a way to prevent user from using APP+DB without my permission(for example registering using keys)
It is possible to create licensing schemes where the application runs only on the designated hardware. Your application takes the host fingerprint (eg. net MAC), uploads it to a service you host, you sign the fingerprint with a private key and provide the signature to the application, then the application validates the fingerprint signature using the embedded public key and runs the application. While this sounds doable, there is a number of ways this can and often does go wrong. Users change the fingerprint frequently (eg. hardware update). Fingerprints are difficult to enforce on virtualized environments (VMs can edit their MAC). It is very difficult to harden application code against a moderate hacker willing to attack and bypass your protection, and basically impossible to harden it against a skilled hacker.
But you have also asked about the database and tagged the question sql-server. To that part I can only double down on my previous answer: It is impossible to protect a database against being accessed and/or modified by a on-site administrator, at will. There are secure ways to audit access and modifications to the database, so you can prove tampering and act accordingly (refuse support or charge extra). But you cannot prevent it.
Ultimately what you're asking for is DRM.
Greetings!
I'm needing to deploy a compact database with an application I am working on. The database acts as a cache for data the app has already seen, and that data will never change, so the cached values will never become outdated. I've chosen SQLite, and I'm writing in C#.
I'd like to protect the database files so they cannot be easily accessed or edited by the user - keeping access to my application only. Now, one option is to use password protection which is fine except that with tools like Reflector one could easily view a near original version of the source and check the passwords/how they are generated per file and replicate this.
Are there any suggestions on how to achieve this result or something close? Have people done something like this in the past?
Thanks!
Security by obscurity.
If your apps can decrypt it, then your user can do it too.
If you want to keep it secure, you'll have to keep it for yourself. Your best bet is to store the database on a server and make it available via a web service. Perform access control checks on your own server so that the application can only access the parts of the database it has to see.
I don't have a clearcut answer for you (obfuscate your code during release deployment, make the password obscenely long) as the golden rule stands: If they have physical access to the executable (substitute machine/car/door) they can get in if they want(and have skills).
All you can do is make things difficult for them.
This area is not my forte, but one thing I could suggest is to just think about what data you are actually sending and determine if there is any way that you can limit any of the more sensitive data from being transmitted to the client in the first place.
If your concern is over sending things like ID numbers account numbers to the client, then perhaps you could translate those values into a client-only version that is meaningless outside of your application. Your server could have a table that contains the translation between the real values and the client-only values.
Let's say you have this table stored in your server's database (not the client database!)
RealAccountNumber ClientOnlyAccountNumber
981723 ABC123
129847 BCD234
923857 CDE345
...
So the client only sees the account numbers in the ClientOnlyAccountNumber column, and when a client sends a request to the server for an action to be performed on account "ABC123", the server knows to translate that into account number 981723.
The basic question
How do I know that it is my publicly accessible (client) application that is sending my service messages? How do I know that it is just not some other application that is impersonating my application?
Some Background
Currently we log all errors that occur on our websites via log4net and WCF to a database. This works well because the web server (accessible from the web - Partly Trusted) reports there errors to the WCF service running on the application server (inaccessible from the web - Trusted) via a trusted relationship. We therefore know that all error logs are real and we need to investigate them.
With our new sites we plan to make use of SilverLight to liven things up a little. The problem we are faced with is how to report errors back from the SilverLight application running on the web consumer's PC (Untrusted) to our application server (inaccessible from the web - Trusted).
We can solve the inaccessibility problem of the application server by making the client communicate via a service facade on the web server, so that is no worry. The problem occurs when we need to be sure that the application sending the messages really is our application and not just an impersonator.
Some Thoughts
The code will be written in C# and be running in a SilverLight application that runs locally on the client PC, so we cannot be guaranteed that it will not be decompiled and used to send fake messages to our service.
The above means that we cannot make use of conventional symmetric encryption because we can't store our private key in the application (it can be decompiled). Similarly we can't use asymmetric encryption since it could just be impersonated (the attacker could just sign messages with the stored public key and send them - the messages would look real)
In the case of this application there is no user authentication, so we cannot use that to provide us with trust.
Yes, I know this is rather bizzare with the error logs being better protected than the data the application displays, but it is the case :)
Any thoughts or help would be greatly appreciated!
Impossible.
You can authenticate users, but not the application.
Let's say you decide to digitally sign the application. This signature is then read at runtime by your client application checking its own executable binaries against this signature. There is nothing that prevents the adversary from simply removing this check from your application.
Even if you make it close to impossible to reverse engineer your application, the adversary could always look at the communication channel and write an imposter that looks indistinguishable from your client to your server.
The only thing you can do is validate the actions on the server against a user identity.
Presumably, your server is creating the web page that the Silverlight application sits in. You could create a short-lived temporary "key" that only that web page contains. When the Silverlight app starts up, it reads this key and uses it. Because the server itself has a constantly changing, very short list of allowed keys, you can be more sure that only your app is accessing your services.
The best advice for you in this matter is to hire a security expert to help you. This is not a unique or unusual problem -- consider any game (like WoW for example) that is attempting to determine if it is speaking to a true client or a fraudulent client. Even with a massive amount of effort (look up Blizzard Warden, I'm not going to link it here), they still have issues. The problem boils down to exactly how much time and effort your attacker is going to invest in thwarting your attempts to make thing hard on him. Just be sure to validate everything on the server-side. :)