Using Active Directory to authenticate users in a WWW facing website - asp.net

I'm looking at starting a new web app which needs to be secure (if for no other reason than that we'll need PCI (Payment Card Industry) accreditation at some point).
From previous experience working with PCI (on a domain), the preferred method is to use integrated windows authentication which is then passed all the way through the app to the database using kerberos (so the NT user has permissions in the DB). This allows for better auditing as well as object-level permissions (ie an end user can't read the credit card table).
There are advantages in that even if someone compromises the webserver, they won't be able to glean any/much additional information from the database. Also, the webserver isn't storing any database credentials (beyond perhaps a simple anonymous user with very few permissions for simple website config)
So, now I'm looking at the new web app which will be on the public internet. One suggestion is to have a Active Directory server and create windows accounts on the AD for each user of the site. These users will then be placed into the appropriate NT groups to decide which DB permissions they should have (and which pages they can access).
ASP.Net already provides the AD membership provider and role provider so this should be fairly simple to implement.
There are a number of questions around this - Scalability, reliability, etc... and I was wondering if there is anyone out there with experience of this approach or, even better, some good reasons why to do it / not to do it.
Any input appreciated

Having used ADAM in a project, I found it to be bear. Documentation for developers can be sparse, it has quirks that differentiate it from full AD and, most importantly, I could not get a straight answer from MS as to whether it will be fully supported in the future. The impression I got was that ADAM was the bastard child and that the new Federated services (ADFS) was where they wanted people to go. Just moving the ADAM store from one member server to another was a pain. Now that said, my issues with ADAM had to do with development against and maintenance of the store, It definitely has the ability to scale and it was reliable. That said there are times when you need to delve into 80th level spells of LDAP/Directory magic to figure what it is or is not doing.
For a public facing site, AD/ADAM might be overkill IMO. You could use alternate MembershipProviders like the SqlMembership provider to get the good level of security with respect to credentials. If you wanted to go further, you could use database encryption (SQL Server at least has this ability built-in) to encrypt information that falls into the PII (Personally Identifiable Information) arena and of course encrypt the backups. The advantage that a database backed authentication store has is that you have all the tools that your database product provides to scale out, do backups, control access and so on.
EDIT: Let me add, that with .NET you can setup your site so that it runs under a Windows user and connects to the database using Windows Authentication (assuming the db supports it). Thus, no credentials need to be stored in a config file. However, if you had to store credentials for whatever reason, you can then use DPAPI to encrypt the credentials in the config file.
ADDITION In response the question about securing encryption keys you have a couple of choices. The first is to simply hash the credit card numbers. That greatly simplifies any problems with access to the data however, it means that the customer would have to re-enter their card number for each purchase. If you want to remember the customer's card number, then you move into a new realm of maintenance of the decryption keys. In this scenario, you absolutely should use Windows Authentication to the database and look into SQL Server 2008's Extensible Key Management feature which lets you hook-in a third-party key management program into SQL's encryption functionality. In this way, only the website user would have access to the keys used for decryption. There are other solutions to ensure that the website cannot be compromised. The greater worry is that someone gets a copy of the database undetected. Here's a link on using SQL Server to be PCI compliant:
Deploying SQL Server 2008 Based on Payment Card Industry Data Security Standards (PCI DSS) Version 1.2.

couple ideas
Run AD/AM - Active Directory Application Mode.
It scales well. It's the same core code as AD. Similar management capabilities. Solid reliability. Works with the ASPNET AD Membership Provider.
And it's included in Windows.
Also consider exploring a federated identity system, via ADFS 2.
unlike AD/AM, this approach is fairly leading-edge. The final version of the ADFS v2 server is not yet available from Microsoft, but it is at "release candidate" stage. If you have the stomach to be an early adopter, ADFS2 holds the possibility to employ a federated identity approach. That means you could accept identity tokens from a variety of existing sources: a google sign-in, a yahoo sign-in, any OpenId source, and use that as the identity on your site. Users would not have to "register" and authenticate to you. Instead, your site would honor the identity and authentication provided by some trusted third party, and perform authorization based on that identity.

This is not a direct answer but having a AD user account means you need a windows CAL for that user. Another way would be to issue client certificates to user and map client certs to AD users in IIS.
You might also consider AzMan with SQL store available from Windows 2008 onwards or the open source netsqlazman.

Related

Best practices for connecting from ASP.NET Core to SQL Server?

I've had some recent difficulty with SQL Server not liking the default AppIdentityUser for logins, so I went ahead and created a custom DB user with write access.
But it made me wonder - is this the best approach?
I was wondering what the best SQL Server login approach would be for Asp.Net Core. I know there's a question similar to this for normal .NET, but you can't encrypt a Core web.config/appsettings.json (well, in a quick and straightforward manner).
Here are the options as I see them:
Connect via SQL Server ID that is stored in appsettings.json.
Pro: Already configured.
Cons: Password in web.config/appsettings.json; have to specifically configure SQL Server ID. Not centrally revokable.
Connect via user NT ID via ASP.NET "AppIdentityUser".
Pro: No passwords in appsettings.json.
Cons: Not centrally revocable. Seems to be restricted to the server name for user.
Connect via Active Directory user.
Pro: Easily revokable.
Cons: Active directory user password in appsettings.json. Could be bad if somebody accidentally reuses that user in another application in the company, and that user gets breached.
Are there other options that I'm missing? Which of these options are used in which situations? Which are more standard? Are there pros and cons that I'm not thinking about?
You should absolutely use a custom SQL Login to connect to the database. Under the hood, the SQL Login could be tied to a local account, service account, network account, etc. It doesn't actually matter.
The real issue you seem to be having here is in not wanting (rightly) to expose login credentials in plain text. I'm not sure why you keep referring to Web.config here, as ASP.NET Core doesn't use that. Instead, there's various configuration providers that can be optionally utilized. By default, ASP.NET Core (at least since 2.0) adds a JSON config provider that looks for appsettings.json and appsettings.{environment}.json in your project, a command-line configuration provider, a user secrets config provider, and finally an environment variable configuration provider.
The last two are the most interesting for your circumstances. In development, you should use user secrets. In production, you should use environment variables. However, neither stores secrets in an encrypted way. The benefit to either approach is that the secrets are not in your project, and therefore also not in your source control. Even though neither is encrypted, it's not as big of a concern as you might think. Getting at the secrets in either would require direct access to the server/development machine. Additionally, user secrets is by default tied to a particular user account, accessible only to that user, and environment variables can be set up the same way. Therefore, someone would need to both gain access to the machine and gain access to the particular account. That's actually a pretty high bar, and if it were to occur, exposing a database password is really the least of your concerns at that point.
Nevertheless, if you want true encryption, you have the option of using Azure KeyVault. KeyVault can be used whether or not your application is actually hosted in Azure, and while it's not free, it's exceedingly cheap.
Finally, you can always create your own config providers or source third-party ones. For example, while the default JSON provider doesn't support encryption, you could potentially write one that does.

Retrieving all users and roles in a .NET Web Application through ADFS

We have a hosted .NET web application (Windows Server 2012 R2 environment) and we need to provide Single sign-on (SSO) to users from a corporate LAN environment. We have used ADFS to enable SSO and it is working as expected thus when a user hits our web application login page URL he is authenticated against ADFS and is automatically logged in to the application.
We have an additional requirement where we need to obtain a list of all users, their groups, email addresses some additional information periodically from their Active Directory so that this information can be bulk loaded into our web application however since ADFS is implemented we do not have direct access to the Active Directory.
Is it possible to connect to ADFS and obtain a list of all users, their email addresses etc. programmatically?
If the above is not possible then what is the recommended approach for this kind of a setup?
Thank you.
No, this is not possible. There is no such API because with SAML and WS-Federation, users can come from anywhere. This does not have to be AD, technically it's possible create a "Log in with Facebook" implementation.
What would you need the information for? The user's claims contain all information which you might need (user name, e-mail address, group memberships).
If you really need that information about all users in your application, perhaps ADFS is not the solution you are looking for.
As Alex mentioned above - the way it works, ADFS does not provide any way of importing data from the AD or other trust stores. It just gives you the information that are carried over with the token.
In case you need more information, you should extend the number of claims being issued by ADFS. You can then collect the information - when the user comes for the first time, use the data from the token and fill the profile. If it is returning user - update the information if necessary.
The other solution (but I wouldn't say it's recommended - rather a workaround) would be to implement custom solution for importing information from AD to your application. I'd say it's fair as long as you use your local AD for reading this data. In the moment you decide to extend the access to third party (e.g. partner company), which might be using different identity provider, which doesn't have to be backed by Active Directory any more - you find yourself in tough spot.

Granting Secure Access from one website to another

I'm really just looking to see how much folly is in the below suggestion from a security perspective.
I have two websites. One is an administration portal and the other is a members portal.
Within the administration portal administrators can retrieve a listing of members and I need to offer the ability for administrators to login to the member portal without having to enter the members login credentials.
Both are separate websites within IIS and for this discussion lets say they are on different servers.
Both websites access the same SQL Server database.
I was thinking that I could on the administrator clicking a "Login as Member" link create a random code string and save this to the database along with the member number.
I could then pass the code and member number to the member portal as query string parameters.
The member portal then read in these values and checks them in the database to verify that the code string exists and if so that it matches the member number also being passed. I could then login the member and set a flag in the database to set the code as being used and therefore invalid for future requests.
I'm thinking to bypass this a hacker would need to successfully guess the random code and pass that to the page alongside the corresponding member number for that code and for that combination to be marked as unused in the database.
This would seem to be unlikely given that only seconds will pass between the code being generated and the code being used.
If necessary I could always check the IP address of the request as users of the administration portal all share the same fixed IP address.
So do you think the above would stand up to scrutiny on a security review or will I need to go down the SSO route?
Your approach is very sound. I can confirm because I have implemented just such a solution for just such a reason. We analyzed the options and exposure. And after implementation, our application passed a PCI Complaince Audit.
Reasons:
SSL is Esential! protects against sniffers. Essential. Without Encryption, sniffers could detect your GUID and may have a window to use it)
As Tony pointed out, the GUID is effectively unguessable.
Guid Tokens expiring should expire within 24 hours.
Suggestions:
Checking against IP is good. But don't be fooled into a feeling of security from it. Anyone can fake IP's in headers. To be Secure against XSS and CSRF by using AntiForgery tokens.
The AntiForgery token is a cookie that populates your HTTPHeaders with __RequestVerificationToken which is almost as hard to guess as your GUID.
Consider using an established Authentication framework like .NET Identity 2 and multitenancy.
An established framework takes the burden of encrypting your passwords. MS Frameworks like Simple Membership and Identity integrate into modern ASP.NET frameworks and give you very strong base of functionality to lean on.
If you're using an old framework like classic ASP or .NET 2.0, the classic Membership Provider is more appropriate.
If you are creating new MVC 5 applications utilizing Entity Framework, I strongly suggest using Identity 2.1.
Consider Mult-Tenancy. While there is nothing wrong with your solution, if Admins and users shared Membership Provider, your solution would be cleaner. An admin could log into the main site and "get" the token from the DB. Then no exposure.
Assuming the use of HTTPS and adequate physical and IT security processes and procedures in place for the administrators, this method should be adequate. It is more secure than most financial website password resets, which typically only require a compromised email account and some personal information to reset the password. If you check the IP address range of the originating client request as well, a hacker would have had to already have access to your systems or network. Also, if you make the code a GUID, it would be (pragmatically speaking) impossible for someone to guess.
You could add a layer of checking for hack attempts by storing a record in the database each time this event occurs (or at least each it fails due to a bad key), and each time it occurs run a check to see if it is happening too often (like 100 times in the past hour, or something--the right number depends on how often you expect it to happen). If it's happening too often, then have it send an alert to IT personnel and revert so that the user has to enter their credentials manually.
Disclaimer: I am not a security expert by any means, so I'll gladly defer to anyone claiming such status. I'm weighing in here due to a lack of answers.

Security Issues ASP.NET integrated Authentication

We currently use a connection string to authenticate our database credentials. Due to grown and compliance the developers are no longer allowed to "see" the database credentials that our websites use. Are solution to this problem is use Integrated Authentication. We planned on setting up a user per App Pool and then allowing that use access to the Database.
My question is: Are there any security concerns around this approach? As far has removing the DB credentials from the connection string, is there a better(easier or simpler) approach we should/could be taking?
If you need to secure and audit access to the production database then Windows Authentication is a better choice than Sql Authentication for a number of reasons:
You can control exactly who can access the database via NT groups and permissions, which means you know who specifically has access to the database. The pool of access with sql authentication is only limited by who knows the password. Given n people who know the password, tracking who did what at a certain point of time is trickier (but not impossible) given that.
Only your sysadmins need know the password for the nt identity with access to the database; in fact, much of the config can be done only knowing the username
Logins and access can be tracked at the domain level far more easily than with SQL Server logins.
What it wont give you is:
Ability to ensure that the developers can't see production data - whoever writes the app can easily include some diagnostic routines to select out data
Ensure that production data only stays in production - anyone making a backup of the production database (say to restore it to a UAT environment for testing) could easily expose production data.
Problems with this approach have already been discussed in other posts; in particular, with ASP.Net applications, you have to consider whether or not you are going to use Impersonation/Delegation (webserver can act as the NT user accessing it) or a Trusted User model (where you configure a fixed identity to access certain resources).
This is further complicated by the IIS version you are using.
If your connection string is stored in a web.config file, you could create a separate production version of that file that the deverlopers can't see. That's easier to test and setup than integrated authentication using app pools.
One word of warning though: If you restrict developers that much, it will slow down their velocity of change. Since the rest of the world does keep moving, this usually ends with the application becoming a dead legacy package. That's dangerous if you plan to grow, improve or extend.
Use of application pool's identity can be quite complicated to set up, consider trust and delegation problem.
A better option can be securing connection strings using encryption.

sql authentication or Windows auth

For my asp.net website with forms authentication, I will use Windows integrated security to access a sql database. I will give DB permissions to the ASPNET or NETWORK SERVICE. Under what circumstances would I use SQL authentication instead?
SQL authentication is also often required when your site is being hosted by an external ISP. They often do not support windows authentication or do not allow you the ability to grant permissions to windows accounts.
Use SQL Auth when you need non-Windows machines to make a DB connection.
Keep in mind that it adds another attack vector (another set of credentials to compromise the machine), so make sure you really need it before using it.
Really you use SQL Authentication when you can't use Windows Authentication. In my opinion that is about the only time. Windows authentication is more secure and can be centrally managed in places which use Active Directory. If you have people who really know how to adminstrate Active Directory and you're in a windows environment, there isn't a good reason to use sql authentication.
With Sql Authentication you have to manage the passwords etc in connection strings and that means that in order to change the account accessing the database, someone has to know how the application functions or at least where the information is stored. With Windows Authentication, all the network admin has to do is enter in the correct username and password into the IIS application settings and you're ready to rock and roll. No developer interaction required.
You have extra steps in securing the connection string information as passwords etc. should be encrypted when stored in the config files. All around there are a lot more steps in invovled in efficiently and securely using Sql Server authentication as opposed to Windows Authentication. This is espcially true if the same sql server credentials are used to access multiple databases across multiple servers.
If you want to completely manage user accounts, you should use SQL Authentication.
This way, you have complete control over user accounts. You could force them to enter private information for example.
Also, like Corbin mentioned, if clients are not running windows OS, you cannot use Windows Authentication (obviously).
Please be reminded that Windows Authentication is the recommended mode of authentication for the simple reason that it inherits the OS authentication. There are many factors that you may not use Windows Authentication as explained above.
That depends. If you are developing a in house web app and the network IT people are down the hall then use Windows authentication. If you are deploying your app to customers and you have no control of their network infrastructure then I would use SQL authentication
If you don't have control over the Active Directory (Like in a hosted situation) or there are users with operating systems other than Windows, you don't have a choice.
Is there a need to create user accounts on the fly with some script? It has to be easier to do for a sql user than the Active Directory (Probably not impossible).
Besides all of the above, consider a case like this:
The account you need to use is from Domain A.
The database is on Domain B.
Domain A and Domain B dont have a trust relationship.
You will need SQL authentication to get past this situation.
Hope this helps.
(To add more clarity): The database is NOT registered with the active directory. Then it is not posisble to use windows authentication.

Resources