Unencrypted connection to SQL Server throws handshake error - sql-server

The bounty expires in 3 days. Answers to this question are eligible for a +50 reputation bounty.
Squazz wants to draw more attention to this question:
It either seems I haven't been able to explain myself well enough, or that the answer is not well known. Either way I hope for clarification on what could be going on here.
I have a .NET 6 service running in a container (based on the mcr.microsoft.com/dotnet/aspnet:6.0-focal image). When my service needs to talk to the SQL Server database, I must set SECLEVEL=1 in my OpenSSL config. I run the following when creating the container (taken from this github issue: https://github.com/dotnet/SqlClient/issues/776#issuecomment-825418533)
RUN sed -i '1i openssl_conf = default_conf' /etc/ssl/openssl.cnf && echo "\n[ default_conf ]\nssl_conf = ssl_sect\n[ssl_sect]\nsystem_default = system_default_sect\n[system_default_sect]\nMinProtocol = TLSv1.2\nCipherString = DEFAULT:#SECLEVEL=1" >> /etc/ssl/openssl.cnf
If I don't, I get this error:
A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: SSL Provider, error: 31 - Encryption(ssl/tls) handshake failed)
But... my connection string has not set anything about encrypt or anything else that indicates that I must make an encrypted connection. And when I look at EF Core 6 or less, Encrypt=False is the default. So if you don't do anything explicit, I assume that the connection is not encrypted.
My connection string looks like this
Server=123,456;Database=123;User ID=123;PWD=123;multipleactiveresultsets=True;
On the .NET side I'm using Microsoft.EntityFrameworkCore.SqlServer 6.0.13, which has a dependency on Microsoft.Data.SqlCliet 2.1.4. Both of these has encrypt=false as default for the connection strings.
And that's where I'm unable to understand what happens.
If the connection is not encrypted, why do I have to set SECLEVEL=1 to avoid handshake errors? Why does a handshake even happen?

If the SQL Server you are connecting to is configured with force encryption, TLS/SSL will be used for all communication regardless of whether the client requests encryption or not.
Even if encryption is not required by client or server, login packets for the credential exchange are still encrypted. The setup needed to do so occurs as part of the pre-login handshake as described in this answer. This introduces the TLS/SSL requirement.

Related

SQL Server Service Broker not sending messages, unable to start endpoint

I had a perfectly working SQL Server Service Broker this morning, until I tested how it recovers from crashing.
I forced a system shutdown on the sender during a messaging session between servers over a network. I was sending binary messages of about 5mb size. There are automatic procedures for sending, replying and receiving messages and ending conversations from both sides in place and my setup uses certificates for security.
I am now unable to send any messages from the server side.
Both sides of the messaging chain have queues on and it does not seem like poison message handling would be causing this. The sender side accepts new messages but is not sending them.
The sender side transmission queue has messages with transmission_status
The Service Broker endpoint cannot listen for connections due to the following error: '10013(An attempt was made to access a socket in a way forbidden by its access permissions.)'.
Running ALTER ENDPOINT myendpoint STATE = STARTED returns the same error as above.
Running select * from sys.endpoints shows the endpoint with state_desc = STARTED anyhow..
Running select state_desc from [sender_database].sys.conversation_endpoints shows state_desc = CONVERSING for all results.
Running SELECT COUNT(*) FROM dbo.sender_queue returns 0.
There is no other traffic to the port my endpoint is using, at least not any that is visible with netstat or the TCPView tool. The ports have rules to allow traffic from the firewall and sqlagent and sqlsrvr processes also have extra rules to be allowed.
Using ssbdiagnose tool with ssbdiagnose -level info configuration from service... from the sender side shows a (not new) error
The route for service sender_service is classified as REMOTE. This will result in the message being forwarded.
along with some other errors about certificates that have always been there even when messaging was working. Ssbdiagnose with RUNTIME flag shows nothing at all.
Ssbdiagnose from the target side now says an exception occurs during connection. The target database also has a couple of reply messages stuck in the transmission queue with an empty transmission_status.
Edit: Seems that occasionally the status on the target side changes to the error 10060 connection failed...
What more can I do to diagnose the problem and fix it?
Edit: I tried changing the port the endpoint uses but the same error is thrown.
Edit: I am able to ping the servers from each other. Ssbdiagnose with RUNTIME option on target side says it cannot find the connection to the SQL Server that corresponds to the routing address of my sender endpoint/database.
The Service Broker endpoint cannot listen for connections due to the following error: '10013(An attempt was made to access a socket in a way forbidden by its access permissions.)'
WSAEACCESS (10013) is a rather unusual socket listen error. I never encountered it before. A quick search reveals KB3039044: Error 10013 (WSAEACCES) is returned when a second bind to a excluded port fails in Windows which is an acknowledged bug in Windows Server 2008R2, 2012 and 2012R2 when excluding a range of ports (netsh ... add excludedportrange ...). So my first question is, are you on one of the affected server OSes and are you actually using a network port exclusion range?
I strongly urge you to open a Microsoft support case for this issue and follow up with them, making sure networking guys are involved (again, WSAEACCESS is rather unusual symptom). This is not one of the usual issues and it is difficult to diagnose over forums discussion.

Windows LDAP API: No connection over SSL

I’m trying to connect to an LDAP directory over SSL using the Windows LDAP C-API. This fails with error code 0x51 = LDAP_SERVER_DOWN while the event log on the client computer has this:
„The certificate received from the remote server does not contain the expected name. It is therefore not possible to determine whether we are connecting to the correct server. The server name we were expecting is eim-tsi2.sam.develop.beta.ads. The SSL connection request has failed. The attached data contains the server certificate.”
This is can’t be true since “Ldap Admin” is able to connect over SSL and port 636.
The LDAP directory is an Oracle DSEE which has the CA and the server certificate in the appropriate cert store.
The client has the CA installed in the “Trusted Root Certification Authorities” and there in the „Local Computer“ physical store. I assumed this to be the right place for the CA since my little client program uses the Windows LDAP C-API; LDAP Admin indeed expects the CA there.
Here is an excerpt of my program omitting the error handling and other obvious source code:
ld = ldap_sslinit(host, LDAP_SSL_PORT, 1);
// Set options: LDAP version, timeout ...
rc = ldap_set_option(ld, LDAP_OPT_SSL, LDAP_OPT_ON);
// Now connect:
rc = ldap_connect(ld, NULL);
Result:
0x51 = LDAP_SERVER_DOWN
Connecting without SSL succeeds so the LDAP server is generally accessible.
Since Ldap Admin is able to connect over SSL, I assume the certificates are valid and in the right place. But obviously the LDAP API expects them somewhere else and cannot get the server certificate from the server. I configured the certs as described here: https://msdn.microsoft.com/en-us/library/aa366105%28v=vs.85%29.aspx
What am I doing wrong?
Sometimes it helps reading error messages more carefully. The entry in the event viewer caused by an unsuccessful bind over SSL was "The server name we were expecting is eim-tsi2.sam.develop.beta.ads."
I should have noticed that the name should have been eim-tsi2.cgn.de.(etc.), instead. So the domain name part was wrong.
This is a bug in Schannel which can be solved by an entry in the registry as described here: https://support.microsoft.com/en-us/kb/2275950.
I still do not know why LDAPAdmin was able to connect without that additional registry key although it also uses the WINLDAP API and therefore should have run into the same error. But that doesn’t matter any more.
Thanks, Andrew, for your help.

Intermittent SQL Exception - network-related or instance-specific error

We have a very strange intermittent issue which has started coming up over the last month or so whereby some connections to mssql server fail with the error:
System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)
The error does not bring down the site, nor does it require a db restart - if you simply rerun the same query will work the second time. This means a lot of users will hit an error every now and then and have to refresh the error page for things to work.
Now, my initial knee-jerk reaction was this could be due to:
Resource related issue - so I started running SQL profiler and perfmon, but did not find any issues with the serve struggling to keep up with the number of connections / sec. I've been looking at MSSQL:SQL Errors, MSSQL:Wait Statistics, MSSQL:Exec Statistics, MSSQL:Locks. Does anyone have any guidance on other stats I should be poking and prodding here?
Unclosed DB connections - I ruled this one out after going through all the data-tier code. We have all the fail safes in place to stop this from happening.
Connection / Network related issue: our SQL server sits on a separate server (MS SQL Server Standard 2008) to our application server (running ASP.Net on IIS7) - both servers run on xlarge Amazon EC2 instances with all security policies configured (as per Amazons direction). Anyone got guidance on how to test the connectivity between the two servers or if this could be the issue?
Is it a possible issue with the IIS connection string? I have not tested this but should we be fully qualifying the server with the computer name we are connecting to (just thought of it)? We use a connection string in the format: server=xxxxx;Database=xxxx;uid=xxxx;password=xxx;
Your thoughts and insight is very much appreciated!
Thanks in advance
Solved. After testing almost every possible performance metric and examining every piece of code, I discovered that the error was caused by a bit of deprecated database code. The main issue was being caused by code using:
SqlConnection.ClearPools;
For future reference, any other developers looking to debug their code and manage connection pools, an excellent resource can be found here: http://www.codeproject.com/KB/dotnet/ADONET_ConnectionPooling.aspx
Try changing the connection string to the FQDN+port
server=xxxxx.domain.tld,1234;
Note: you don't need any instance name if you use port
On our global corporate intranet... we had a similar issue that happened to remote clients: more often if they were further away, never in the same building as the server.
After some poking around, chatting to the DBAs and MS, it was said to be caused by timing/Kerberos/too many firewalls etc. Adding FQDN+port removed all our issues.
It may be solved by switching to TCP/IP instead of Named Pipes, if you can.
Perhaps you can test this by changing the server name to the server IP address.
I use server=tcp:servername in my connection string to force TCP.
KB313295
It seems like connection are not being closed correctly, and after some time you can't open any more new connections. As the total allowed connections to database is a constant digit.
If you are using C#/VB.net
Are you using "Using" statements to open the connections ?
using (System.Data.SqlClient.SqlConnection con = new SqlConnection("YourConnection string"))
{
con.Open();
}

Hijacking connection string with network packet analyzer

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...

FreeTDS Bad token from the server (SQL Server)

Today we had a lot more activity than normal between our Ruby on Rails application and our remote legacy SQL Server 2005 database, and we started getting the error below intermittently. What is is? How can I prevent it (besides avoiding the situation, which we're working on)?
Error Message:
ActiveRecord::StatementInvalid: DBI::DatabaseError: 08S01 (20020) [unixODBC][FreeTDS][SQL Server]
Bad token from the server: Datastream processing out of sync: SELECT * FROM [marketing] WHERE ([marketing].[contact_id] = 832085)
You need to use some sort of connection pooling.
Windows itself (including Windows Server X) will only allow a certain number of socket connections to be created in a given time frame, even if you close them. All others will fail after that.
A connection pool will keep the same sockets open, avoiding the problem. Also, new connections are real slow.
This Microsoft article says:
Often caused by an abruptly terminated network connection, which causes a damaged Tabular Data Stream token to be read by the client.
Was the server network bound? I have no experience with SQL Server, but does it have a limit on the number of connections you can make?
Add the following to your script; the first statement you run:
SET NO_BROWSETABLE OFF

Resources