We are about to migrate an intranet web application from using a proprietary forms-based security to Active Directory. The application logs a variety of user actions, and there is a significant amount of data associated with user accounts. Our plan was to migrate all of these UserId columns in various tables: from a foreign key linking the proprietary system, to an Active Directory GUID. Login names are identical between the two systems, so migrating is not an issue.
However, we identified one major problem: Our security policy dictates that inactive users must be deleted from Active Directory. An orphaned GUID in our security logs makes the entries pretty meaningless to anyone viewing them.
How can an application maintain the human-readable basics (name, login, etc.) about a GUID that has been deleted from Active Directory?
We have considered the following options. One of these options may end up being the optimal, but we wish to try for better:
Denormalize the log tables and store name/login instead of a GUID (okay for logs, not so much for active data.)
Maintain a "cache" of AD object information where entries are never deleted
Keeping the AD account but deactivating/locking it down
I wouldn't fully denormalize the log table, but instead store the pertinent AD information alongside the GUID, as Tim said. However, if you will need this AD information in other areas, cache it in your user table. I would recommend against changing your security policy.
For logging, I favor the denormalized approach, but maintaining the id. I store the user's id along with other, human-readable indentifying information. For active user's I can still use the id in joins (if necessary). For inactive (deleted) users I have the human-readable form for use by the auditors.
We have decided to use a "cache" table that will store a dictionary of GUIDs that map to friendly user information. This will require a view that abstracts an AD user list, and coalesces in missing entries from the cache.
Related
I'm working on multiple projects for single entity, they want the user to have to register just once for all their products (something like Google where you have one Google account for products like Gmail, Drive, YouTube, ... etc.).
My choice for the technology is Identityserver4 with ASP.Net Identity as user credentials store. For this problem I decided to use separate database for Identityserver and separate database for ASP.Net Identity(User profile, claims, credentials, ... etc.) because, and based on my very humble experience, identity-server is concerned about authentication & authorization but not the mean of storing user data and how to register new users or keeping and maintaining the user data, please correct me if I have a misunderstanding here. I'm not very experienced with Identityserver so I think I'm doing huge risk by going with this design. For example, I have audit columns (CreatedBy, UpdatedBy, DeletedBy) in multiple tables in all of these products besides ownerId in most of the tables in these databases.
So my question is:
How should I reference the user (via CreatedBy, UpdatedBy, DeletedBy, OwnerId columns) in the central database in these products databases and should I ever do that (separating the user-store database)?
And in regards to the user-profile information (user-claims):
Those products share many of the information between users like (First name, middle name, last name, address, phone numbers, etc...) and they have other optional info (university, high school) and other that required by some, optional by some, and totally irrelevant by others.
Should I store all these claims in one central table (user-claims
table in the identity database) and then generate customized profile
via the ProfileService based on the the client (the user
authenticating to) and the accessToken (what the user allow this
client to see from it's profile data)?
I hope this question is not an off-topic here in SO and not too-broad.
It was a good decision to build your application with IdentityServer 4 and Identity framework. Because the combination of both has very powerful features (Authentication, Authorization, User management).
As you decided, implement this as one application in your echo system. So now this System works individually for User management, Authentication and Authorization. As an example create users, user groups, user claims, 2FA.... all should be handle in this Application.
Now you can Think above identity server as the third party application (think it as google). So when Login through google it gives us a token that token contains many details depending on what we requested (User ID, Email, Frist name.....).
Okay, now let's think about your second application in the echo system. it doesn't know anything about the users inside the identity server. It only knows the details coming inside the token.
Depending on that token details maintain a separate user table in your second application. you can use Email or userId to keep the mapping of the Identity server user and new Application user.
For all requirements in the second application use this table to refer the user.
I have a app that is running on a Remote Desktop Session Host Server that is tracking user logon/logoff/idle times, however I do not know where a good place to store the data I am gathering.
The user turnover rate is fairly high, a user account will only exist for 1-4 months and will have at most about 3KB of XML formatted logs associated with it.
The data needs to be retrievable from other users (specifically a service that other users query) so I think storing it in the users AppData folder is out of the question.
I was thinking storing a XML log in a Active Directory Attribute but I do not know if Active Directory is really designed to store text blobs in the 3KB range.
My last thought was using something like a SQLite database. However with the high user turnover rate I was hoping to use something that was stored per user. That way when the user is deleted the records are deleted with the user and I don't need to worry about keeping a database in sync if a user is deleted via methods outside of the management software I have set up.
What is the best option to log records in this situation?
I would suggest a log-folder containing sub-folders per user.
Running a (scheduled) powershell script to cleanup after deleting the account, or archiving if historical info suddenly gets a value.
The data is then at a specified location, easy locatable and accessible for (only) the user without polluting the AD.
I have a very basic question and want to know how other experts do this
I have an application with some 100s of users. I have been using SQL LOGINS to authenticate these users. These users have password policy enforced. and I face difficulty when any user's password is expired i.e. i have to reset it from SSMS myself. It sometimes becomes a difficult job along with other tasks that i do.
I was told by some experts that it is a good practice to create my own user table and have all the user details in that table. I have created a user table with following columns.
User Id
User Name
Password
PasswordCreationDate
PasswordExpiryDate
PasswordActive
One simple question. How do my users connect to the database . Offcourse i would need a connection string from the application. That connection string would require a user name and a password isn't it? and I can not get the information from the user table until and unless i am connected to the database.
Another problem, how do i keep track of last 5 password. The policy says that the user can not use any of the last 5 already used passwords.
All this can be avoid if I can get a solution of notifying my users that their Password is due to expire in 'n' days and they must change it before it expires.
What do the other developers do when authenticating their users. Please Guide Me
If you keep your user's login credentials in the database, then for access to sql server itself you may only need one login for the entire app. This login would have full access to your database, because it would be up to your application to enforce access rights.
If you go this route, you need to be aware of two things:
There is still a security concern for larger applications that need to give ad hoc reporting capabilities to users through tools such as Reporting Services, Crystal Reports, Infomaker, etc. In this case, users can use these reporting tools to gain read access to areas of the database they should not be able to see.
If you store your own credential information for your users, you need to make sure you do it properly. That means no plain text passwords. You need a cryptographically secure password hash (not md5!) and a per-user salt. If that's greek to you, best to leave this alone.
Another option open to you is to use Active Directory/Windows Authentication for your database. The trick here is that you still have to set up access rights for all your users. However, you can use Active Directory groups for this to reduce the number of logins you need to create, and it will at least prevent you from needing to reset Sql Server logins by hand, because users will log in with their Active Directory account.
A pretty common scenario amongst web applications is to use one username/password (so only one sql login, typically some kind of dedicated login with minimal rights for the application). This way, connection pooling can be used. This is of course a backend account, configured in the web.config and not visible to the end-users.
The users are maintained as a type of data within the application. Asp.net comes with a solution that is called Membership. User authentication is done against the Membership provider and several classes give you programmataic support for authentication, roles, etc. You can use AD as a provider for example, or forms authentication. Or you can write your own.
Since you are now using a dedicated sql login for each user, you need to be aware that this approach moves data access security to the application level. So this might not always suit your needs.
Ideally you'd use existing Active Directory infrastructure to handle your authentication/authorisation of individual users, and you could then have end-users' credentials passed via the web server to your SQL server (You'd probably need to look into handling the Kerberos "double-hop issue" to effect this).
But failing this, it's easy to set up so that the application it self has a SQL login to access the database in order to retrieve user level authentication information. One-way hashes on user passwords would ensure that even if the app's password is read from connection string, user passwords can't be obtained.
Or somewhere in between those two solutions, where the application has a service account within AD, which has access to the SQL database, in order to retrieve the user account info from within the DB.
Either way, if AD is available you can secure further with Kerberos Service Point Names to ensure database access from only your expected end-point (ie the ASP.NET server).
I'm developing an application that manages information about users and save the data in a SQL Server. I would like to 'somehow' connect this application with our Active Directory, so all the changes this app will make will be reflected in the Active Directory too (if we add a new user in the app, it will be added also in the Active Directory)
Is it possible? if so, which are my options?
Thanks in advance
Don't do it. Let AD be the authoritative copy of your user base, and let the users always be created in AD first and then propagate to SQL. By letting users be added through a different path (SQL first) you open a huge can of worms with regard to security. If a user is defined in SQL but not in AD, what exactly is taht user? How can he log in? To what groups does he belong? IS he allowed access or not to this resource or that resource? How about cases when an user is added in AD and in SQL with different characteristics and then you need to reconcile.
Modify your application do always create the user in AD, in conformance with the AD policies and security requirements (password complexity being the most trivial example). Then let AD synchronize with SQL.
The way I chose to solve this problem was to add an event that was triggered when I saved my user object. The listener on this event would then send an update to Active Directory. In my case I was doing a one way sync to Active Directory and it was also a best effort attempt, meaning if it failed I was fine with it. If you need to do some more reliability around it you will want to wrap your SQL updates inside of a transaction and only commit after active directory is updated.
If you need a two way sync with Active Directory you will need to look at doing some sort of a background synchronization with Active Directory where you iterate over your users and check for updates in AD.
If you are doing a one-way sync to AD, I agree with Aaron that you should simply have a Trigger in SQL server. Note that this solution may suffer from some problems, like the user accounts already created, user name or password doesn't meet the AD complexity rule. You need to then find some ways to log the error. You may also need a tool to do initial provisioning of your database accounts.
If you want to do two-way sync, I suggest you to read up DirSync. You probably need to write a NT service to do it. I hope you don't store password in your database. I highly suggest you to use Windows authentication. If you do need to sync up the password, you may need to write your own passwordsync and install it in all the domain controllers in your machine.
If you are developing a solution for enterprise, you should look up the existing meta-directory solution products from Microsoft, MIIS, ILM, FIM.
They are all the same thing except with the names different. Many enterprise has adopted this as their meta directory solution. You just need to write up an extension to leverage on its provided infrastructures to do the identity synchronization.
We have audit table in our database.
Records to this table are done using triggers.
Currently, there is nothing that prevents user to log on to database server, open table from management studio and change data in audit table.
What are possible mechanisms that can prevent (or at least detect) cases of audit data tampering?
I'm thinking of adding one column in audit table which should contain some hash calculated based on values that are entered in that row. However, since audit is done using trigger, malicious user could open any trigger and see the logic by which this hash is calculated.
EDIT:
I was not clear enough. Application user does not have access to database. I was referring to some user like DB admin, with appropriate rights on database. Still, if this DB admin logins and has rights to temper with audit table, I would like to have some mechanism to detect this tampering at least.
Nothing can prevent someone accessing your database via SQL manager from changing the contents. You can make it tamper evident though.
Basically you need to use HMACs which are keyed hashes. Unfortunately this leads you to requiring key management to ensure the key stays secret which may not be possible in triggers. We use a cryptographic service to provide the key management but this is accessed from code.
You also need to think about a users ability to delete a record rather than change its contents. We ended up with two HMACs, one calculated using the contents of the record (to make changes to a record evident), the second using the current records HMAC and the HMAC from the previous line to make any line deletion tamper evident.
Then you need to worry about deleting the first or last x records. For this we use a trailer and header record which always have the same contents, if those aren't present then the top or the bottom of the table has been deleted. The combined HMAC of the header uses the record after it rather than the record before (as there is no record before).
And, of course, if you are going to be deleting old records to manage the amount of data you store you'll need a mechanism to add a new header record after the deletion.
Here are some possibilities:
You can't prevent or detect tampering by somebody with sysadmin (sa) permissions. If you don't trust your system administrator, you probably have worse problems than this specific one.
It's difficult to prevent or detect tampering by a domain or local administrator. Such a person can restart SQL Server in single-user mode and gain access as a sysadmin using SQL.
To detect tampering by the database owner (dbo), you could use Server Audit in SQL Server 2008 or a server-side SQL Trace in earlier versions of SQL Server.
You can prevent tampering by other users by restricting their permissions to the relevant triggers and audit tables.
you could enable Change Tracking so you have kind of "Audit on the audit table".
if your infrastructure is properly managed I guess users do not have sa rights and they use Management Studio to see the database logging in with their windows account, in this case you can set security on that audit table, only sa and other administrative accounts will be able to change content but not normal users/developer accounts.
Hope this helps.
The problem you're describing may indicate a more serious problem in the architecture of your system.
Usually, users shouldn't even have direct access to the machines running the database.
You may want to consider an architecture where the database machine is separated from your business logic machines, and are accessible only to them.
If your users decide to try to access your servers not through your clients, then all they should be able to do is reach well defined web services that you decided to expose.
There's no reason that a user should be able to access a DB machine, or to have the credentials of an account that is allowed to write to the database. You seem to be worried about tampering with audit information. What's to stop a malicious user from deleting tables or tampering with functional data?
Separate the audit data into its own schema and then set permissions such that the users you're concerned about don't have access to that schema.
Use an entirely separate database which could even be on a different machine.
I often see some type of publish/subscribe model used to publish audit data from a relational database and then asynchronously write that audit data to the audit store.
Perhaps you could have your triggers write audit data to a queue. Then you could have a scheduled job that runs every few minutes to take audit data from the queue and write it to your audit store.