I'm just starting to spec out a project that will be a fairly advanced DB with a fairly simple MVC front end, accessible over the internet, I'm unsure of how to handle users, I can see two options:
Option 1 - Use SQL Servers in-built Logins/Users to handle user authentication and use the in-built user access to control who can access what (almost everything will be selects or stored procs).
Option 2 - Use my own list of users (with hashed salted passwords) and my own access control list (possibly using proc name and OBJECT_NAME(##PROCID) passed to another proc) and do all writes/reads of the DB through an application profile with access to all procedures/views.
I've searched but can't find any reasons I should pick one over the other, can anyone share a link or provide reasons why one is better that the other (or if there are glaring issues with both)?
If you need any more details please let me know.
If using SQL authentication (Option 1 for each user) via a connection pool, you're going to get comparatively poor performance. You'll get pooling for each user, but that could still mean 100's or 1000's of connections. There are ways around that, but the solution begins to start making Option 1 work like Option 2, so you might as well use Option 2.
I've seen a few solutions that create SQL Accounts to do the inital authentication for each user (via a single application based SQL account), then the rest works like Option 2 (again via a single application based SQL account). Those cases were using lots of SQL accounts, so each user could own a set of Views, and imitate Schemas. As Schemas & Aliases have been available since SQL Server 2005, it wouldn't be worthwhile to pick option 2 anymore for that reason.
Finally, don't use SQL Server Application roles either - they're bad security practice. Brian Kelly covers a few of the issues (pos & cons) in an article about them (http://www.sqlservercentral.com/articles/Security/sqlserversecurityprosandconsofapplicationroles/1116/).
Related
We currently have a SQL Server 2008 instance set up for our ASP.Net MVC application, and the SQL Server instance uses built-in auditing (I believe CDC?)
We also have our ASP.Net application set up to use one connection string specified in web.config for the entire application, no matter who is logged in (of about ~50 users)
The problem: We want to be able to include among the audit information the username of the user who made the particular change in question.
It looks like we can only do that in one of two ways:
Change our application setup so that every single user gets their own database login. This would require us to use dynamic connection strings (perhaps not too terrible), but moreover it would be a pain in the ass to add a new user to the system and the admins could no longer do it automagically via the application's interface (I think).
Use another solution from within the ASP.Net app itself. This would allow us to trivially add any bit of information in the application we wish, but would involve scrapping the entire builtin solution and essentially starting from scratch with a significant effort.
Someone must have run into this problem before with auditing - is #1 feasible? Or is #2 the only way we can go here?
Thanks
Option #1 is pain for the admins, a little complicated code for "dynamic" connection strings, and calling sp_addlogin to create users. But the worst is that separate DB login for every user also allows them to query DB directly (if they know instance & database names, which could leak to them in any way and "see" DB server through the network). Direct access to the DB is something that may crash every application. Don't do it, unless you're very sure that DB server is not directly reachable to the users.
About #2. How about adding column "LastModifiedLogin" to every table, where you put login of logged in user during every insert/update? This shouldn't crash CDC and you got what you want. However auditing delete is little problematic, because you issue statement and have no longer row where you could place the login. You may organize seperate "DeleteAudit" table where you put name of table, row identifier and user login on every delete, but that's only rough idea.
If you use NHibernate for data access, I would advise you to consider switching CDC to NHibernate Envers, which is very neat solution.
Good day all,
I am studing the following case:
Scenario: An application connects to the production database(SQL server 2008) using a generic "SA" user instead of the domain user. This is making traces\logs\organization harder, because everything is flagged as done by SA user!
NOTE: In the application the domain user/password is used, the generic account is only regarding to the database.
Questions: What would be the best pratice in this case? every user should have an account to log in the database? (sql using windows authentication) there are +- 500 users is that an issue regarding to database performance? or a generic account is indicated?
Many thanks!
As others have mentioned, Active Directory and Windows Authentication might be more appropriate if that's an option. But if not...
If the application has a central place that creates the connection & transaction prior to update, you may be able to use SET CONTEXT_INFO to pass along the "real" application user while still using a shared SQL account for the login.
Then in your auditing triggers you can pull the information back out again using the CONTEXT_INFO() function
This is the approach used by at least one commercial auditing tool
See also similar SO questions here and here which reference context_info and a blog post Exploiting Context_Info for Fun and Audit which gives an NHibernate example.
Nitpick on something else in your question: you said it's using sa user. Maybe that was just an example, but probably the application should not have so many rights on the server. Create a user with only the rights needed for the particular database(s) that application uses. This limits the impact of any future security vulnerability (e.g. SQL Injection) in your application. And to take it one step further, you might have one connection string with a read-only user account, and then at the point where you create a transaction to update data, switch to a connection string with the read/write user account. You still get most of the benefits of connection pooling, but you limit even further the impact of any application-tier bugs.
This is a repost of a question I asked 4 or 5 days ago, with zero response. Hoping for more luck this time...
(Using SQL Server 2008)
Within the next few weeks I plan to introduce SQL server to an office that is in dire need of a proper data server. Currently there is a heavy reliance on loose Excel and Access file (supplemented with frighteningly large amount of impenetrable VB code to do data manipulations) strewn all over the internal network.
We need SQL server for two things:
1. For internal databases that will be designed upfront and will be capturing data on an ongoing basis
2. For ad hoc uploads of datasets received from clients, which we then analyse
I am the only person in this office who is familiar with SQL. I will have to train the other 5 or 6 people to use it.
Now, my question is this: how would you guys set up the DBs so that it would be easy using Management Studio to visually recognize where what is being stored? To be more precise: if this were a windows file system it would look something like this:
c:\client work\client 1\piece of work 1 (db with 10 tables)\
c:\client work\client 1\piece of work 2 (db with 8 tables)\
c:\client work\client 1\piece of work 3 (db with 7 tables)\
c:\internal\accounting system\some db with 8 tables\
c:\internal\accounting system\some db with 5 tables\
c:\internal\some other system\some db with 7 tables\
etc.
So briefly, I need to visually split by internal and client work. Client work I need to split by different clients. For each client I need to split out the different distinct sets of work. (Internal work follows a similar pattern).
Solutions that I am aware of:
Run multiple data servers (e.g. one internal, one for client work). Not sure what the cons of this would be though
Assign schemas to tables
I would love to hear your suggestions!
Your organizational tools for managing SQL Server are instances, databases and schemas:
A server can run multiple instances. An instance is basically a completely separate server instance on the same machine.
An instance can manage multiple databases. The database is the standard boundary of integrity - you (usually) back up an entire database, referential integrity is constrained to being between objects in the same database, etc.
Each database can contain multiple schemas, which allow you to organize code.
All these "containers" relate to security in some way.
I recommend that you take an organization data and process inventory first, so that you understand what data you are dealing with, who uses it and how - with special attention on data which is public or collaborative (data used by certain people together) and which needs to be compartmentalized access (only used by a particular role). SQL Server is not really a great place of choice to be storing unstructured data - I would not view it as a simple replacement of a file server, for instance.
From there, proceed to define roles for your users. Having roles is a lot better strategy than assigning rights to individual users. It documents the semantic meaning of the access (any person performing this role needs this access as opposed to the user's identity - john and kate need access - this tells you nothing about why they need access). Be certain that the roles are sufficiently fine-grained. A departmental role like AccountsReceivable isn't nearly as useful as PaymentApprover or InvoiceProcessor or AccountsSupervisor. Users can act in multiple roles - this will give you a lot more self-documenting ability in your infrastructure and a lot fewer security holes and headaches.
This should help to define which containers you will need and what access to grant and guide your data infrastructure from there.
As far as giving users direct access, I'm with Randy Minder, SQL Server is only an expert user tool at best. If they are familiar with Access, a good option is to let them use Access against carefully designed and chosen views in SQL Server until they are ready for a more systematic data engineering approach.
IMO, users of your databases should not have to know or care where or how your databases are set up. And they shouldn't be given access to SSMS unless they are well trained in SQL. This is a disaster waiting to happen. You should be creating applications and/or reports that allow the user access to the data they need. That way they don't care where the data sits, and don't need to know.
In SQL Server you are able to have application role security, through which you are able to for example give specific permissions that originate from specific applications.
You can execute sp_SetAppRole() to set the application role but was wondering how this could be accomplished when using a LINQ2SQL datacontext with the least amount of friction.
I've seen this link:
http://social.msdn.microsoft.com/Forums/en-US/linqprojectgeneral/thread/e25e98a6-b0ac-42fc-b70c-2b269a7fa1cb but was hoping for a cleaner approach/
My conclussions (see below section for the why):
Using SQL application roles doesn't plays well with connection pooling and also shouldn't be used directly in final user apps (only on a business tier).
The SQL alternative would take away a lot of advantages from using linq, as it relies in SPs.
My recommendation:
If you have a business tier/server, do authorization at the application level instead of relying on sql authorization. If you still want to authorize, have an account associated to the business tier application, and associate a normal role to it.
If it is a client app that connects directly to sql. The user will still have the permission to call whatever his(her) identity has access to, and the app password is there. If you are not comfortable with the user having that level of access, you need a business tier.
If you still want to proceed with the approach, turn off connection pooling. To reduce the open/close overhead, open connections explicitly.
Full explanation/references:
One issue is it doesn't plays well with connection pooling. That is regardless of linq2sql. See at the end of this in msdn.
There are 2 alternatives since sql server 2005 (msdn link), one is also mentioned in the thread you linked to, but it also points out it can go wrong.
Note that its an unsecured option in a 2 tier scenario, like when the application used by the clients connects directly to sql. In those cases the pwd for any application in the client's computer would be exposed in those. Its more secure if it is a business tier the ones that connects, but that's precisely the case where you really want connection pooling.
The another alternative mentioned in my second link to msdn, works well with connection pooling. It is based on stored procedures, and the execute as statement. The execute as is called inside the procedure, and after the procedure is executed the context is reverted. That is great but really would be giving away a lot from what you get with linq2sql by going the sp route.
What is the best option for a windows application that uses SQL server authentication? Should I create a single SQL account and manage the users inside the application (using a users table). Or should I create a SQL server account for each user. What is your experience? Thank you!
Depends on whether the username/password for the SQL server would be exposed to the user, and whether that would be a problem. Generally for internal apps (in smaller organisations), one would trust the users not too log in directly to the sql server. If you have a middleware layer (ie webservices) the password can be hidden from user.
I prefer to use a general login for the DB and manage users in the application. Even if you do create a login to sql for each application user, they could still connect directly, so why not just use a generic sql login that is easier to manage. This is of course assuming all users have the same accesses.
One good practice, if the users potentially can get direct access to the db, would be to grant access only through Stored Procedures and not directly to tables, so that only certain actions can be performed. Steer away from writing business logic or security checks (except basic ones) within the stored procs.
One way I would solve your problem is to write some webservices that check security and does your CRUD (via datasets, etc), but again it depends on the app and environment.
In summary if you have a middle layer or all users have the same access manage the user within the application and use a single user login. Otherwise use a login per user or role.
One option that I have used in the past is to use the ASP.NET Membership Provider. It makes authentication a breeze to use. The only drawback that I saw was that it added a bunch of tables to your database.
The code for using it is very straight-forward.
Here's a blog post about using this in a Windows app. http://msmvps.com/blogs/theproblemsolver/archive/2006/01/12/80905.aspx Here's another article with more details. http://www.c-sharpcorner.com/UploadFile/jmcfet/Provider-basedASP.NET10162006104542AM/Provider-basedASP.NET.aspx
Here's another article that talks about using it with Windows applications: http://www.theproblemsolver.nl/usingthemembershipproviderinwinforms.htm
Google for "ASP.NET 2.0 Membership Provider", and you will get plenty of hits.
What about having SQL accounts based on the level of permissions needed for the task. For example you could have a read only account just used for reporting if your system has a lot of reporting. You would also need an account what has write access for people to change their passwords and other user admin tasks.
If you have situations where certain users are only going to have access to certain data I would have separate accounts for that data. The problem with using 1 account is you are saying that there is no SQL injection anywhere in your application. That is something everyone would strive for but sometimes perfect security is not possible, hence the multi-pronged approach.