I'm trying to understand how I can impersonate a different user when accessing to SQL Server.
Basically my C# application has to access the local-filesystem with the same account as it was launched with, but should use another account when accessing the database.
IF the database is remote, I can achieve this splitting by using "runas /netonly", BUT if the server is local the process will use the credentials with which it was launched.
The user which has the right credential for DB access is different from the user which have access to the filesystem I need to use.
How can I solve this situation?
Basically my C# application has to access the local-filesystem with the same account as it was launched with
Split the app in two and separate this local file access requirement into a separate service that runs with the required privileges. the two parts of your app communicate using your IPC of choice (including authentication and authorization of the two app 'shards' between each other). This may sound complex, but is pretty much buletproof from security POV and not at all hard to implement. C# code can impersonate and reverse impersonation explicitly using WindowsIdentity. Access across network under impersonation is subject to delegation. But I believe going there (impersonating when connecting to DB, reverting when accessing local resources) is just a bugfarm in wait of a harvest... Separating the local access part code from the impersonating one in two services is much more robust imho.
Related
I have 3 machines, one of them is acting like a server that contains the database and tables. However when I try to connect over the Named Pipes protocol, I need to add a domain account to each machine.
What I want to do is to access the database remotely using the 2 other machines without adding any user; I'm using Windows authentication.
When you use Windows authentication, you need to have the same Windows account on both the machine making the request, and the server.
To do what you are trying to do, you would need to use SQL Server authentication or user impersonation. Personally, I find user impersonation to leave too many potential security holes, so I recommend SQL Server authentication.
Very top level question so very top level answer:
Extend and manage permissions by Active Directory groups. Place individual user's accounts into the active directory groups. You are now managing permissions from an AD perspective and not by a individual machine perspective. ie user mgmt happens in one place instead of distro.
This way you are not constantly adding/removing users to multiple machines. They are just placed in the group and have access to X number of servers due to permission inheritance.
It also saves you from hard coding sql account credentials into distributable applications. Not a huge concern if this was a web application but think what would happen if you had the need to cycle your sql user password and you had your wpf application installed on X number of machines...becomes a management/release nightmare
I'm creating a web front end for some common Active Directory tasks. I'm planning to store service account credentials in the database so that they are able to be changed by the end user. How can I safely store the password when I need to pass it to AD?
Do you need to support different domains / use different accounts for accessing AD ?
If no, I suggest to not store credentials at all, but let your process run under a specific user account. (using IIS or a standalone service.) Some time ago, I used a Windows service for that
(see https://www.rsprog.de/aspnet-webapi2-angularjs/).
If you really want/need to store passwords, you can use the MS Data Protection API. See
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata
I have used it a few times and it has proven to be a solid and reliable approach.
But be aware that anyone who knows your algorithm and entropy and has admin rights on the server is able to decrypt (if he is able to let a process be run under the service user).
Description of my problem sounds somewhat complicated, what makes me think that my approach is flawed, so I will also appreciate any better idea.
Short description:
Given connection string to MSSQL 2008 DB and website name deployed on IIS6, I want to verify programatically whether website is able to connect to database.
Long description:
I have MSSQL Server database, let's call it portal_db.
I have an application deployed on IIS6, called portal. I can access it by url http://localhost/portal . In Web.config file I specified connection string to my database, which look like: "server=(local)\SQLEXPRESS;trusted_connection=yes;database=portal_db"
Web application is accessing database using System.Data.SqlClient.SqlConnection, without any wrappers, ORMs, mappings, anything.
Website is configured to run in appool PortalAppPool. It's using ApplicationPoolIdentity as a security context.
It is not possible to easily modify web application code (particularly the way it accesses database)
When my web application tries to connect to database it either succeeds or fails, depending on whether user IIS APPPOOL\PortalAppPool is configured in MSSQL database. That's a part which I understand, but when deploying my app I often forget to create new user/login in db for apppool virtual account. So what I want to do, is to verify from separate, standalone, console app (preferably written in C#, but not necessarily), whether my web application can access database, in following way:
Read connection string from Web.config
Read app pool identity settings (managed to do this by Directory Services API)
Impersonate identity with credentials defined on app pool (using impersonation class I found here: http://platinumdogs.me/2008/10/30/net-c-impersonation-with-network-credentials/ which uses ideas found in many other places, including MSDN)
Open SqlConnection with connection string read from Web.config
It boils down to following snippet:
using (new Impersonator("IIS APPPOOL\\PortalAppPool", "", ""))
{
SqlConnection conn = new SqlConnection(databaseConnectString);
conn.Open();
}
Everything works very well, when my app pool security context is set to any other value than AppPoolIdentity - specific user, local system, etc. When I change credentials passed to Impersonator to my user's name and password, I get desired result (exception when I have no login mapping in database, and everything is OK when I add one). But I just seem to not be able to impersonate IIS APPPOOLS\PortalAppPool virtual account - just have no idea what parameters should be passed to LogonUser - I would not be surprised if it would not be even possible. Maybe I am focused on impersonation approach too much (I am using it to access registry keys and services of other users and it works good), and maybe there is some better way.
If you have any other, better ideas, or need some more explanation to this problem, please let me know.
I don't think you can impersonate a virtual account (IIS service account). They are special service accounts setup mainly for IIS security. They are for local services only and cannot be attached to any domains. Virtual accounts in Windows Server 2008 R2 and Windows 7 are "managed local accounts" that provide the following features to simplify service administration:
No password management is required.
The ability to access the network with a computer identity in a domain environment.
You cannot "Log into" a virtual account, they are used by windows for security purposes:
Some light reading if you have time:
This gives a brief overview of MSAs and Virtual Accounts
The differences between MSAs and Virtual Accounts
The dirty details on each and how to manage them
To solve your original problem, you could build an app that could do the same logic but check the sql server if it has the correct users setup instead of simply trying to login with the account.
The basic setup is classic - you're creating a Windows Forms application that connects to a DB and does all kinds of enterprise-y stuff. Naturally, such an application will have many users with different access rights in the DB, and each with their own login name and password.
So how do you implement this? One way is to create a DB login for every application user, but that's a pretty serious thing to do, which even requires admin rights on the DB server, etc. If the DB server hosts several applications, the admins are quite likely not to be happy with this.
In the web world typically one creates his own "Users" table which contains all the necessary info, and uses one fixed DB login for all interaction. That is all nice for a web app, but a windows forms can't hide this master login information, negating security altogether. (It can try to hide, but all such attempts are easily broken with a bit of effort).
So... is there some middle way? Perhaps logging in with a fixed login, and then elevating priviledges from a special stored procedure which checks the username and password?
Added: OK, so integrated authentication and windows groups seem to be a fair choice in most situations, so I accepted the relevant answer. Still, if anyone can come up with a non-integrated authentication solution, they'll get an upvote from me.
For WinForms use Windows groups. No passwords are needed because the credentials are inferred from the Windows login using your application.
This is best practice
Basically:
The user belongs to a group (assumes single domain)
Group is a login in the SQL Instance
SQL login maps to a database user
DB User belongs to a DB role
Role has object permissions
It's worth reading up first before having someone try to capture all the information here
Edit:
If you have a workgroup, you can still do it by setting up sqlbox\bob, sqlbox\hans etc in a sqlbox local group.
When someone tries to connect (say bob on his PC) windows will ask them for their details. As long as bob knows his SQLbox account detailsm he can connect.
But then, I've not tried this in a workgroup setting...
In addition to using Windows Domain/AD Groups (put the AD groups in appropriate roles you create in SQL Server, so all account maintenance moves to AD), be sure to use the Application Name in your connection string - this allows you to see which applications are performing operations in the profiler etc.
Because when everyone is logging on as themselves from different applications - windows and web, it helps to know that it's actions taking place through an application and not just any user's ad hoc query through ODBC and Excel, say (if you allow users access to certain views for data export or report writing).
Can't you use Active Directory Groups to make the management of the db connections easier?
From MSDN...
The name can be a Windows user name or a Windows group name, of the form DOMAIN\Name.
That way you may have a few groups, read-only, editor, manager, admin etc. It's how I have achieved similar things in that past with Click-Once apps.
It really is the best choice for what you are doing.
I am assuming this is an existing app? If it was new I would otherwise say to go client server with web-services or similar.
PK :-)
With regards to wanting to hide your authentication and use a single application login with WinForms, if the login has very little privilege - select only on views and execute only on stored procedures, anyone who manages to reverse engineer your encryption of the login information in your application will only be able to perform the same functions they could perform in your application. If you absolutely have to raise the level on the security, you could authenticate each stored proc against your users table (poassing user and hash to each SP). Also, rotate the central application login on a regular basis.
All this is a lot more difficult than using integrated authentication and implementing AD platform in your environment. So you're effectively writing your own directory and authentication instead of using one off the shelf.
In addition to gbn's update about workgroup versus domain, you can run the application with RUNAS /NETONLY /USER:SERVER\USER with user credentials on the domain or server which your machine is not a member of. At the point that the application makes the connection to the database, the remote credentials will be authenticated and used. I have an application which actually checks to see how it was run and if it not run with a particular switch, it prompts for username and password and then re-runs itself using the Windows API using a function equivalent to RUNAS /NETONLY /USER:DOMAIN\USER. This is because our workstations are not currently on the domain (or on a domain with a trust relationship) of the SQL Server. In this case, you could still manage the security in local groups on the SQL Server or groups on the domain of the SQL Server. You would basically just lose out on the automated authentication token.
I have a situation that users access remote MySQL server in C# application.
Basically,
A user using C# application on his/her desktop ->>>> connects to remote ->>>>>>>> [ REMOTE ]
How do I securely hide database connection detail?
I have few ideas, but I don't think they are safe.
Encrypt database connection data into a file and store it within application directory.
prompt login page and let a human enter username/password, then transfer database connection data to user's computer.
No matter what you do if the credentials end up in the application in cleartext you are vulnerable.
Either implement a service layer in front of the database or if direct connections are essential try and come up with a scheme that allows a unique databse account for each user and then authorise them appropriately on the database.
Generally, it's better to ask the user for the credentials so that each account can be enabled or disabled by the administrator. Barring that, there are APIs for encrypting all or part of the configuration file. Here's a sample article:
http://www.codeproject.com/KB/dotnet/EncryptingTheAppConfig.aspx
I would suggest some form of session management based on user credentials. This can be accomplished in many ways.
For instance, you may accomplish this by simply wrapping your database access with a back-end system. Your desktop clients are oblivious to the database and interact solely with the back-end system. Unfortunately, implementing this level of indirection is not trivial if you have to do it from scratch but it will certainly make your application more robust and flexible. WCF services can help accomplish this.