jonwagner / Insight.Database

Fast, lightweight .NET micro-ORM
Other
861 stars 145 forks source link

SQL Server role, db_denydatareader prevents stored procedure execution #470

Closed JoeyCranberry closed 2 years ago

JoeyCranberry commented 2 years ago

Description

Executing a test store procedure that does not access any function, tables, or other stored procedures with Insight.Database results in the error:

The SELECT permission was denied on the object 'schemas', database 'mssqlsystemresource', schema 'sys'.

The login used to create the connection has both roles, db_denydatareader, and db_denydatawriter - but db_denydatareader seems to be causing the issue.

The user is given permissions, Execute and View definition on the stored procedure.

When not using Insight.Database Methods - like a normal SqlCommand does not encounter any errors when executing on the same stored procedure.

I would like to not allow the user to view all definitions, and would also like to keep db_denydatareader and db_denydatawriter roles.

Is there any way to ensure security and use the Insight.Database solution?

Enviroment

jonwagner commented 2 years ago

The ORM has to do some inspection of the schema in order to properly do the mapping. I can think of a few places where restricting metadata access could cause issues. I think we can get there but we'll need more information.

The best way to track this down:

  1. Post a stack trace where the exception is thrown so we can see what part(s) of metadata inspection are failing.
  2. Post a SQL Profiler trace so we see what SQL is being executed and denied.

With that information, either we can adjust the library or give you better guidance on the right security permissions.

JoeyCranberry commented 2 years ago

Hey Jon, Here is the stack trace: https://pastebin.com/JdwURne9 And here is the Profiler trace: Stack Trace.csv )

This is Insight executing on a stored procedure called, sp_COD_Estimate_Email, this is the interesting part from the profiler trace:

exec sp_executesql N'SELECT ParameterName = p.name, SchemaName = s.name, TypeName = t.name FROM sys.parameters p
                                        LEFT JOIN sys.types t ON (p.user_type_id = t.user_type_id)
                                        LEFT JOIN sys.schemas s ON (t.schema_id = s.schema_id)
                                        WHERE p.object_id = OBJECT_ID(@Name)',N'@Name nvarchar(max) ',@Name=N'sp_COD_Estimate_Email'

I'm trying to limit this login to minimal permissions, and I wouldn't want to give it permissions to view definitions of/select from the entire schema. Thanks for any help you can provide!

jonwagner commented 2 years ago

The stack trace doesn't show where in the Insight library the exception is thrown. That would be helpful to see.

However, my guess is that you're using Insight to call a stored procedure by name. To do that, it needs to query the parameters and their types. I can't remember why it needs the SchemaName but we can look that up if we get to that part.

If you're asking Insight to call a stored procedure, but deny it the ability to view the definitions, it wouldn't be able to do a lot of the automatic conversions that it takes care of for you. It uses that query you posted to figure out conversions like string->guid, table value parameters, etc.

Back to your goal. You want to provide minimum permissions to the login. I presume you want to use deny read/write to force everything through stored procedures.

I read a little about the roles:

https://www.mssqltips.com/sqlservertip/1900/understanding-sql-server-fixed-database-roles/#:~:text=The%20db_datareader%20role%20gives%20implicit%20access%20to%20SELECT,this%20role%20used%20in%20production%20for%20normal%20users.

"Creating a user-defined database role and explicitly defining permissions is still preferred over the use of this role."

I agree with this statement. My recommendation is to create a custom role and add only the permissions you want to grant.

  1. Custom role
  2. Add EXEC to the stored procedures you want to execute.
  3. Add SELECT to parameters/types/schemas for this role. There shouldn't be anything sensitive in those tables. If you want to be strict, I think you could limit it specifically to those columns.

Let me know how this works. It would make a good wiki page - "Minimum permissions for using Insight.Database"

JoeyCranberry commented 2 years ago

Hey Jon, It looks like creating a role is the best option for this with Select permissions for sys.parameters, sys.schemas, and sys.types. And EXEC perms for the SPs. Unfortunately, even with restricting the select to only certain columns, my co-workers see this as too much access. I really appreciate your help with this!