Can DCL commands (e.g. GRANT/REVOKE) be committed/rolled back as transactions in snowflake? I can't find any mention of how DCL is handled in the snowflake transaction documentation.
Explicit transaction:
Explicit transactions should contain only DML statements and query statements. DDL statements implicitly commit active transactions (for details, see the DDL section).
GRANT and REVOKE are also considered
User & Security DDL:
Access Control Management
Use the following commands to manage access control for objects by granting (and revoking) object privileges to roles and granting roles to users and other roles:
GRANT … TO ROLE
REVOKE … FROM ROLE
DCL commands always force a commit(implicit autocommit if they are successfully executed without errors) and will in turn commit all statements before them.
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.
I have to implement a financial application. One of the acceptance criteria is:
"The data may never change."
Therefore I need to prevent update and delete operations on the database, because it will be deployed on machines owned and administrated by the customer.
Is this even possible? Maybe with triggers? If not, are there any other databases that can prevent update and delete?
The easiest way is via roles, such as a query role. Grant select on the list of tables to that role, and grant that role to the user of your application. You can of course create others such as an admin role with update and delete privileges, to be granted later on when needed.
Example:
CREATE ROLE FIN_APP_INS_SEL_ROLE;
GRANT INSERT, SELECT on <table1> to FIN_APP_INS_SEL_ROLE;
GRANT INSERT, SELECT on <table2> to FIN_APP_INS_SEL_ROLE;
GRANT CONNECT, FIN_APP_INS_SEL_ROLE to <app_user>;
You can also make tablespaces read only,
ALTER TABLESPACE <name> READ ONLY;
or the entire database read only.
ALTER DATABASE OPEN READ ONLY;
It turns out to be impossible.
There is no way to grant an INSERT privilege without allowing to UPDATE. As I understand it, the INSERT privilege is interpreted as may alter data of that table.
I have 2 schemas on my database, an admin (which contains all the tables) and a second schema which has grants to select, update, delete from synonym tables from admin. (I am using 11G)
I am working just with the admin schema.
What i am trying to do is, get the scn before an operation is done:
SELECT current_scn FROM V$DATABASE;
then some oeprations are done, and after that I am trying to make a select with the scn that i stored it before operations:
SELECT * FROM myTable AS OF SCN 2312312;
and then
ORA-01031: insufficient privileges
01031. 00000 - "insufficient privileges"
*Cause: An attempt was made to perform a database operation without
the necessary privileges.
*Action: Ask your database administrator or designated security
administrator to grant you the necessary privileges
this error is coming.
You need to grant the user privileges to run a flashback query against the table.
grant flashback
on myTable
to someUser;
Or you can give the user privileges to run flashback queries against any table
grant flashback any table
to someUser
Generally, auditors get rather nervous when they see the various "any" privileges but this one is reasonably safe. You may also want to grant privileges on the dbms_flashback package as well.
The documentation has a good overview of the administrative tasks to enable flashback features.
I have a series of stored procedures that select data from a db. I have a role (cctc_reader) that has execute permissions granted on the procedures. One of the procedure calls another stored procedure called recControl_system_option which in turn queries Information_schema.columns.
The problem is that in this proc the query
select column_name from information_schema.columns where table_name = 'recControl_manager'
does not return any records. cctc_reader has grant permissions on:
each select proc
recControl_system_option
so in theory this should work. I have no problems when run under dbo.
If I grant db_datareader to cctc_reader the query is fine, but I don't want to grant reader permissions to all tables (hence why I used stored procs). I've tried granting Select permissions on Information_schema in the Master db as suggested in some articles, but still can't get this to work.
Any suggestions?
Objects metadata visibility is subject to the VIEW DEFINITION permission:
GRANT VIEW DEFINITION ON ... TO cctc_reader;
The VIEW DEFINITION permission lets a
user see the metadata of the securable
on which the permission is granted.
However, VIEW DEFINITION permission
does not confer access to the
securable itself. For example, a user
that is granted only VIEW DEFINITION
permission on a table can see metadata
related to the table in the
sys.objects catalog view. However,
without additional permissions such as
SELECT or CONTROL, the user cannot
read data from the table.
The right securable to grant permission to depends on your scenario. It could be the dbo or some other schema, it could be the database itself, it could be individual tables. If I was in your place, I'd code sign the recControl_system_option procedure and I'd grant VIEW ANY DEFINITION on the signature at server level, a much better and secure way that using roles and granting permission on roles. See Signing an activated procedure for an example of how to sign a procedure and grant a server level permission on the signature.
As Remus mentioned, metadata visbility affects data returned when querying system tables and views. If you have no rights on a securable (object, login, whatever) it won't be visible.
Depending on your situation, you would allow the internal call to have EXECUTE AS OWNER, or wrap Information_schema.columns in a udf that as EXECUTE AS OWNER
We use this technique where we query metadata.
Found this elsewhere, make a sproc that calls System sproc sp_columns in your database. Your sproc can execute with the same permissions as your other sprocs. Downside is that the returned set has many columns that you probably are not interested in. I daresay you could refine the sproc. I chose to do the field choice in code.
CREATE PROCEDURE [dbo].[proc_tblMyTableSchemaGet]
AS
BEGIN
SET NOCOUNT ON;
exec sp_columns #table_name = 'myTable', #table_owner = 'dbo';
END
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: