Prevent database access outside the application - sql-server

We have a MVC application running with SQL Server database.
We are using windows authentication, and when we want to give user access to our site we add them in the active directory group SEUser.
We have given login as well as access permission to SEUser group to our database as well.
But the problem is since the AD group has permission to database so the user belonging to that group not only can access website but can also connect to the database from outside the application and can make changes to it as well.
So I am searching a lot to find any way where I can restrict user group to access database only when the request comes through our application and not from outside.
For that the first approach I thought of is to use impersonation/connect as approach, and allow only worker process account to connect to the database,
But the problem is we are accessing current logged in user information within stored procedures also by using methods like SYSTEM_USER and IS_MEMBER which considers current logged in user only and so we cannot use worker process approach.
Is there any way I can achieve this for my particular scenario? Please help

The short answer is there is no capability that would allow an authorized user to connect from one program (i.e. your middle tier), but not another (i.e. an interactive query program such as SSMS).
The best advice I can give you is to design your system under the assumption that the users will find a way to connect directly to the database, and therefore restrict their permissions as much as possible to avoid any problem when they decide to do so.
One strategy to limit what users can do on the system when connecting to the DB directly is to use stored procedures to limit what they should be able to do on the DB (i.e. they have access to run the SPs, and nothing else), granting permissions only through the SP execution via signatures.
I also strongly recommend using auditing to detect any abuse of the users’ privileges. Given that you expect all users to connect via your middle-tier application, it should be relatively easy to detect unusual activity.
One trick you may find interesting as a workaround is to use logon triggers to try to avoid accidental access through non-authorized programs (AKA. avoid the “I didn’t know” excuse). But be warned: This is not a security boundary, and it is easy to bypass, but it will help you keep honest people honest.
For example:
I grant access to a specific group on my system, but I would like to limit this group as much as possible to my app:
CREATE LOGIN [myDomain\myGroup] FROM WINDOWS
So I will create a logon trigger that will check the application name on the session, and block any app I haven’t approved for these users.
CREATE TRIGGER connection_limit_trigger
ON ALL SERVER
FOR LOGON
AS
BEGIN
IF( IS_SRVROLEMEMBER('sysadmin') != 1 )
BEGIN
IF( IS_MEMBER('myDomain\myGroup') = 1 )
BEGIN
DECLARE #appName nvarchar(256)
SELECT #appName = program_name FROM sys.dm_exec_sessions where session_id = ##SPID
IF( #appName != 'My approved app' )
ROLLBACK;
END
END
END;
Notice that this trigger will affect ALL my users, so I added checks to avoid unnecessary restrictions on certain users.
I have a very simple app that I approved (See the ApplicationName property on the connection string):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;
namespace SampleAppSql
{
class Program
{
static void Main(string[] args)
{
SqlConnectionStringBuilder cnnstrbldr = new SqlConnectionStringBuilder();
cnnstrbldr.ApplicationName = #"My approved app";
cnnstrbldr.DataSource = #"."; //local machine
cnnstrbldr.IntegratedSecurity = true;
using (SqlConnection conn = new SqlConnection(cnnstrbldr.ConnectionString))
{
conn.Open();
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = #"SELECT ##version;";
string vers = (string)cmd.ExecuteScalar();
System.Console.WriteLine(#"SQL Server version: {0}", vers);
}
conn.Close();
}
}
}
}
When a user of this group tries to connect to SQL Server, the trigger will check the application name, and if it doesn’t match, the logon trigger will cause the connection to fail:
C:\>g:\temp\SampleAppSql.exe
SQL Server version: Microsoft SQL Server 2016 (RTM) …
C:\>sqlcmd -E -S .
Sqlcmd: Error: Microsoft ODBC Driver 13 for SQL Server : Logon failed for login 'myDomain\toto' due to trigger execution..
Please notice that this technique is not a security boundary, as the authorized users can simply manipulate the application name and bypass the trigger; but the offending user will not be able to deny that she/he tried to bypass your policy on purpose.
I hope this information helps.
For more details, I recommend the following articles:
Logon Triggers
(https://msdn.microsoft.com/en-us/library/bb326598.aspx)
Signing Stored Procedures in SQL Server (https://msdn.microsoft.com/en-us/library/bb669102(v=vs.110).aspx )
Customizing Permissions With Impersonation in SQL Server (https://msdn.microsoft.com/en-us/library/bb669087(v=vs.110).aspx )
SQL Server Audit (https://msdn.microsoft.com/en-us/library/cc280386.aspx )
-Raul

I don't think you should focus on verifying the application. I think you should instead verify the user's actions, in the Web Service (the MVC Controller). As this gives you the most fine grained control.
Then the Web Service should be the only component with direct network access to the database. There should be no harm in accessing the Web Service (the MVC Controller) from outside the intended UI (the MVC View)

Related

Accessing Azure SQL from Web App with EF Core, Docker and System Assigned Identity

I'm trying to access a serverless azure SQL database from an Azure Web Application running a docker container under Linux. The container is a .Net Core 3.1 web application using the latest EF Core. The web app has been configured to use a system assigned identity.
For the SQL user, I use the following PS script to get an SID, where the object ID is the system assigned identity object ID:
$principal = Get-AzADServicePrincipal -ObjectId $objectId
foreach ($byte in $principal.ApplicationId.ToByteArray())
{
$byteGuid += [System.String]::Format("{0:X2}", $byte)
}
$sid = "0x" + $byteGuid
Then, I created the user with db_owner role to the database using the SID like this...
'CREATE USER [AppUser] WITH DEFAULT_SCHEMA=[dbo], SID=' + '$(AppSiD)' + ' , TYPE = E'
...similar to the process described here:
https://blog.bredvid.no/handling-azure-managed-identity-access-to-azure-sql-in-an-azure-devops-pipeline-1e74e1beb10b
I've also updated the EF instance using the following method:
https://learn.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi#modify-aspnet-core
When the application tried to access the DB, the following exception is thrown:
Microsoft.Data.SqlClient.SqlException (0x80131904): Login failed for user '<token-identified principal>'.
EDIT I don't believe the SQL user to be causing the issue, as the error occurs whether the user exists or not.
I'd prefer to fix the error above but if there is is an alternative way to connect to the DB without using a SQL user I would appreciate the advice.
Thanks
EDIT
Elaborated on the SQL user process as the link is down at the time of posting
First you need to make your SQL database AAD-enabled. Then you can create a user for your Managed Identity like this
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
And then of course assign permissions to that user as needed.

Pass through Windows user for Datazen SQL Server data sources?

Is it possible to pass-through Windows User logins from Datazen through to SQL Server?
Scenario:
I created a Dashboard which uses a SQL Query as a data source.
The data source is of type "SQL Server" and the flag Integrated Security is set to YES.
I've also configured the data source to be "Real Time," to avoid any issues with caching.
I'm expecting the data view to execute on SQL Server with the credentials of the user which is browsing the final dashboard, unfortunately this is not the case.
Problem:
In this scenario the authentication against SQL Server is now done with the Windows user account, under which the Service "Datazen Server Data Acquisition Service" is running. I would expect that the "Acquisition Service" will delegate the effective user. Is this possible? Or will the authentication always be done with the service account?
I know about the "personalize for each member" setting, which passes-through the username to a data view query, but this is not the same as my requirement (leverage existing MSSQL-DB-Security for effective windows-users).
Your observations are correct that by default, the service account will be recognized as being logged into SQL Server.
There's no way to get around that with settings, but you can use some T-SQL magic to switch users at runtime. You have to lead your queries with an EXECUTE AS statement, like so:
EXECUTE AS USER = 'DomainName\' + '{{ username }}'
SELECT TOP 1 login_name -- This is just a nice quick test to echo the username.
FROM sys.dm_exec_sessions -- You can swap it out for your real query.
WHERE session_id = ##SPID
This, of course, also requires the "Personalize for each Member" setting to be turned on, so that the username is passed through.
It's pretty self-explanatory what's going on here, but basically you have to explicitly impersonate the request via your service account, as SQL Server will be connected to via the database using that account. Once you run this EXECUTE AS statement, it will use that user account for the remainder of the session.
Note that your service account will need permission the IMPERSONATE permission set, or else this will fail. It will also fail, of course, for any users that exist in your Datazen Server but do not have permissions against your SQL Server, and vice-versa. That's definitely the desirable behavior, but it's worth keeping in mind if you ever add users to one, you'll also have to add them to the other.
Disclaimer: I'm a Microsoft Support professional, paid to support Datazen.

Connect to MSSQL using a specific Windows account while the application uses different credentials

I've got an application which is running under under the credentials of the local user. However, I would like to allow this application access to a MSSQL database using specific credentials.
This isn't a problem if I use an SQL login, however I would like to use a specific Windows account for which I have the username (along with the domain) and password. Note that I do NOT wish to run the entire application using these credentials.
Is this at all possible? This SO question seems to suggest that using Integrated Security=SSPI in the connection string WITH Windows credentials specified will allow me to login to the database as that user, however I was not able to do this on my test machine.
Given how the SQL Server Management Studio logs into databases (i.e. it uses the current credentials or specified SQL credentials, but doesn't seem to permit specified Windows credentials) I'm thinking this cannot be done, but I would like a confirmation of this...
You could deal with this as the SQL Server end
by encapsulating the tasks that need done under the other account in a stored procedure created using the "EXECUTE AS Clause"
Create Proc sp_Dosomething_As_specific_user
WITH EXECUTE AS '{SpecificUser}'
BEGIN
/*Do Something*/
END
and allow the user account execute permissions on that
GRANT EXEC ON sp_Dosomething_As_specific_user TO {Actual_User}
For fuller details on the "EXECUTE AS" clause look at this
http://msdn.microsoft.com/en-us/library/ms188354.aspx
This means that you've limited the user to running only a specifically predefined action or set of actions as the other user as opposed to a general permission to let them impersonate the other user
Which is going to help keep whoever is responsible for IT security happy

SQL Server 2005/2008: Identify current user

I have a web application, which is using a SQL Server 2005 database.
My problem is, that the application has no role management. So the application always accesses the database with one default user. But now I have to save and access a value only for the current user.
Is there any way to do this? Maybe something like a session on the web server? The best way would be, if there is any possibility to access the current session id of the web server from T-SQL.
Do anyone understand my problem? :)
Allows a system-supplied value for the current login to be inserted into a table
DECLARE #sys_usr char(30);
SET #sys_usr = SYSTEM_USER;
SELECT 'The current user is: '+ #sys_usr;
GO
from MSDN
In my opinion, it's better don't do this. Another way: send to stored procedure current user from web sever:
command.CommandText = "EXEC mySP #user";
command.Parameters.Add("#user").Value = ((YourOwnUserClass)Session["user"]).Name;
// or System.Web.HttpContext.Current.User.Identity.Name; to use built-in
// from web page it becomes this.User.Identity.Name;
If you are using Windows integrated authentication instead of SQL accounts:
Give schema object permissions to a Windows group, not a user. Then add all of your application users to this group.
Use the built-in SUSER_NAME() function to retrieve the underlying Windows user name (in loginDomain\userName format.

What's the point of creating a user in order to access the DB located at SQL Server 2008

So far, after creating DB with all the schema, all I have done so for was accessing them (tables) by reference through ConnectionStrings.
Now, twice, I've read that it's better to create a DB user and access the DB trhough that user by including him in the connectionString.
I'd like to know why so?
Thank for helping
Your question isn't that clear. It seems that you're asking if it is better to use windows security ("Integrated Security=SSPI" in the connection string) or a username/password ("User ID=myUsername;Password=myPassword;").
Its always better to use windows security. Having login information within the connection string is a security risk. Its in cleartext (unless you take some complicated steps to secure that section), and is sent across the wire as cleartext unless you set up a trusted connection between application and server.
Is it better to "create a db user and access the db trhough that user by including him in the connection string?" No. Its better to create a sql server login for user's windows identities and let them use those credentials to access the server.
You do this if you wish to connect as a specific user, rather than (for example) just using the context of the current user which your application is running under. However, if you use SQL Server authentication (i.e. username and password), you'd need to provide that password in the connection string, which is something of a security problem.
If the application has a group of anonymous users (or manages users/passwords itself) then its better to use a Windows login and run the application under a service account (which has minimal required access to the database).
If you're running an interactive application on the desktop, you should let those users connect to SQL server in their own context, by adding them to SQL Server with the required rights (e.g. db read/write , remove any higher functions). Obviously you would use groups to make administration simpler rather than adding individual users.

Resources