Stored Procedures access when no access in a table - sql-server

All,
In SQL Server, can a stored procedure (beeing ran from a user) write to table where the user doesn't have access to write directly to the table?
Rgds,
MK

The correct answer is NO, a stored procedure does not have access to write into a table. However most users perceive it, incorrectly, as YES because of Ownership Chains:
When multiple database objects access
each other sequentially, the sequence
is known as a chain. Although such
chains do not independently exist,
when SQL Server traverses the links in
a chain, SQL Server evaluates
permissions on the constituent objects
differently than it would if it were
accessing the objects separately.
These differences have important
implications for managing security.
Ownership chaining enables managing
access to multiple objects, such as
multiple tables, by setting
permissions on one object, such as a
view.
So a procedure will be able to write into a table that the user has no permissions to write into if they form an ownership chain. This means that if the owner of the schema that contains the table is the same as the owner of the schema that contains the procedure, an ownership chain is formed and the procedure is allowed to write into the table. Since the vast majority of objects deployed in practice belong to the dbo schema, an ownership chain is almost always formed.
It is important to comprehend these details, so you can troubleshoot problems and understand why is the procedure allowed to write into the table. Erland Sommarskog has an excellent comprehensive write up on this topic: Giving Permissions through Stored Procedures. This article goes into great detail explaining all the options available. Your best option, far better than ownership chaining, is code signing.
Understanding how this works also helps understanding why dynamic SQL seems to 'break': running dynamic SQL is an automatic break in the ownership chain, which causes all 'magic' to disappear. And it also helps understand why this 'magic' appears not to work outside the database: cross db ownership chaining Option default value is 0.

In short, yes.
The main restriction in play in this scenario is whether the user can execute the stored procedure.
When creating the stored procedure, it needs to be done with a login/user that has the necessary write access to the table in question.

Yes, if the user is GRANTed EXEC permissions on the SP, any actions it takes (within that database) are allowed.
Going over to another database will require permissions on the underlying user to be examined.
Also, dynamic SQL built within the SP will require the underlying user to have permissions.

Related

server principal not able to access database on second call

I am using SQL Server 2017. I am in the role of sa for the server in question. I have two databases that are used in an ETL process. The ETL is coded in one database, and the raw imported tables are located in the staging database. All ETL is handled in SQL stored procedures that follow a pattern. The first step in each ETL SP is a call to a diagnostics table in the staging database.
My current ETL job is a wrapper around two of these ETL sps; the wrapper itself contains only code that accesses the main db.
The first SP can be called and successfully selects the data from the staging db, however, the second SP that has identical code up to the point of failure with the first, fails on accessing the diagnostics table and tells me
The server principal "sa" is not able to access the database "staging" under the current security context.
The problem stays if I comment out the first SP call, so something must be different in the definition of the two SPs, but I cannot spot it.
There are plenty of SPs that use the diagnostics staging table, so it is not a general problem (as stated in answers to similar questions that suggest changing security options in the staging database), but must be related to the new SP somehow.
Any suggestions?
There are three things to check/do.
First of all, the login associated with the user in database DB1 must also be associated with a user in DB2. This provides the login with a security context in database DB2. The sa login will map to dbo in both databases, so this should already be fine.
Second, the security context of the code being executed in DB1 must be "trustworthy". In other words, when the user context goes from DB1 back up to the server level and then down into DB2 via the cross-database call, the new user context has to trust the original login. There are two ways to do this, the quick and dirty and opens-up-possible-security-holes way, and the more complicated but safer way:
Quick and not entirely safe: alter database DB1 set trustworthy on.
Safe: Use signed modules
Third, in the general case you should check that the owner of DB1 and the owner of DB2 are the same (otherwise you can't cross database ownership chain): select owner_sid from sys.databases where name in ('DB1', 'DB2') But as with the first point, as a sysadmin you can take ownership of anything.
As too often happens, I failed to recognize a subtle difference between the two stored procedures: They both call a logging stored procedure, but this logging procedure has two variants, one with prefix sp_, and another one with the prefix usp. (Someone reacted to the Microsoft warning not to use sp_ as prefix.) The old one had an 'execute as owner' inside, which caused the error.
Replacing the function call with the new version fixed the error.
Sometimes the error is on the other side of the screen.

Determine the final Windows user

We have a SQL Server 2008 R2 database whose tables are used by stored procedures themselves called by dedicated application code (VBA).
Until now all the final users were accessing the same data but for regulatory compliance they will be split into 2 legal entities and we'll have to ensure each user only accesses his entity's records.
Implementing this restriction at the application level is quite simple but not safe (AFAIK any XLA is easily broken).
So to be safe we must implement it at the database level.
My first idea was to simply change the stored procedures to join on the current caller's entity to transparently filter the records retrieved by the SQL queries.
Unfortunately the access is made via a generic SQL Server user, and, from what I've seen on SO and elsewhere, although we are on a full Microsoft infrastructure, there is no way to get the Windows user name.
And indeed all the functions I have tested return the SQL Server user name:
SELECT SUSER_NAME();
SELECT ORIGINAL_LOGIN();
EXEC sp_who
EXEC sp_who2
So, unless I've missed something, we'll have to switch the authentification mode to Windows.
Then, either join as described above, or:
create 2 database roles, one per legal entity, and manually assign users to each one,
create views dedicated to each legal entity, and restrict their access with the roles.
Is there any other option?

Are stored procedures more secure than using LINQ against the database?

I am not a security expert and there was a discussion in my project about if we should use Entity Framework. Even though it seems we will use it the project leader is instill insisting that we should still do all our operations (that includes simple CRUDs) with store procedures because of security. He says that if we use stored procedures the users will only need permission for executing a stored procedure instead of needing permissions for create/read/update/delete.
As I said before I am not a security expert, so I was curious to know how true is this.
What this does is give rights and privileges to the individual store procedures, which then have access to the tables, rather than to the tables themselves.
This way you can restrict the users from all the tables, and allow the SPs to allow semantic access based on other logic (both DB permissions at the SP level, as well as code within the SP).
This is gives the overall security framework finer granularity in terms of roles and privileges.
For example, using normal DB permissions, it's easy to limit what tables a user can see, but not what rows they can see within a table.
Two ways to fix that is to limit access to the underlying table, and then create a limited view on that table and grant permission to that, or you can limit access via the SP which has logic capable of restricting what rows a user can see.
Its true.
Stored procedures gives ability to perform better security than standard table permission (for example by giving possibility to update only few columns of table)
But..
For developers its a nightmare. Even simplest query needs to be implemented as stored proc or view.
So its not agile, rapid or sexy :)

Role for read-only access to execute SP/get result set, without indirectly modifying db?

For example
if a SQL Server user account is given
only the DataReader role and ability to execute one stored
procedure that modifies data in some
way, should the execution of that
stored procedure by that user cause
the modification to occur?
Overall, I want to give one user only read ability to the entire database including use of SQL syntax, Views and to execute any store procedures that return result sets. But I don't want any side effects to cause changes in the database. Therefore in the aforementioned stored procedure example, the attempt would ideally error out to satisfy my requirement, and all similar scenarios where a side-effect might cause a change. I want to ensure my database is protected against those.
Is this doable simply at the role level?
Product: SQL Server 2005 and up
Sure you can do this. Simply create a database role at the database level, and grant that role read on the tables and execute on only the stored procedures you want (i.e. the ones that read). Then, add the desired user(s) to your database role.
However, all things considering, if you are using stored procedures to read data, do so completely and do not grant read on tables for users of any level. Drive all data access through stored procedures (and views).
EDIT: Just noticed you said SQL 2005 "and up." If you are using SQL Server 2008, look at application roles instead of the traditional database roles.

Why is there no built-in "stored procedure executor" database role?

I've always wondered why the list of database roles (db_datareader, db_datawriter, db_ddladmin, etc) never included a db_storedprocedureexecutor. The others make sense, but it seems like being able to grant the ability to execute all stored procs to a particular user (without granting them db_owner, which is the only other way to accomplish the same thing) would be a handy thing.
For example, say I want to give all of my developers the rights to run stored procedures, while not let them execute any DDL - without explicitly granting EXECUTE on every stored procedure (and then remembering to add the new ones when additional SPs are deployed), there's not way to do this (I know that SPs can contain DDL, so they may still be indirectly allowed access to DDL this way).
If I have an application service account and a number of stored procedures that go along with my application, I have to grant rights explicitly to every SP (since I don't want to grant my application service account DBO), whereas I can use a role to allow them to update/delete anything they want.
While it initially seemed obvious, I'm now not sure why this role is missing from the database server - can anybody offer an explanation of why this is a terrible idea (as I assume it is, or it would already exist)?
EDIT:
Seems I'm not the only one with this expectation - and it's worked around with a handful of T-SQL (it seems you can grant a blanket EXECUTE right, which I wasn't aware you could do), which just leaves me wondering why it's not standard!
If you use schemas, then you only have to GRANT EXECUTE ON SCHEMA::storedprocschema
eg CREATE PROC storedprocschema.DoStuff ...
As to why, no idea...
Because if you can execute all stored procedures, you can execute sp_addrolemember, and you can do everything that a database_owner can.

Resources