views:

1560

answers:

12

I was thinking about how to secure the Data Layer in a C# Application, the layer could in this case be either a LINQ to SQL Model Diagram stored with the Application itself containg the connection string to the SQL Server Database.

Or it could be connectivity between the application and webservices.

Either you need to impement some sort of security, for instance, the Connection String in a Application can easily be reverse engineered and Webservices can easily be tracked and used for other reasons than the applications original purpose.

So my question is in a shorter way: How do you solve the security issues when handling Webservices and/or direct connection to a SQL Server From a Windows Forms Application?

+3  A: 

One way would be to use a Trusted Connection to SQL Server, that way you don't store the username / password in code.

Dan Diplo
I am more focusing on applications ( Windows Forms ) than on Websites ( asp.net ). Applications are globally available and therefore you need to have solid security, this is the issue. Trusted connections doesn't solve this problem?
Filip Ekberg
Still the app vulnerable all sort of SQL Injection attacks, this won't solve anything. It might make the attacker's life harder though.
dr. evil
Well, I wasn't saying it was a panacea that solved everything, merely pointing out it was a way of securing connections to a database that didn't require hardcoding in the username and password. This was addressing a direct concern of the questioner. I get the impression he already is aware of SQL injection and would use appropriate binding to ensure that wasn't a problem.
Dan Diplo
A: 

Where security is that important, for example when you are storing credit card information, you'll usually want the data repository and the webserver on seperate boxes, with a firewall between and both locked down by IP Security.

This way, only the webserver is exposed to the outside world. Your database server is sitting comfortably behind the firewall, and can only be accessed by the webserver through a certain port.

You might also consider SSL encryption on the web services and expose only HTTPS endpoints.

Winston Smith
This doesn't really solve the problem, it's easily tracked what ip + port is accessed with an application and therefore the Webservice is exposed.I'd like to find a way to use I.e. LINQ to SQL in my Application but even so have a Completely secure application where it's "impossible" to reverse engineer the Connection String to the Database.
Filip Ekberg
A: 

I am not completely clear here. If the winforms application calls webservice then use a appropriate model for mutually trusted authentication. This can be based on client and server certificates or SSL with client certs or even Net.Tcp if you are all .Net. Then however the webservice is exposed only trusted clients can communicate. The webservice can then stay behind a DMZ and the DB behind another DMZ. Use appropriate firewall rules and IPSec connection between webservice and SQL is an option.

For direct connection to SQL server to many winforms application the challenges are many.The connection to your DB has to authenticated and encrypted. In any case your SQL server will be exposed and I would not recommend such a model.

Pratik
+10  A: 

In your case there are two main attack possibilities:

  • Steal the connection string and then access the database directly
  • Call methods in your C# code directly without using the UI

For the connection string you need to store it in an encrypted form in a config file. Problem is that there need to be enough information in the winforms app so that it can decrypt and use it.

For accessing the code directly you can use code access security and obfuscation.

In your case I would not give the windows app direct access to the database. Let the windows app call a WCF service, the the WCF service would access the database.

The user's user account is allowed to call the WCF service, the WCF service is running under an account that is allowed to access the database, the user's user account has no rights to the database.

Windows App with 3 Layers:

  • UI
  • Business (Security check what UI should be shown to the user)
  • Proxy

WCF Service with 2 Layers:

  • Facade / Business Layer (Security check is user allowed to call this method with this data)
  • Entity Framework datamodel

Common dll's to both Layers

  • Contracts / WCF Interfaces
  • Data Transfer Objects

For info on proxy, contracts and DTO's see this video:

http://www.dnrtv.com/default.aspx?showNum=103

Shiraz Bhaiji
This is the closest answer I've gotten so far. This actually fits a 3-tier model perfectly: Data Layer -> Logic -> Presentation if you can keep the Data Layer in the Database and have a LINQ to SQL layer on top of that, you could let WCF Services handle the -> Presentation. Could you evaluate more on this please?
Filip Ekberg
Have edited it. Let me know if you think anything is missing.
Shiraz Bhaiji
+2  A: 

I don't think there is any one-solution-fits-all to this problem, you will need analyze and adjust your solution to the particular problem you are having.

As far as I know there are no known ways of securely storing your connection information on the client side as your client is a "trusted" part of the communication to the server. No matter how you store the information, the client has to be able to reverse it or send it directly to the server, which also means that a potential attacker can repeat the process. Also any external communication directly to your database can potentially be intercepted/hacked.

The best way I can think of to protect your data is having a webservice (over a secure connection) as middleware controlling the communication with your database(which you need to secure) and adding logic to enforce whatever level of security you wish to attain. You can make it account based to grant different levels of access if needed. But the main thing is that it only allows safe/isolated operations.

To secure the webservice(middleware) there are two concerns, authentication and isolation.

Authentication

You can use the standard .NET authentication as Steven suggested. I normally prefer rolling my own solution though for two reasons. First off, so far I've mostly ended up handling more complex users/roles. For example using permission based roles so that you can check for permissions instead of specific roles.

And second, it gives you more control. You can avoid session based authentication and you can also use challenge-response, for example challenge with a timestamp and expect a hash of the timestamp+password(which the user has to enter at application start) or some other creative combination as answer, I am sure there are better hash combinations to respond with. This should also be done two-way, to make sure that the client verifies whatever it gets from the server.

Also here are some SO topics about WCF Authorization that might be interesting: WCF Service authorization patterns Authorization and Authentication using WCF WCF Authorization - access to operations via claims And also a book and a paper (not free)

Isolation

No matter how secure your authentication is, there is always the possibility of someone being able to access your webservice for malicious intents. As far as I know there is no one solution to this problem, but it is rather dependant on the specific application and how the data is structured and shared between users.

You will need to identify layers of isolation such that users cannot affect each other or the system in general, and also how the application is used. Will clients need to write data, or only read? If they write, is written data shared in any way and in what way can you isolate/verify that data? If they read, is the information private for the user, private for the system or shared among users?

For example a system for storing medical journals or personal task lists will have very isolated data and you can restrict access to your private information only (and possibly your doctor/boss depending on user groups). In this case you can isolate all data read/writes to the particular user, thus the attacker can only affect his own data, keeping everyone else safe.

If the data is shared between users you will need some way of verifying the input that is given from the user. Preferably you should also have some kind of trust-level for the user such as SO's reputation to prevent any one-time users to attempt a hack. This is really too specific to give any good advice on.

You also properly need to verify the input that you recieve to prevent hacks such as buffer overflow hacks and SQL injections. Allthough I don't know if buffer overflow is a problem with .NET, and SQL injections should be easily preventable with LINQ-to-SQL.


All in all there is no 100% guaranteed way of securing your data, and you should keep regular backups (separate from your database) of your data in case you get compromised and probably also transaction logs.

And as a final advice, if you are really serious about the security you should probably hire a security consultant and have a peek at how banks have set up their security infrastructure.

Also you can still use LINQ with webservices through LINQ to ADO.NET, though I haven't tried this myself.

This link might be more explaining How to move from LINQ to SQL to “LINQ to WCF”?

Runeborg
And why exactly was this downvoted?
Runeborg
Because this answer doesn't contribute anything concrete.
Filip Ekberg
Well then you should probably elaborate on exactly what you are trying to achieve. In what context is your application going to be used? How is it going to be distributed and who will have access to it (freely downloadable or is users trusted)? Why would not account-based security(not concrete?) as I suggested work? What are the attack vectors you could imagine? What exactly is it that you are trying to prevent?
Runeborg
It's an abstract question but your answer, however, didn't answer my questions sufficient enough and therefore the answer is useless. Imagine the application used in the worst scenario, downloadable by everyone, used daily by thousands, the security is vital. You can't store reversable data that allowes access directly to the database in the client software.
Filip Ekberg
Okay, but it is the _direct_ access to the database that you are trying to prevent? And is read-access okay? If so a webservice(or similar) that acts as a security layer that you control should be fine. How this would work would be dependant on the specific application and the type of data that you store. To be more specific I would need a more specific question.In any case I can't imagine any way of storing any such information on the client side as it has to be reversable by the application by some means, which means an attacker can also do it.
Runeborg
I'd like to be able to use LINQ to SQL in the client-application, which makes everything harder.
Filip Ekberg
I updated my answer to reflect our conversation a bit. The general answer is still "Adjust your solution after analyzing a concrete problem" though since there are many factors to consider such as isolation levels/type of data etc.
Runeborg
Much more helpfull, thanks!
Filip Ekberg
I like much of what you said, but I'm not sure that there's any point to more complex authentication schemes; running Basic over HTTPS avoids replays and doesn't depend on session cookies.
Steven Sudit
Good point. I wasn't sure if the authentication you suggested was using session cookies, so I thought it was worth mentioning, plus the challenge response should provide some extra security. My number one reason to usually do this though is the extra flexibility in roles as the default security is perfectly fine to use.
Runeborg
That's a reasonable answer.
Steven Sudit
+4  A: 

Shiraz Bhaiji came close, but I think they missed the key step.

Yes, you want access to the database to be mediated by a middle tier, exposed through WCF, which imposes whatever business logic you require, including full access control. This service does have the connection string that you want to keep secret, but it's not accessible to the WinForm clients.

The key step is that the client uses the user's authentication to gain appropriate levels of access, and never has any ability to contact the database or even get full control of the middle tier. The middle tier grants access to methods based on the groups that the client user is a member of. This means that a user with low security can call any method they like, but they'll get access denied exceptions, or data filtering, or whatever other failure mode is appropriate. The user account, on its own, has no access to the database, so the middle tier can do whatever it likes.

The obvious way to bypass this would be for the client to use the account of someone with full access. Of course, if they could do that, they'd already have what they wanted.

Hopefully, this approach would be useful in solving your problem.

edit

This solution does not allow LINQ-to-SQL in the client, just the middle tier. If that's a dealbreaker, then this isn't for you. Then again, the moment the client can access the database directly, a gigantic security door is opened up, and it's hard to close. There's a huge amount of extra work involved in securing the database itself so that it provides the sort of user-based, row-level security that comes naturally from a three-tier solution. I would generally recommend against it, although I do recognize that there are times when it is entirely appropriate.

Steven Sudit
This might be the answer I've been waiting for. If you put logic in your client code, your three-tier solution is faulty, I want to use LINQ to SQL in the logic / data layer but be able to pass information secure to the client and the client needs to be able to run commands that are executed on the database and your solution seems to solve it, thanks!
Filip Ekberg
Oh, you can put as much logic as you like in the client, just so long as you treat it as entirely untrusted. This is a lot like a typical web form, where there's Javascript that checks for validity on the client side, but the server nonetheless runs its own validity tests. Anyhow, hope this works for you.
Steven Sudit
Yeah I know I can put logics there, I was thinking of a lower level of logics that is thought of as "trusted" in this case. Thanks again.
Filip Ekberg
Filip, is my answer sufficient to be accepted for the bounty or are there any gaps that need filling at this point?
Steven Sudit
It might be sufficient if you could contribute with some links maybe to valuable WCF-resources regarding the security of the middle layer?
Filip Ekberg
I believe that this was already answered here: http://stackoverflow.com/questions/288070/using-windows-role-authentication-in-the-app-config-with-wcf
Steven Sudit
The security of the middle layer (bar authentication issues) is dependant on how your data is structured and shared between users. You will need to identify layers of isolation such that users cannot affect each other or the system in general, and also how the application is used. Will clients need to write data, or only read? If they write, is written data shared in any way and in what way can you isolate/verify that data? If they read, is the information private for the user, private for the system or shared among users? Or is it the authentication you need more information on?
Runeborg
Runeborg, if you were to answere those questions in your answer, i beleive it would lead to higher rating.. Because, those are the key issues. @Steven, sure that link was good however it does not really cover the possibilities with authentication. Questions I might have is, do I use membership-authentication?
Filip Ekberg
In an enterprise environment, which is what this sounds like, you not only want to leverage the network for authentication but also use group membership to keep security manageable. This lets the LDAP admin control access instead of requiring that functionality in your program. At this point, I'm not sure what else to tell you, so if you feel that Runeborg can provide the answer you need, then by all means give them the bounty.
Steven Sudit
Im not only targeting enterprises but imagine the scenario where you distribute a software online, which needs some sort of common database, security is vital and the clients are unknown where self registering users is trivial.
Filip Ekberg
Well, the basic architecture remains the same, but you'll want a rather different authentication scheme, and you'll need to deal with authorization yourself. For authentication, take a look at http://www.leastprivilege.com/WCFUsernamesOverTransportAndIISHosting.aspx for how to get basic authentication going under HTTPS.
Steven Sudit
@Filip: I elaborated a bit more about my comment in my answer. If you feel anything is missing or is incorrect please do tell.
Runeborg
A: 

You don't secure it because you can't secure it. First you can't properly hide credentials, even though you figure out how to do that then an attacker can sniff (yes even if it's encrypted you can locally sniff) or do SQL Injection directly on the wire.

You need to write all of you webservice calls in a secure manner which doesn't require to transfer raw SQL Query or direct SQL Server connection.

Also it doesn't matter how much obfuscate or encrypt it if the code is not running your system it's not your code any more. By reverse engineering, debugging, modifying the code a potential attacker can change your application into something else and do whatever they want.

Also as someone else wrote your webservice will be open to direct access. Someone can make a call directly to your web service and ignore the GUI at all.

dr. evil
Ok, anyone can call the webservice, but why should that grant them any more access than they'd get through the standard WinForm client?
Steven Sudit
Well this is already known, hence the question.. I want to find a solution to the problem. I already know the security risks.
Filip Ekberg
Put it this way, "it's not possible" unless you trust the user of the Windows Form application, if you can trust the user then obviously it's pretty straight forward.
dr. evil
A: 

A secure method is:

Place the data layer behind a (WCF) service on an physically separate Application Server and have WinForms clients connect to the service using their Windows Credentials. The service then validates whether users can access the various methods in the service based on an Authorisation store (such as Active Directory), and database or combination thereof.

The data service can then use a single pooled identity to connect to a database.

Mitch Wheat
That's the right answer, and only 13 minutes late.
Steven Sudit
@Steven Sudit: why does it matter if its late?
Mitch Wheat
@Steven Sudit: after all, the question is open for 7 days.....
Mitch Wheat
Then the application won't be globally available, I have to "know" all the clients, which is not possible in all scenarios.
Filip Ekberg
@Mitch: Sorry, my sense of humor doesn't always translate well to this medium.
Steven Sudit
@Filip Ekberg : "Then the application won't be globally available, I have to "know" all the clients, which is not possible in all scenarios." - I have no idea what you mean by that. The application is available to all those clients whose credentials give them access.
Mitch Wheat
@Mitch: It interpreted this to mean that the client software will not be under his control, which is why we've all been talking about a WCF middle tier that treats the client as untrusted.
Steven Sudit
A: 

One of the more common approaches with web services is to pass an encrypted username and password via the web method signature in order to validate that the user attempting to invoke the web method indeed has rights to do so.

In terms of the configuration file it is possible to encrypt the file itself or use integrated security as another poster mentioned.

Jason Irwin
A: 

It's difficult to provide a precise answer because I'm not sure what specific issues you are trying to solve and which is the key driver for securing the system.
However, in the past I have used WinForms -> WebService secure communication by utilising WSE
We used X509 certificates and WS-Security. This has the distinct advantage of providing End To End Security rather than relying on standard SSL transport.
However this in of itself doesn't solve issues like user authentication per se, in that case Mitch Wheat's answer seems a good solution.
However, your user authentication model will depend on whether this is a public distributed app, whether the number of users of the tool is large or small etc.
For small numbers of users, or where cost is not an issue, you could implement RSA SecurID authentication by setting up a RADIUS server or such like. This has the advantage in that each RSA key is unique and tied to that user ( though you can never stop a user giving out their credentials and PIN )

HTH

zebrabox
A: 

The answer is simple to protect sql strings is simple. NEVER make a direct connetion to SQL in the client side.

Only accept well formed, schema-validated xml serialized objects as the entrance of your program, after being authenticated in a hashed public private key pair (http://msdn.microsoft.com/en-us/library/6f05ezxy.aspx) , being the public key certificate shipped within your program, so someone eavesdropping wont discover the password.

Also, watch out for DDOS attacks. Measure the use of each webservice exposed for each client, and if the use rises above a given limit, block all incoming connections from the user, and from the user´s ip.

kurast
A: 

If I understand the OP correctly, the immutable design characteristics are a WinForms client connecting directly to a publicly accessible SQL Server?

Almost everyone who responded has basically said 'don't do this, use a web service instead'. This is good advice. Even if the ws is hacked, it can only do things it was designed to do. So an RPC WS can only execute methods already written whereas hacking a SQL Server connection would allow arbitrary SQL Execution. Also, I think you would find that a well designed web service would be more performant.

However, if you are going to do this then you must secure your SQL connection over SSL (see technet) as a start. As with secure web services (which also would use SSL) this will hide the contents of the traffic from the men in the middle.

You can't rely on the authentication of the connection string (but using it adds another layer for a hacker to get through), so you must have an application level authentication layer that you most likely would roll yourself.

Don't allow the WinForms application to connect to your operational database. Create another database instead and allow the connection string based auth to connect to it. Do not do dynamic SQL with this design, use stored procedures instead. Create stored procedures in your public database that would act as your "rpc web service" to hide the real SQL (which would query your operational database and return the results). This will hide the operational details of your schema and reduce the surface area of attack.

If procedures are out of the question because you must use dynamic SQL, still keep the public/operational database structure and use views to expose as little of the data as possible. Leverage user id and any multi-tenancy features you have in the database to pre-filter data in the view. If you can do that you reduce the surface area of attack to the connected user's data.

Without understanding why you must allow a direct sql connection, I can only say again that you shouldn't do it. What you are gaining by doing so in the short term is at the cost of your system's long term security.

ongle