I'd like to log all SQL that a client app is sending to a remote SQL server I have no access to. I'm thinking of some kind of client side proxy that can log and pass through data. It has to run on the same machine as the client app.
Any ideas appreciated.
SQL Server's protocol, TDS ("Tabular Data Stream") is not encrypted by default, so a trivial packet-forwarder could be used to proxy SQL Server connections and intercept commands (and their responses).
The TDS protocol specification is available from Microsoft's website, you could write your own proxy which can intercept commands that way: https://msdn.microsoft.com/en-us/library/dd304523.aspx?f=255&MSPPError=-2147217396
However, this is a large undertaking. You have other simpler options if you don't need to capture every connection:
If you control your application's source-code, then simply modify all database operations to intercept every SqlCommand's CommandText and Parameter values.
You could skip writing a proxy and instead use native packet-capture, you'll need to use WinPCap: https://www.winpcap.org/
You could also use SQL Server's Profiling features to get a log of every command executed: What are the APIs used by SQL Profiler?
What you are looking is called an SQL Profiler.
In specific - you are looking for an API for one.
I have never used an API of a profiler myself - but this one looks promising.
Also - take a look at this question for another sample.
If you want to have an impression of a working profiler client you can take a look at this answer.
Related
I have a Python package that I am able to run successfully on an Azure Data Science Virtual Machine. However, when I push it to Azure as a Function, I cannot successfully make a database connection. I was getting an error that the ODBC Driver 13 for SQL Server was not supported, so I changed the driver to ODBC Driver 17 for SQL Server and now I am NOT getting an error, but no data is being returned for a query that I know should return data.
Is there any other reason that data would not be returned? Firewall issues? do I need to add a binding? Do I need to separate out the connection string to feed each part (e.g., Driver, UID, PWD) into pyodbc.connect() separately? Right now I am feeding it in like this:
setting = os.environ("CONNECTIONSTRING")
conn = pyodbc.connect(setting)
This query works fine returning data when I run it on the VM using this code, just not as a Function.
(Note, this is different from my previous post regarding reading the Azure App Setting. That problem has been solved).
There are many parts where this could be breaking.
I'd suggest start by having a Profiler or Extended Events trace on your SQL Server to verify whether a connection is even being established. If not then you need to work through the the various points of connectivity to find out where it breaks. The identity, firewall, NSGs etc might all come into play here.
Once you see a connection then you can play with permissions to ensure that your query then returns your data.
Without a full picture of your infrastructure and settings it is hard to pin it down further.
Turns out it was not a database connectivity issue like I thought it was; it was a code error.
I am building a support ticket system using Sql Server 2014, ASP.Net MVC 5, angular JS etc.
As part of the design I want a way for my system to know when a ticket has been updated, deleted, or created.
That way if a user has a ticket open and it is changed while they have it open I can design the system to force them to refresh the ticket before they themselves can make changes to it, to prevent User B from overriding User A's changes they haven't seen.
Ideally, I'd like to design a TCP Protocol server as a Windows Service and be able to connect to it and send it data from table triggers in Sql Server.
Then the application front end would use Javascript and WebSockets. So the application would be connected to the socket server as well as sql server. When a user opens a ticket I would send a message that user XXY has Ticket 00X open. When a change happens in sql server it tells the server Ticket 00X changed. Then the Socket server tells clients connected to it that are looking at Ticket 00X that it has changed and the javascript prevents a submit until a fresh is done.
But... Can sql server do this at all? Doesn't appear so.
So I'm wondering if it's posisble to build a plugin for SQL Server to enable support for it like PostgreSQL's Notify feature.
Update:
I've discovered User Defined CLR Functions in SQL Server and have managed to get it working. (C#/.Net Framework) I made a static class with some static methods like,
public static int NotifyTicketUpdate(int ticketID)
{
//...
}
Then I registered it in SQL Server,
USE TLCDB;
CREATE ASSEMBLY MyCompanyName_MyDll
FROM 'd:\pathtodll\mydll.dll'
WITH PERMISSION_SET = SAFE;
CREATE FUNCTION XYZ_Notify_Ticket_Updated(#input int) RETURNS int
AS EXTERNAL NAME MyCompanyName_MyDll.UserDefinedFunctions.NotifyTicketUpdated;
Then to call it in SQL, I just do
select dbo.XYZ_Notify_Ticket_Updated(#ticketIDHere);
And it all works. My Static method in c# sends the TCP/IP message to my socket server, the server then checks to see who is looking at that ticket ID and sends them a Ticket_Updated message. The websocket layer running in client javascript sees it, and locks the ticket for updates/saves.
Or you can use Service Broker for handling asynchronous notifications. Not the simplest thing to learn, but lightweight, scalable and already built-in.
You could use CLR, which requires a bit of setup.
You could create an EXE that you can shell with parameters from an SP.
You could implement some standard concurrency. Optimistic vs Pessimistic
So yes, it's possible.
When we change the port number of SQL server, is any changes we have to done in the web application, to connect the database.
Probably not. There is a service that gets installed along with the database engine called SQL Browser that serves as a means to translate the instance name to a port. So, assuming that you didn't hard code the port number into the connection string, you should be good to go. Of course, you should test it first to make sure.
On my PC I have a small program to run SQL Server queries and gets the results back. I don't want to duplicate the DB on the server, I want to call that program on my PC from the server (The server runs Linux OS).
I was thinking of using a web-service to communicate with my PC (using C# maybe), I can attach my PC to a Dynamic DNS (DDNS like No-IP), so I always request the name of the PC not the IP (in case the router restarted and my PC got a new IP).
What do you think, is there a better way to do that?
The fastest solution will probably be to write a web services API written in C#/VB.NET whatever language you prefer. That API could be as simple as executing a remote ad-hoc sql query (rarely recommended) or as complex as a fully blown API. Obviously, security will be important any you may want to create your own SSL certificates and import them to your Linux server (if you're doing this on the cheap) to make sure that your home machine is the one that is reports it is!
I guess everything is possible but I am wondering how easy is it for someone to hijack a connection string with a network packet analyzer or equivalent tool.
A winforms application fetches data directly from an MSSQL server.
(Supposing there are no webservices in the middle for extra protection)
1) Is it possible for someone with an analyzer to read the connection string as clear text?
2) The connection string could be protected with an SSL certificate?
3) The SSL certificate should be installed on the SQL server?
4) I already own an SSL certificate https Could I install it also for the SQL server?
5) The speed of the the return data, will be reduced due to SSL?
Thanks in advance
Yes. If they're on the same network as the packet sniffer (henceforth "the sniffer") and the connection string is in plain text it's easy. Using a switch instead of a hub will not make it any harder to do this.
still possible using a man-in-the-middle attack. Channel binding is designed to detect and prevent this, along with careful examination of the certificate received by the client. Client certificates would help strengthen this as well
yes it should
as long as the host name matches the sql server exactly it should work, otherwise you'll need a new cert.
it probably will reduce the speed but not by much. Benchmark it and see if the slowdown still gives acceptable performance; there's no other way to predict the impact with any degree of reliability.
One other thing: if the connection string is encrypted I can still analyze the packet to find your server's location and if the data being passed back and forth isn't encrypted I can still read it even if I can't connect to the sql server. I can also potentially modify it. This is why it's unusual for a SQL connection to exist over the internet and why it's usually either connecting to a DB on the same server, connecting via a local network, connecting via a VPN, or encrypting the whole data stream.
If it isn't encrypted, it can be read, yes. Note that the SQL Native Client may often perform a non-SSL based encryption (depending on lots of factors), but yes, it can also be encrypted with SSL; see technet. And yes, it slows things down slightly. The requirements for the certificate are all in the technet article. But please don't expose your db server to the internet...