2

We have an application running multiple services and executables. Some one them need to access the SQL database, so I need to store the SQL server password somewhere. To avoid direct access to the password, the password is stored encrypted. To decrypt the string, a crypto DLL can be called, returning the plaintext password. Whats bothering me is, how to avoid that anyone can decrypt the password. The following options had been discussed and discarded, because they do not solve the problem of more or less direct access to the plaintext password:

  1. The crypto dll contains all required information to decrypt the password: any malicous user may call the DLL to decrypt the password with his own component

  2. Using DPAPI, I need to set the scope to LocalMachine, meaning any user logging on to the local system may decrypt the password.

2a. Using DPAPI and a service component running with special account would solve the "any local user can use the Unprotect method of DPAPI to decrypt the password" problem, however, the malicous user still can call the crypto service with his own component.

  1. The crypto DLL requests a password, and encrypts/decrypts using a RijndaelManaged instance. Every calling DLL must know the password, meaning I just moved the problem to another component.

  2. Integrated Security is not an option, customer's security policies deny to use IS

Any pointer how to solve this?

Sk93
  • 3,676
  • 3
  • 37
  • 67
SurfGrobi
  • 23
  • 2
  • Can you use a three-tier architecture, where the SQL database is only accessed from a server running in a secured location? Other than that, the best you can do is locking down the database account, so that even with knowledge of the password nothing bad can be achieved. – Thilo Nov 03 '15 at 10:04
  • I'm assuming this is a WinForms app, thick client? – Paul Nov 03 '15 at 10:06
  • @Paul: Yes, it is a WinForms applicaiton. – SurfGrobi Nov 03 '15 at 10:08
  • @Thilo: Locking down the SQL user is not an option, the application needs to read and write data. And because the db user must be able to write data, the user may abuse the db access to gain higher user rights in our application – SurfGrobi Nov 03 '15 at 10:11
  • 2
    You can create stored prcedures to read and write the data and then only give access to the those procedures – Matt Wilko Nov 03 '15 at 10:13
  • I suppose there are also vendors that offer hardware security tokens that could protect a password. – Thilo Nov 03 '15 at 10:33
  • 1
    First, just *don't* use SQL Server Authentication, use Windows Authentication. No password to store this way. Then give permissions *only* to authorized users. You could create a Windows Group, put all users into it and add *only* the group to the database. Or you could create DB roles and add the users there. Finally, *don't* make everyone a db owner - only give them the permissions they need. This is easy if you have groups or roles, you only need to assign permissions to the roles, not individual accounts – Panagiotis Kanavos Nov 03 '15 at 10:58
  • 1
    @SurfGrobi writing to the database does *not* mean the user can abuse anything or elevate any writes. Even if you give an account `dbwriter` to a database, he can *only* write to that single database, not elevate anything. – Panagiotis Kanavos Nov 03 '15 at 10:59
  • @PanagiotisKanavos that's all fine assuming the users are all in the same domain / trusted domain as the SQL server, otherwise you can run into a whole host of issues. An unknown at this point. – Sk93 Nov 03 '15 at 11:13
  • @PanagiotisKanavos - also, SurfGrobi is referring to the fact that an account with dbWriter permissions could get into a "userPermissions" table and update the "isAdmin" column for any row to "1". (sample table and column names used)... eg: winForm app-level permissions, not actually elevating SQL server permissions. – Sk93 Nov 03 '15 at 11:15
  • @Sk93 wrong. First, you *can* use workgroup accounts with Windows authentication. Second - just *don't* give extra permissions to anyone. `dbwriter` is the lazy way to add a user. It's actually very easy to create a role with only the required access to the database. – Panagiotis Kanavos Nov 03 '15 at 11:18
  • @PanagiotisKanavos you're right, you can, But like I say, we have no idea at present of the location or restrictions (firewall?) between the server and the users. I'm also aware of what you can do in regards to SQL user account restrictions, I was just pointing out your misunderstanding :) – Sk93 Nov 03 '15 at 11:21
  • 1
    @Sk93 no misunderstanding at all. Just because a customer wants a live grenade as a flower pot doesn't mean you should give him one. No matter of hand-coded encryption is going to fix the inherent insecurity of using a single account with an almost hard-coded password – Panagiotis Kanavos Nov 03 '15 at 11:25
  • 1
    @SurfGrobi what exactly is the customer's problem with integrated security? I doubt they have a policy that says "ensure weak authentication and use dozens of hard-coded passwords that need to be changed and known by the administrator". Almost always there is a different reason for such apparently illogical requirements, eg: the customer wants remote users to connect without a VPN, or the customer bought SQL Azure but doesn't want to pay for AD. Or the customer may simply misunderstand security – Panagiotis Kanavos Nov 03 '15 at 11:26
  • 1
    @Panagiotis Kanavos: yes, it is easy to give a user just the required access to the database. But writing access is enough to allow the user to get higher rights, not on DB level, but in our application, by modifing our application related user table – SurfGrobi Nov 03 '15 at 11:36

3 Answers3

3

If it's a publicly available application, then you would be best to avoid storing any SQL connection string details in the winform app itself.

Instead, host a web service that the winform will communicate via.
This will ensure a malicious user cannot get your SQL connection details (at least, not from the winform app or associated dlls) and allows you to hide your SQL server away from the net.

There are many ways to secure a web service so that it can only be accessed by "approved" clients. (User authentication tokens, etc )

2

This will depend how far you think a user in the system will go to get at the connection string.

  • Do they need domain access to use your application?
  • Can you restrict IP addresses into your SQL server?
  • Do users have admin rights on their machines?
  • e.t.c.

Things like the above will narrow down the potential users that can gain access. Some other things that seem to stand out are:

  • Move the KEY and IV outside the DLL as that seems to be the single point of failure if its stolen
  • Obfuscate the key and iv in your application code or store in certificates, possibly with DPAPI
  • Lock down access to your program files, make the application run under a restricted user.

Some other tips are here:

handling key and iv values
storing key in certicates
restrict SQL access by IP address

Community
  • 1
  • 1
Paul
  • 1,483
  • 14
  • 32
  • Or, use Windows authentication and restrict the permissions given to accounts. No password, no need for encryption, no chance of elevation. – Panagiotis Kanavos Nov 03 '15 at 11:00
2

you could set the crypto dll's current public interface to internal only. Then, using the InternalsVisibleTo attribute, you can specify one or more specific assemblies that can actually see those internal interface methods.

This will allow you to restrict access to your crypto library.

reference here: InternalsVisibleToAttribute Class

EDIT 1

The only downside to this would be if the malicious user was to decompile your crypto dll. Whilst you can make this difficult to achieve, you can't avoid it altogether in .Net.

Also, you don't make mention of what level of risk (internal/corporate app, publicly available app, etc), which makes providing the best answer quite difficult.

(I say best answer, as there's no guarantee to any cryptography :))

Sk93
  • 3,676
  • 3
  • 37
  • 67