How to deny access to SQL Server to certain login over SSMS, but allow over .Net SqlClient Data Provider
I think there is no reliable solution for your problem since Application Name
is modifiable parameter
that cam be changed by any user.
Here is how to change it within SSMS
:
In Connect to Database Object
dialog choose Options, open Additional Connection Parameters
and choose any name for Application Name
like this:
Now sys.dm_exec_sessions
DMV and Program_name() will show you what you passed in your connection string in Application Name
parameter:
You can use a server logon trigger to make custom logon validations and reject them whenever you see fit. You will see this trigger listed below "Server Objects" and inside "Triggers" if you are using SSMS.
For example:
CREATE TRIGGER strRejectSSMSConnectionForSQLLogin1
ON ALL SERVER FOR LOGON
AS
BEGIN
IF ORIGINAL_LOGIN() = N'SQLLogin1' AND PROGRAM_NAME() LIKE N'Microsoft SQL Server Management Studio%'
BEGIN
RAISERROR('Direct connection by SSMS refused.', 16, 1)
ROLLBACK
END
END
The ROLLBACK
inside the trigger will reject the connection (there's an implicit transaction wrapping the call to the trigger on the logon event).
Be careful when implementing logon triggers, if not coded properly you will be rejecting logins that should be able to login (including your own!). Make sure to test on test/dev environments first.
Keep in mind that this code is executed before the session is created, so system views that rely on the session id (SPID) won't contain the currently checked login until the triggers ends without rollback or high enough failure.
In the ideal sense, this is a process / policy / management issue. Even if someone knows the password, if it is against company policy for anyone but a DBA to connect to Production (well, you might have a Release Engineering team and/or sys admins, etc), and there are penalties for breaking the rules, then that should be sufficient (assuming that such rules are enforced).
Trying to prevent a particular application from connecting is impossible. As sepupic demonstrated, it is fairly easy to change the "program name". But even if the developer can't figure that out, there are plenty of other programs that can connect to SQL Server. Most people will have access to SQLCMD.exe and even the deprecated OSQL.exe. The developer can connect from within Visual Studio, and they can even create their own app to connect via ".Net SqlClient Data Provider". Oh, and now we even have Azure Data Studio. It's just too many.
Still, this might could still be possible if we approach it from the other direction: instead of preventing application X from connecting, how about only allowing application Y to connect? Sure, we again get into the "program name", and even "hostname" can be spoofed, BUT, I am pretty sure that the client's IP Address cannot be spoofed (at least not through the connection string keywords). You know the IP Address of the app server(s), or can easily find it from the
sys.dm_exec_connections
DMV (in theclient_net_address
field).Starting with the Logon Trigger suggested by EzLo, we can modify the logic that determines if the connection is valid or not to be the following:
IF (ORIGINAL_LOGIN() = N'SQLLogin1' AND ( CONVERT(VARCHAR(10), CONNECTIONPROPERTY('net_transport')) <> 'TCP' OR CONVERT(VARCHAR(10), CONNECTIONPROPERTY('client_net_address')) <> '10.10.10.10' -- uncomment below (and comment-out line above) if app uses multiple IP addresses -- OR CONVERT(VARCHAR(10), CONNECTIONPROPERTY('client_net_address')) -- NOT IN ( '10.10.10.10', '10.10.10.11', ...) )) BEGIN RAISERROR('Non-application connection refused.', 16, 1); ROLLBACK; END;
The only ways in now would be to either log onto the Production machine, or to have their workstation spoof the IP of the app server. Hopefully devs do not have any access to log onto Production. And spoofing an existing IP on a network causes problems which might adversely affect Production, so they won't be trying that, right? Right?