SQL Public role audit findings - sql-server

Our SQL auditors have issues with the Public role being able to query master.sys.syslogins, master.sys.databases, master.sys.configurations from a specific database. Has anyone had to remove these rights to the Public role and does this cause any issues? Thanks all.

This is unfortunately a common false positive when using DB vulnerability scanning tools, and unfortunately there are no absolute answers. It will depend on your particular scenario & auditors to determine if such findings are indeed something you need to change, or accept it as operational risks.
For the most part, I have been able to argue that these permissions are acceptable, especially since the typical best-practice recommendation is to not modify the default permissions granted to public role.
The default permissions granted to public on SQL Server are intended to make tools & some features in SQL Server work, and typically there will be mitigating factors around these permissions.
In the particular case of catalog view access, it is not only governed by having select permission to the catalog view itself, but also by metadata visibility rules. For details Please visit Metadata Visibility Configuration (https://msdn.microsoft.com/en-us/library/ms187113.aspx) on BOL; I especially recommend reading the "Benefits and Limits of Metadata Visibility Configuration" section.
For example, a low-privileged user in the system will have different visibility on sys.server_principals (master.sys.syslogins is deprecated) that a user with sysadmin access:
CREATE LOGIN [test00] WITH PASSWORD = '<s3cr3t P#zzw0Rd>';
ALTER LOGIN [test00] DISABLE;
CREATE LOGIN [test01] WITH PASSWORD = '<s3cr3t P#zzw0Rd>';
ALTER LOGIN [test01] DISABLE;
CREATE SERVER ROLE [srvrole00];
go
ALTER SERVER ROLE [srvrole00] ADD MEMBER [test00]
go
SELECT * FROM sys.server_principals -- Can see all server principals
EXECUTE ('SELECT * FROM sys.server_principals') AS LOGIN = 'test00' -- besides the system principals, can see only himself & the server role he is a member of
EXECUTE ('SELECT * FROM sys.server_principals') AS LOGIN = 'test01' -- besides the system principals, can see only himself
go
You will notice on the results that the 3 principals have a different view of the metadata.
If your SQL auditors think any of these permissions is not acceptable for any reason, you may revoke the permission as they deems as necessary, but the cave-at is that such actions are likely to limit (or in some cases completely break) functionality of SQL server and/or tools. I would strongly recommend looking at what operations they are trying to block/prevent, and act accordingly.
For example. For access to DB metadata, there is one special permission granted by default to public: VIEW ANY DATABASE. This permission was introduced to allow users using SSMS & similar tools to navigate to different databases.
Revoking this permission will affect how some tools work in order to allow you to switch between databases, but it doesn't change the access to the DB; therefore it may be an acceptable trade-off if your users do not need such functionality and you want to prevent users from looking at all the DB metadata.
I hope this information helps. Please feel free to follow up with any question. I will be glad to help.
-Raul

None of our general users even have public access to the Master database, and likely shouldn't in most environments. Only DBAs really need access to the Master database generally. As long as you only grant the public role on the Master database to logins that have any business being in it... then it's really not necessary to remove the public role from any objects in there. If you remove the public role access to those objects, then only system administrators will be able to query them.

Related

SQL Server Management Studio server roles

I dont know if im doing something completely wrong or im just missing the point of SQL Server security.
Here's what I'm trying to do using SSMS, a simple two-level access (network\DomainUsers, network\SQLAdmins).
Domain users would not be unable to view any tables within SSMS but can access data via applications.
SQLAdmins see all
To start with I thought I had it cracked by setting up a new server role for domain users and assigning view and database/definition permisions then removing these from the public role - no joy!
Staying with the same settings I then branches down to the table to grant permissions but again no joy.
I've setup several roles / users and applied all forms of permissions but as soon as database/definition is altered in public it overrides everything. I thought public was a default setting which then became redundant when other roles became active?
Can someone please point me in the correct direction before either my head pops or the machine learns to fly :-)
SSMS: v17.8.1
SQL Server: 2012
Depending on how you actually defined your roles (which isn't clear from your question) it can simply be that you DENY view any database on the public role. This will in turn make it so everyone is denied. Because everyone is always a part of the public role. (This is why messing with the public role is a bad idea).
Deny's trump Grants. So no matter what you grant them later on, the deny overrides it. So if you denied it at the top level, it will stay like that no matter what you specify later on.
The exception to this is, that you can always see the objects that you own. And members of the sysadmin server role can't be denied since they always jump in as the owner. So you can technically hide all databases by revoking view permissions on the public database. But then you need to make a shared login and assign ownership to the databases that you want to be viewable.
Of note is that in this case, it means they can do whatever they want in said databases. Since you can't 'deny' them rights in something they own (which is why they can view it in the first place).
In overall, you're better off finetuning roles on the DB level, or making some custom server roles depending on what you want to accomplish.
Note, unless you messed with the public role. Logins with no user mapping in a database can't see the tables within a database, they can only see the existance of the database itself.

What are good practices for granting database permissions to a web service connection?

I have been searching for articles and SQL script examples that would demonstrate how to securely and conveniently solve one of the most common scenarios - connecting from a .Net Core Entity Framework based web application to an SQL database.
But somehow I could not find any coherent step-by-step guide from a reputable source.
Let's assume the following:
I cannot use integrated Windows auth in the connection string and must use username and password based auth (because hosting on a Linux server and the DB is on a different Windows server)
the web service will need your usual minimum set of permissions - connect to the database, read data, write data, delete data, execute stored procedures
While reading many tutorials, I find there are multiple ways to manage the connection permissions. To avoid this question being too broad, I'll list my current choices as I understand them (please correct me if I'm missing something).
Users and logins:
create a login and a user for the database
create a database-only user without a login (not sure if this is applicable to a web app and connection string, but still it's a feature that I've seen being used)
Assigning permissions:
assign the user to some fixed SQL role (db_datareader, db_datawriter AND also will have to grant EXECUTE permission)
grant all fixed permissions
create a custom role (let's say, db_web_apps) with required permissions
Which choices are better (more secure and easier to manage in general) and recommended by SQL DBAs?
I think every database administrator should have a template script handy for quickly adding a new user with minimum required permissions every time when developers ask for a new connection for their shiny new web app.
If you know a good, reliable tutorial or GitHub / Gist example that explains what and why is being done that way or a script that you yourself have used for years without any issues in production environments, I'll really appreciate if you could share it.
Create a role in the database and assign the required privileges to the role. Don't use the fixed database roles. Instead grant permissions directly to objects, schemas, or the entire database if necessary. Like this:
create role trusted_app_role
grant select, insert, update, delete, execute
on schema::dbo to trusted_app_role
That will grant the role full DML permissions on all the objects in the default dbo schema. So if you have any tables or procedures you don't want the app to have access to, just create them in a different schema, say, admin. This way you never have to fiddle with permissions as you add objects. The fixed database roles predate schema-based permissions, and aren't really needed any more.
For your application's identity, add Active Directory or Azure Active Directory (Azure SQL) identities to this role, or, if you can't, add SQL Users to the role.
If you are on Azure SQL, you should normally use a database user without a login. On SQL Server you can only add "contained database users" if you enable Partial Database Containment. Which you can do, but is incompatible with Change Tracking and Change Data Capture, so it's a tradeoff.
So normally for SQL Server you still create a login and map the user to the login. EG:
create login web_service_user with password = '5X+jeuAB6kmhw85R/AxAg'
create user web_service_user for login web_service_user
And then add that user to your role
alter role trusted_app_role add member web_service_user

SQL Server roles and permissions

I really need some advice about adding roles at the server level and apply some permissions that will be applicable to each database on my server.
Basically I need to two roles read only and read write.
The read will have permissions to select and see any object
The write will have permissions to select/insert/delete and execute any object
I want to create a server role, then a login associated to this role (which can be a AD group) and after that for each database create a user that will inherits all permissions from the server role.
So on each database, I will have each user that belongs to the server role created, the problem is to clearly define the permissions, is not straight forward in my opinion.
What I can see, I cannot assign read or write to a role and then use it on each db, on the contrary on the General tab of the server role I have a bunch of permissions that is not clear which one to use for this purpose.
Maybe I'm doing it wrong but I want to have something at the server level and not define the same role on each db for that purpose. I'm using SQL server 2014.
The short answer is you can't.
Generally, server-level permissions are not propagated down to individual objects within databases. The only exception is a sysadmin role, which I would strongly encourage you not to use for this purpose, as you would essentially give up the control of the entire server instance to every member of it.
As a kind of a shorthand, you can use built-in database roles to save yourself a bit of trouble. For read-only access, a membership in db_datareader role is usually enough, unless you have stored procedures that return datasets which this role is supposed to be able to execute. There is also a similar role for modification, db_datawriter, but it doesn't cover the execute permission. So you will have to create a custom role for that:
create role [DataChanger] authorization [dbo];
go
alter role [db_datareader] add member [DataChanger];
go
alter role [db_datawriter] add member [DataChanger];
go
grant execute to [DataChanger];
go
-- Now you can add your members. Here is a reader
create user [Domain\MyUser1] from login [Domain\MyUser1];
go
alter role [db_datareader] add member [Domain\MyUser1];
go
-- Writer
create user [Domain\MyUser2] from login [Domain\MyUser2];
go
alter role [DataChanger] add member [Domain\MyUser2];
go
These permissions will automatically pick up newly created objects, without you having to explicitly add new permissions after every schema modification.
You will have to do this in the context of every user database that you want to manage in this way. You can probably create a SQL Agent job which will run periodically and introduce these changes in any user databases which don't have them already (for example, if a database has been restored from earlier backup, or brought from another server, or a new one was created). Also, since you can't loop through databases in static code, you will need to wrap it into a dynamic SQL and loop through sys.databases, or maybe via an undocumented sp_MSforeachdb system stored procedure. Oh, and don't forget to remove all these go statements from dynamic code, as they are not part of SQL, and are only recognised by SSMS and sqlcmd.
P.S. All that being said, I hope you are not going to manage any production databases in this manner. I don't even know where to start on how insecure this approach is.

SQL Server 2005 Security

Here is the scenario. I have a SQL Server 2005 production database/server. It currently has developers and supporters who can connect to it. I need to create a security module that gives developers read-only access to all areas of the database. This means that a developer should be able to view all objects as well as scheduled activities/jobs only.
Is it possible to enable security in this way and if so can I be gently guided on how to achieve this. I am learning to be a DBA and creating snapshots of the databases are not an option.
Thank you all in advance.
There is permission to every object.
Create a stored procedure that grant each gruop the exact permission you need on the objects you need to protect.
I'm not quite sure I follow where this "security module" will be in the architecture. Anyhow, here's one possibility that secures it from the database end.
I'm going to assume you already have users created.
Create a new role (yourdb > security > roles > new database role), say "ReadOnlyDevelopers". Make the owner dbo or whatever makes sense. Do not select any schemas to be owned by the role. Populate the "Role Members" with your developers.
Next, open the properties page on your database. Go to the permissions page. Click Add... and add the new role. Under the permissions grid at the bottom, Grant SELECT to the role.
Now assuming your developers already belong to some other role, you'll need to go into the user properties and under Database Role Membership restrict them to just the new role. At this point they should be able to just read
I'm guessing that I'm missing a detail or two (the role may need to be grated a few additional rights to "see" the database, alter passwords, etc.) but I can't get to that level of detail without setting up the entire scenario. Hopefully this pushes you in the right direction.

SQL Server 2005 "public" database role doesn't seem to apply?

I have a SQL Server 2005 database that I'm trying to access as a limited user account, using Windows authentication. I've got BUILTIN\Users added as a database user (before I did so, I couldn't even open the database). I'm working under the assumption that everybody is supposed to have permissions for the "public" role applied to them, so I didn't do anything with role assignment. Under tblFoo, I can use the SSMS Properties dialog (Permissions page) to add "public", then set explicit permissions. Among these is "Grant" for SELECT. But running
SELECT * from tblFoo;
as a limited (BUILTIN\Users) account gives me an error "Select permission denied on object 'tblFoo', database 'bar', schema 'dbo'". In the properties dialog, there's an "Effective Permissions button, but it's greyed out.
Further, I tried creating a non-priv account called "UserTest", adding that at the server level, then mapping it down to the "bar" database. This let me add UserTest to the "Users or Roles" list, which let me run "Effective Permissions" for the account. No permissions are listed at all -- this doesn't seem right. The account must be in public, and public grants (among other things) Select on tblFoo, so why doesn't the UserTest account show an effective permission? I feel like I'm going a bit crazy here.
ASIDE: I am aware that many people don't like using the "public" role to set permissions. This is just my tinkering time; in final design I'm sure we'll have several flexible (custom) database roles. I'm just trying to figure out the behavior I'm seeing, so please no "don't do that!" answers.
UPDATE: Apparently I know just enough SQL Server to be a danger to myself and others. In setting permissions (as I said, "among others"), I had DENY CONTROL. When I set this permission, I think I tried to look up what it did, had a vague idea, and decided on DENY. I cannot currently recall why this seemed the thing to do, but it would appear that that was the reason I was getting permission failures. So I'm updating my question: can anyone explain the "CONTROL" permission, as it pertains to tables?
You only need to have SELECT rights. In raw SQL (see the "script" icon/button in your dialogue box), it's GRANT SELECT ON dbo.tblFoo to public. This is the only permission needed to view the data,
In this case, the error message explicitly mentions "deny". "DENY" is a right in itself, so it mentions it,
If you had no rights, you'd get the message (very approximately) "tblFoo does not exist or you do not have rights"
"DENY CONTROL" is mentioned here. In this case, you denied all rights to the public role.
The grantee effectively has all
defined permissions on the securable
Assuming "UserTest" is a domain user account, connect as a member of the sysadmin role and run
EXEC MASTER.dbo.xp_logininfo 'Domain\UserTest', 'all'
(substituting your domain name for "Domain")
this will display the Windows groups etc. that the account is inheriting security permissions from and the level of access, e.g. you would expect to see something like:
account name type privilege mapped login name permission path
domain\usertest user user domain\usertest BUILTIN\Users
This will help troubleshoot where the account is inheriting permissions from, e.g. which Windows groups it is part of that have permissions to the database. If this all looks OK then I would follow your own advice and not mess with the public role.
Create a database role in your
database
Assign explicit permissions for that
role
Create a server login for your user
account
Open the server login, go to the
User Mapping section, click on the
database and select the database
role you created

Resources