'Prevent database access outside the application

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



Solution 1:[1]

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:

-Raul

Solution 2:[2]

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)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Raul G
Solution 2 symbiont