I have a sproc (call it client.UpdateClient) that is executed by a SQL User (call it MyWCFServicesUser.
MyWCFServicesUser has datareader and datawriter permissions on the database. It also has execute permissions on the sproc (but no other permissions).
The sproc will insert a row into client.Client with SET IDENITY_INSERT client.Client ON.
When I run this sproc (from SSMS) with integrated security (I am sa), everything works fine.
When I run it as MyWCFServicesUser (from SSMS) it fails with this error:
Msg 1088, Level 16, State 11, Procedure UpdateClient, Line 33
Cannot find the object "client.Client" because it does not exist or you do not have permissions.
I usually have all my sprocs and tables in the default (dbo) schema, but this time I am trying to not use dbo.
Is that why I don't have permissions? Do I need to elevate the sproc somehow? Or the user? Or somehow change the schema?
I am stumped...
Turns out that SET IDENTITY_INSERT requires alter permissions by the user.
The proper way to resolve privilege requirements in store procs is to use code signing. This way you grant the required privilege (ie. ALTER TABLE) to the procedure, not to the user, and you need only grant EXECUTE on the procedure (or schema) to the user. The advantage is that your low privilege user can only invoke the procedure and do whatever action requires the elevated privilege (ie. setting identity_insert on) as controlled by the procedure. Had you been grant the required privilege directly to the user he/she could use it for any operation permitted by said privilege (eg. add columns, drop constraints etc etc). The link has several examples.
That being said, I must call out that your question is about SET IDENTITY_INSERT, which is a special setting normally used for one-time data load. The fact that you are setting this from what seems like a routine CRUD UpdateClient procedure is a bit of a code smell.
what will matter is who is the owner of the objects you mentioned.
Any chance they were created by different users? Maybe sa is the owner of the table and MyWCFServicesUser owns the proc?
See this link about Ownership Chains http://msdn.microsoft.com/en-us/library/ms188676.aspx it may help you on your investigation
Related
I have a SQL Server database (let's call it DB1) with a few stored procedures, and these stored procedures are executed by my Web API (that will be consumed by my mobile app later).
These stored procedures get data from DB1 and from another database (let's call it DB2).
I created a SQL Server login to be used by the Web API with public and dbcreator server roles and only public database role in both DB1 and DB2.
Then I followed this guide and granted Execute permission on the stored procedures for the login.
But when I try to execute my Web API method that uses one of the procedures, I get an exception:
The SELECT permission was denied on the object 'APP_USERS', database 'DB2', schema 'dbo'.
So, do I have to grant the permissions on DB1 and DB2 for this to work, even if I already granted it on the stored procedure? Or am I just granting the wrong permission to the stored procedure?
Note: I used to grant permissions directly on the database for each login, because all applications consulting the database were internal of our enterprise (until now). But this mobile app will be public. I talked to a security expert who told me that this practice is insecure, and advised me to grant the permissions only on the stored procedures.
It looks like you've been introduced (whether you wanted to be or not!) to something called database permissions chaining. At a high level, you're allowed to have objects in your own database reference other objects and only have to grant permissions on the referencing object so long as both the referenced and referencing object are owned by the same database principal (i.e. user). For example, if I have a table that I own, I can write a stored proc doing whatever (say a SELECT) against the table and then grant execute on the proc to another user. When the other user goes to execute the proc, permission chaining kicks in and says "the proc and the table are owned by the same user - the execute permission is sufficient"
But! By default, the permissions chain is broken when the referenced object is in another database. Why? I can only speculate as to creators' intent, but imagine a multi-hosted database server and I'm an malicious actor. If I have my own database, I could write a proc that says select * from OtherDb.dbo.Users;, grant permissions on that proc and exfiltrate data from other users' databases.
There are a couple of ways around this:
You can enable cross db ownership chaining at the server level. I don't recommend this, but it is an easy button out of the problem you have.
You can grant permissions on the objects referenced in the procedure. This may be okay, depending on why you're gating data access through stored procedures (which, full disclosure, I like to do in general). This would be a simple grant select on dbo.APP_USERS to «some DB2 principal - a user or group»;. The downside here is that the principal to whom the permissions are granted can do any select on the table now, thereby bypassing the proc.
You can sign your stored procedures. This is a little more involved, but is the more secure option. It involves creating a certificate or asymmetric key in both databases, creating a user based on the same, granting permissions to that user, and finally calling add signature on the related procs. You'd think you're done, but you'll need to re-apply that signature any time someone changes the procedure definition. Why? Let's say that you sign the proc today but then I change it to do something unintended (either innocently or maliciously). If the signature persisted through an alter procedure, the original proc could be a Trojan horse.
Here is a rough sketch of the module signing dance.
use Db1;
create certificate ModuleSigningCert ...;
add signature to dbo.YourProc by certificate ModuleSigningCert;
use Db2;
-- import ModuleSigningCert - either by backup certificate/create certificate
-- you technically only need the public key portion
create user SigningUser from certificate ModuleSigningCert;
grant select on dbo.YourTable to SigningUser;
For what it's worth, I don't know that "database will be accessed by a public app" necessarily means "and now we need to do cross-database stuff". It may, but it may not. For instance, if the public app still accesses the database through an internal application server, you're not getting much security-wise with the multi-database setup.
What is the best way to prevent changes to a database or verify the integrity of this, so that it can not be altered from an application created for this database.
assuming you have a username and password to access the database permits reading - writing.
requirements:
The user has write permissions
Do not depend on a particular system like (MySQL, Oracle, SQL Server)
solution I'm looking for is not based on the user's permissions on the database
Most modern databases allow you to grant reading and writing permissions but while disallowing DDL commands like ALTER TABLE.
Do not give users that should not alter the DB structure permission to execute DDL.
If by "Alter" you mean change any data rows, rather than the database structure, you can grant the user only SELECT rights.
The user or account that your application uses must be granted permissions from the database server. Typically permissions include things like:
Select
Insert
Update
Delete
Alter
Drop
Only give the user account the permissions needed; in other words, don't grant Alter permission, and the application (or anyone using the same login) won't be able to alter tables.
Two strategies: 1) if you are running SQL Server, Oracle, DB2, etc, you can configure permissions so users are reader/writer by default (which means no alter permissions). 2) you can periodically check to see if someone has changed the data structure or even set up a DB trigger to detect changes and record who/when, etc (depends on your DB platform)
I have a SQL user that I gave explicit Execute permission for a specific stored procedure. This stored procedure contains a truncate statement. The user is unable to execute that procedure and receives the error:
Cannot find the object TableName because it does not exist or you do not have permissions.
If I alter the stored procedure to use Delete instead of truncate the user can execute the procedure.
What do I need to do to allow the user to execute this stored procedure, without giving the user more access than necessary?
From MSDN:
http://msdn.microsoft.com/en-us/library/ms177570.aspx
"The minimum permission required is ALTER on table_name. TRUNCATE TABLE permissions default to the table owner, members of the sysadmin fixed server role, and the db_owner and db_ddladmin fixed database roles, and are not transferable. However, you can incorporate the TRUNCATE TABLE statement within a module, such as a stored procedure, and grant appropriate permissions to the module using the EXECUTE AS clause. For more information, see Using EXECUTE AS to Create Custom Permission Sets."
You can try this:
create procedure SpName
with execute as owner
as
truncate table TableName
go
Then assign permission to user
grant execute on TruncTable to User
truncate table Setting permission on objects like stored procedures can be accomplished with:
GRANT EXECUTE ON <schema>.<object> to <user>;
However, you may also want to grant security rights at both the login and user level. You will want to determine and grant ONLY the necessary rights for the objects that require access (such as execution). Consider use of the EXECUTE AS capability which enables impersonation of another user to validate permissions that are required to execute the code WITHOUT having to grant all of the necessary rights to all of the underlying objects (e.g. tables). EXECUTE AS can be added to stored procedures, functions, triggers, etc.
Add to the code as follows right within the Stored Procedure:
CREATE PROCEDURE dbo.MyProcedure WITH EXECUTE AS OWNER
In this case you are impersonating the owner of the module being called. You can also impersonate SELF, OR the user creating or altering the module OR... imperonate CALLER , which will enable to module to take on the permissionsof the current user, OR... impersonate OWNER, which will take on the permission of the owner of the procedure being called OR... impersonate 'user_name', which will impersonate a specific user OR... impersonate 'login_name' with will impersonate a specific login.
MOST of the time, you will only need to grant EXECUTE rights to stored procs and then rights are granted to all objects referenced within the stored proc.
In this way, you DO NO need to give implicit rights (example: to update data or call additional procs). Ownership chaining handles this for you. This is especially helpful for dynamic sql or if you need to create elevated security tasks such as CREATE TABLE. EXECUTE AS is a handy tool to consider for these.
This example may help clarify all of this:
Create a user called NoPrivUser with public access to a database (e.g. dbadb):
USE [master];
GO
CREATE LOGIN [NoPrivUser] WITH PASSWORD=N'ABC5%', DEFAULT_DATABASE=[dbadb],
CHECK_EXPIRATION=ON, CHECK_POLICY=ON;
GO
USE [DBAdb];
GO
CREATE USER [NoPrivUser] FOR LOGIN [NoPrivUser];
GO
NOTE: CREATOR OR OWNER OF THIS PROCEDURE WILL REQUIRE CREATE TABLE RIGHTS within the target database.
use DBAdb
go
CREATE PROCEDURE dbo.MyProcedure
WITH EXECUTE AS OWNER
truncate table MyTable
GO
GRANT EXEC ON dbo.MyProcedure TO NoPrivUser;
GO
-- Now log into your database server as NoPrivUser and run the following.
With the EXECUTE AS clause the stored procedure is run under the context of the object owner. This code successfully creates dbo.MyTable and rows are inserted successfully. In this example, the user NoPrivUser has absolutey no granted rights to modify the table, or read or modify any of the data in this table.
It only takes on the rights needed to complete this specific task coded WITHIN the context of this procedure.
This method of creating stored procedures that can perform tasks that require elevated security rights without permanently assigning those rights come be very useful.
FYI: SQL Server 2005
I have a database user account (user_web) that has the ability to connect to and run queries and stored procedures in my database. Specifically, I have given the user the db_datareader and db_datawriter roles as well as granted them execute permission on the specific stored procedures it needs to be able to run.
In one of the stored procedures, I need to disable a trigger then re-enable it after some specific edits are done. When I attempt to run that stored procedure with the user I get the following error:
Cannot find the object "TableName" because it does not exist or you do not have permissions.
TableName is the table where I am attempting to disable and enable the trigger. My question is what is the least amount of permissions I can give to my user account that will allow it to successfully run the stored procedure.
The user will "at a minimum" require ALTER permissions on the table in question. See: http://technet.microsoft.com/en-us/library/ms182706.aspx
Rather than grant the user ALTER permissions on the table, which could be a security issue, I'd have that particular stored procedure run as a different user that does have those permissions. Use the EXECUTE AS syntax to accomplish this.
http://msdn.microsoft.com/en-us/library/ms188354.aspx
Is there a way I can give developers permission to grant a user permissions over objects without giving them the option to create users or functions?
I'm trying to limit developers permissions, I recently found out that developers had db_owner permissions in dev and prod environments! So I'm doing my best to stop this madness.
Any good article about this matter?
You can make them members of the "db_securityadmin" database role
As said, if someone could hand out permissions, they could hand out permissions to themselves (or a dummy account). I'm not sure if there is a trick in SQL Server to provide "give user permissions less then me".
The way I would do it is with stored procedures.
Create a stored procedure that gives a specified user a specific right or set of rights (those rights are the ones that regular users are allowed to have). Then give the developers execute access to this stored procedure. In effect you use stored procedures to create a limited version of GRANT, while keeping the full GRANT command to yourself.
If someone can give someone else permissions, he can also give himself the permission to do what he wants. So what is this good for? Probably I don't understand your situation.
Owners of objects can grant permissions on those objects. Provided your developers don't need to grant things like CREATE TABLE rights, you might be able to give them ownership of the objects that you want them to grant permission on.
As Stefan said, giving them grant permissions would effectively give them all permissions, since if they want to do something all they have to do is grant themselves the permissions to do it.
Rather than considering the developers the enemy, though, you may want to consider giving the developers a second user account that's used to administer the database. It's pretty common not to give developers ANY permissions to production, at least on their development account.
Setting permission on objects like stored procedures can be accomplished with "GRANT EXECUTE ON . to ;
However, you may also want to grant security rights at both the login and user level. You will want to determine and grant ONLY the necessary rights for the objects that require access (such as execution). Consider use of the "EXECUTE AS" capability which enables impersonation of another user to validate permissions that are required to execute the code WITHOUT having to grant all of the necessary rights to all of the underlying objects (e.g. tables). The EXECUTE AS can be added to stored procs, functions, triggers, etc.
Add to the code as follows right within the Stored Procedure: CREATE PROCEDURE dbo.MyProcedure WITH EXECUTE AS OWNER
In this case you are impersonating the owner of the module being called. You can also impersonate SELF, OR the user creating or altering the module OR... imperonate CALLER , which will enable to module to take on the permissionsof the current user, OR... impersonate OWNER, which will take on the permission of the owner of the procedure being called OR... impersonate 'user_name', which will impersonate a specific user OR... impersonate 'login_name' with will impersonate a specific login.
MOST of the time, you will only need to grant EXECUTE rights to stored procs and then rights are granted to all objects referenced within the stored proc.
In this way, you DO NO need to give implicit rights (example: to update data or call additional procs). Ownership chaining handles this for you. This is especially helpful for dynamic sql or if you need to create elevated security tasks such as CREATE TABLE. EXECUTE AS is a handy tool to consider for these.
This example may help clarify all of this:
Create a user called NoPrivUser with public access to a database (e.g. dbadb)
USE [master] GO CREATE LOGIN [NoPrivUser] WITH PASSWORD=N'ABC5%', DEFAULT_DATABASE=[dbadb], CHECK_EXPIRATION=ON, CHECK_POLICY=ON GO USE [DBAdb] GO CREATE USER [NoPrivUser] FOR LOGIN [NoPrivUser] GO
NOTE: CREATOR OR OWNER OF THIS PROCEDURE WILL REQUIRE CREATE TABLE RIGHTS within the target database.
use DBAdb go CREATE PROCEDURE dbo.MyProcedure WITH EXECUTE AS OWNER AS IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].MyTable') AND type in (N'U')) CREATE TABLE MyTable (PKid int, column1 char(10)) INSERT INTO MyTable VALUES (1,'ABCDEF')
GO
GRANT EXEC ON dbo.MyProcedure TO NoPrivUser; GO
-- Now log into your database server as NoPrivUser and run the following.
use dbadb go
EXEC dbo.MyProcedure
(1 row(s) affected)
Now try to select from the new table while logged on as NoPrivuser.
You will get the following:
select * from MyTable go
Msg 229, Level 14, State 5, Line 1 The SELECT permission was denied on the object 'MyTable', database 'DBAdb', schema 'dbo'.
That is expected since you only ran the procedure under the security context of Owner while logged on as NoPrivUser.
NoPrivUser as no rights to actually read the table. Just to execute the procedure which creates and inserts the rows.
With the EXECUTE AS clause the stored procedure is run under the context of the object owner. This code successfully creates dbo.MyTable and rows are inserted successfully. In this example, the user "NoPrivUser" has absolutey no granted rights to modify the table, or read or modify any of the data in this table.
It only takes on the rights needed to complete this specific task coded WITHIN the context of this procedure.
This method of creating stored procedures that can perform tasks that require elevated security rights without permanently assigning those rights come be very useful.
I've found that the most dangerous aspect of the db_owner role is that if you issue a deny on a permissions, then the members of the role can grant it back to themselves. I've just started reading about this and I'm testing this
Create role db_ControlDatabase
grant control to db_ControlDatabase
deny backup database to db_ControleDatabase
alter role db_ControlDatabase add member TestUser
So far, I've found that the subject TestUser has permissions without being able to add or remove members of the fixed database roles. You should be able to deny whatever you need at this point like backup certificate, backup master key, etc.
Here is a list of permissions that can be denied or granted: