SQL Server transmits unencrypted passwords

While analyzing SQL Server's network protocol, I came across a weird fact: when a SQL Server client logs in using database authentication (as opposed to Windows authentication), it has to send the user's password in (arguably) unencrypted form, in blatant violation of all security guidelines ever written.

I am certainly not the first person to discover this. I just can't believe it hasn't been fixed.

In this article, we'll look at how the password is transmitted, and the reasons why this is a terrible idea.

What is the problem?

First, a little background.

SQL Server supports two types of authentication:

  • Windows authentication is the most common form of authentication into SQL Server. It uses the same authentication mechanism as other Windows components. No problem there: everything is nicely encrypted.

  • database authentication is when you don't want to use a Windows domain account, and you just want to create a user in SQL Server. That's the one with the problem.

Now, when a SQL Server client opens a connection to a SQL Server instance, it start with a handshake to agree on protocol, feature levels, and so on.

After that, there is a short exchange to open a TLS connection. So far, so good.

Then, if database authentication is being used, the client sends a packet containing the password in essentially clear form. It's actually slightly mangled, but an eight-year-old programmer would figure it out in less than five minutes. In fact, I find this Mickey-Mouse mangling insulting -- it fools exactly no one, so why bother?

Now, to be clear, that packet containing the password is encrypted using TLS, so you might think -- what's the harm? It's still encrypted, right?

Why this is a terrible idea

I see two reasons why this is a bad idea:

1 - TLS is quite secure per se, but only if it's enforced rigorously. It's common for SQL Server instances to use a self-signed certificate, or a certificate that is not easily verifiable. This means that it's going to be very tempting for database users to overlook any certificate problems, which means that a man-in-the-middle attack is entirely possible (in fact, that's how Gallium Data works, though it's an authorized man-in-the-middle).

2 - Public-key encryption has been around for decades, and there is simply no reason to pass credentials around in a form that can be read. Once your password is compromised, it's gone, and who knows what else is gone? We're not talking about just snooping on a connection here, we're talking about stealing your password.

Like almost every other credential system, SQL Server should use a method that does not require the password itself, but instead uses a single-use token, or something along these lines. A lot of very smart people have spent a lot of time figuring this stuff out. This problem was solved decades ago.

Some people will argue that database authentication should not be used, that everyone knows they should use Windows authentication, etc... This is irrelevant. If you support an authentication method, and there is an obvious and well-accepted way to do it right, why do it wrong?

And frankly, that half-hearted mangling of the password stinks to high heaven. It tells me that someone at Microsoft knew that this was a bad idea, but they couldn't be bothered.

So here we are, with a world-class enterprise database that features an authentication method that is literally as insecure as HTTP basic authentication. When was the last time anyone put any trust in that? And in an enterprise context?

Come on, Microsoft. I can't believe I'm the only one who thinks this is broken. Database authentication is a useful feature, but can we please bring it into the 21st century?