I have an SQL Server running on a Windows 2008 R2 machine which needs to have basic queries run on it (SELECT / INSERT / UPDATE). These operations are executed directly by the client, an application written in C# which installed on one computer in a different location so the connection is over the internet.
Since the nature of the operations run on the DB is so simple, I would rather not write a back-end on top of the SQL Server. So the setup for security:
1) Username and Password written in client and submitted.
2) A (parameterised) query is run on the server and the password hash and salt are returned to the client.
3) The password and salt are appended, hashed using SHA_512 and is compared to the password hash.
4) If the two match you are given access to the toolset that creates and sends the queries.
After researching the topic somewhat I feel like this system has some security flaws, but I cannot pin-point exactly what these vulnerabilities might be.
Based on your scenario I would consider creating SQL accounts for each user of your application. When the user logs into your application use these credentials when constructing the SQL Server connection string and allow the server to perform the credential validation. This is often referred to as pass-thru authentication.
Even better, if your application will be executed by users on the same Active Directory domain as the SQL Server you can use the more secure Windows Integrated Security (what you are currently using for local testing) and the users will not need to login at all. The connection will simply use their current AD credentials. See this link for more information about setting up user accounts in SQL Server using Windows domain credentials: https://msdn.microsoft.com/en-us/library/dd787978.aspx
Also, with either option you will still want to use a TLS protected connection (Encrypt=true) to help prevent snooping of credentials over the wire.
If I understand this correctly, then the whole password-check is done on the client side. Is that correct? If so, it seems potentially insecure.
Do you trust the client itself entirely? If an unauthorized person can get access to the client, or create another client that mimics your client, then that significantly increases the chance they'll gain access to your server side.
It definitely sounds like you would be more secure creating a back end system, even if it is just a very simple proxy-service that simply checks the username and passwords, and then forwards the query itself as-is.
That way, the password-hash and salt will never have to leave the server.
A client connecting directly to a SQL Server is not secure. If the client is on the local hard drive then it can be hacked.
You are not finding tools for what you are trying to do because it is not a good design.
Don't get your logic of "Since the nature of the operations run on the DB is so simple, I would rather not write a back-end on top of the SQL Server." If it is easy then that is a reason to set up a back end.
.NET has a whole infrastructure for it. Windows Communication Foundation.
Related
I have googled for a long time for ways to secure the SQL connection string stored in a Winforms app. Encrypting the app.config (connection string included) of a Winforms app could be useful; however, it is not as safe as a webform app since the app is installed on user's PC. Any malicious users who want find out the connection string can reverse-engineer the app using the locally saved certificate to decrypt out the connection string.
Recently, I think of a possible way for protecting my connection string.
It is like this:
I'll create a read-only user and a read-write user using MS SQL Server Management Studio. The readonly user's connection string is located in the resource properties unencrypted. It is used to connect to SQL Server and check for the login passwords into my app.
Once the password has been checked, I will call a user defined SQL function (secret key included) which input is a ciphertext and return me the connection string to login the SQL Server with the read-write user account.
Will someone view my secret key hid in the user-defined function? Will this work to protect my connection string for logging in the read-write user account?
Thanks for all your answers. After watching TimCorey's YouTube video (https://www.youtube.com/watch?v=rFncI9yfY-E), I think I am sort of knowing that my idea is too simple. Using stored procedures in a SQL server should be a safer choice than the user defined function.
Here I would like to make a summary, as suggested by Mouse Power and Charlieface, for a win-forms app to connect to a SQL server with more safety, we can get data from a SQL server either through:
(1) executing stored procedures (with limited permission) or through
(2) web APIs wherein SQL connections are made within the server.
Conventional encryption(using ASPNET_REGIIS) of connection string in web.config of a web-forms app can not be applied directly to the app.config of a winforms app. This is because the app.config and its encrypted key are both located on the client side, so it is difficult to prevent any malicious users using reverse-engineering to crack out the connection string. Nevertheless, encrypting the connection string using a key hidden somewhere (in codes, file, or resource) is still suggested, as a preliminary protection.
Using a separate account for each connection may also be an option, but this may make the programming of SQL connections relatively more complicated.
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 was wondering what the best approach to make secure connection to SQL Server would be? Here is my scenario. At my work, we have SQL Server 2012 Standard. My boss wanted me to create a new DB utilizing TDE. I found out that you have to have Enterprise Edition in order to use TDE. We looked into it and it was going to cost a fortune, so we are not going to purchase Enterprise Edition. So I was thinking about using Stored Procedures to interact with DB. Is this more secure than submitting SQL query across web? Also, what is the best security measure to communicate and transfer data to/from web app/DB server?
Thanks in advance,
Brad
EDIT:
Also, is there anyway to securely send username/password credentials in the connection string?
Stored procedures would in a sense be more secure, since you could simply submit objects into the procedure to generate your desired result. This would mask the underlying SQL statement, so it could be considered more secure. I think most places rely on the Windows Authentication aspect of SQL in a domain environment.
It is fairly secure, more so if your site is wrapped up in SSL. Avoid standard SQL authentication, it's text based and shouldn't really be considered.
Code wise, you probably want a layer in between your DB and your website to do all the heavy lifting. This somewhat obfuscates what your website is doing since it is calling to your middle-man, and he handles all the truly transactional stuff.
Also, how are users going to be interacting with your website? Will they be required to login first, and what mechanism will control this? There are quite a few other design details to figure out before you can really consider which method will be the best balance of security and usability. I'd go for WindowsAuth/SSL and utilize a security account to perform all your transactions. It's easy to setup and AFAIK not easy to hack.
This are two different things - TDE will help you just with encrypting data on file system (so if I have access to filesystem where you have your db I won't be able to read it if you're using TDE).
Communication between application and db is different issue. There are several things you can do:
open network ports for db just to webserver (only from web server ip(s) you can access db)
use integrated authentication (no-one can sniff your password)
embed your business logic into stored procedures (you limit access to db just to function needed for scope of your web application)
However especially the stored procedures part can be pain (ORM like EF, LinqToSQL or nHibernate are just terrible when it comes to stored procedures). And also this approach doesn't guarantee that no-one will be able to see data coming from database server to web server).
If sniffing data between webserver and db server can be a problem, you have to write webservice for accessing data. This webservice should be on trusted network to db server (as close to db as it can be - same box is the best). Webserver should call this webservice over https (thus sniffing data between web server and webservice is impossible) and use authentication to access webservice (recommended is windows authentication).
My application connects to a SQL Server using windows authentication. I have a login in on the server which is a Active Directory group. If the user is in the Active Directory group then it logs you into the SQL server and gives you the correct permissions.
However this way is much slower than using SQL Server authentication, is there any way to increase the performance.
I did some tests for how long it takes to login into the server:
SQL Server Authentication - 0.068414 s
Windows Authentication using AD - 0.182627 s
Thanks
I wouldn't be worried about this. All MS technologies for connecting to database have a database connection pool will be kept in the background so there won't be many opening and closing of connections.
0.18267s is most likely nothing compared to actual queries you run on the server.
If you really want to look into this some more you can try following:
make sure AD is not too busy
make sure there is good connectivity between SQL Server and AD (use Ping to verify)
if possible give permissions to AD users vs AD group.
I was just going to add a comment, but it got long. Now its here.
Anyhew. When you provide credentials to SQL Server directly it can perform its own authentication and return.
However, when you specify AD credentials SQL Server then has to do another round trip to the Domain Controller to confirm your credentials (although technically I think you are actually passing a token. Anyway).
My 2c.
I'm pretty new to C#, I've been doing a bunch of stuff but I'm missing a lot of basics.
Anyways, I'm making a program where the user has to log in and and then it checks if the entered password is the same as the one on the database.
Anyways, I know that there's ways to get get into the code of a compiled program and I wanted to know if there's anything I should do to make sure that nobody can see the login info of the MySQL data somehow.
Thanks
There are many different ways you can Protect Connection Information depending on your specifications and requirements.
One simple rule, never include database connection strings in compiled code!!!
Some Links
Protect Connection Information
SO - Encrypt connection string in NON ASP.Net applications
MSDN Securing Connection Strings
Further to a questions raised in the comments.
Secondary to ANY connection string configuration you should also limit the applications access to the Database by using Role Base Access Control to reduce the permissions granted to the application and the procedures or Sql commands it can execute to a bare minimum.
The only way to prevent people from seeing your MySQL connection string credentials would be to use a three tiered architecture where you have a webserver or service running on a server which holds the connection string and makes the requests to the database. Your client applications would communicate with the with the webserver/service.
I agree with Lloyd.
In addition to the security aspect, keeping the connection string out of compiled code means that if you need to change it for some reason, you don't have to recompile and redeploy your code. Often, you don't know that someone messed up the server name or database name or credentials until your site suddenly stops working. In the middle of the night.
I was thinkinging this would be an issue with my program, So I am makeing a PHP file to process POST data and return a response, Where the PHP file on my sever side holds the Database connection as well as only return's limited data to my C# program. And the C# program then read's the response and get's the appropriate data. This will make it so the program it's self does a HTTP POST and doesn't know the database user and password. As well as give's me control over what data can be sent to the C# Program.
There is no way to hide your connection credentials from someone that can get into your code using some ILSpy like intrusion.
«Intruder» can see anything needed to find them. For example he/she can see how you decrypt the (so called...) encrypted xml and use the same method.
The only way to hide user credentials is in database itself, where the user has no access.
Explain: If user has to enter its own credentials to login to database, the credentials will be checked by the database server, so no credentials are exposed in your app residing in user's machine. And user cannot see other's credentials.
So:
Create the users in the database as database users.
Allow them to access any tables they should access.
In your program:
Ask user for credentials.
Check if you can connect to database with those credentials.