tedious: [NODE v18] Failed to connect to {server} - socket hang up (code: ESOCKET)
Everything works in Node v14 and v16 (haven’t used v17 as it isn’t LTS or a candidate for it). This issue seems to only pop up with the latest current v18.
Note: sensitive data has been omitted.
Actual behaviour:
Error:: ConnectionError [SequelizeConnectionError]: Failed to connect to {sql_server_address}:1433 - socket hang up
at ConnectionManager.connect ([omitted]]backend/src/node_modules/sequelize/src/dialects/mssql/connection-manager.js:138:17)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at ConnectionManager._connect ([omitted]]backend/src/node_modules/sequelize/src/dialects/abstract/connection-manager.js:326:24)
at [omitted]]backend/src/node_modules/sequelize/src/dialects/abstract/connection-manager.js:250:32
at ConnectionManager.getConnection ([omitted]]backend/src/node_modules/sequelize/src/dialects/abstract/connection-manager.js:280:7)
at [omitted]]backend/src/node_modules/sequelize/src/sequelize.js:629:26
at NameService.getMessage ([omitted]]backend/src/src/app/app.service.ts:105:34)
at bootstrapFactory ([omitted]]backend/src/src/common/common.utils.ts:42:5) {
parent: ConnectionError: Failed to connect to {sql_server_address}:1433 - socket hang up
at Connection.socketError ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2222:28)
at Connection.socketEnd ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2239:12)
at Socket.<anonymous> ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2013:37)
at Socket.emit (node:events:549:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ESOCKET',
isTransient: undefined
},
original: ConnectionError: Failed to connect to {sql_server_address}:1433 - socket hang up
at Connection.socketError ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2222:28)
at Connection.socketEnd ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2239:12)
at Socket.<anonymous> ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2013:37)
at Socket.emit (node:events:549:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ESOCKET',
isTransient: undefined
}
}
Error:: ConnectionError [SequelizeConnectionError]: Failed to connect to {sql_server_address}:1433 - socket hang up
at ConnectionManager.connect ([omitted]]backend/src/node_modules/sequelize/src/dialects/mssql/connection-manager.js:138:17)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at ConnectionManager._connect ([omitted]]backend/src/node_modules/sequelize/src/dialects/abstract/connection-manager.js:326:24)
at [omitted]]backend/src/node_modules/sequelize/src/dialects/abstract/connection-manager.js:250:32
at ConnectionManager.getConnection ([omitted]]backend/src/node_modules/sequelize/src/dialects/abstract/connection-manager.js:280:7)
at [omitted]]backend/src/node_modules/sequelize/src/sequelize.js:629:26
at Name2Service.getMessage ([omitted]]backend/src/src/app/app.service.ts:105:34)
at bootstrapFactory ([omitted]]backend/src/src/common/common.utils.ts:42:5) {
parent: ConnectionError: Failed to connect to {sql_server_address}:1433 - socket hang up
at Connection.socketError ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2222:28)
at Connection.socketEnd ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2239:12)
at Socket.<anonymous> ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2013:37)
at Socket.emit (node:events:549:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ESOCKET',
isTransient: undefined
},
original: ConnectionError: Failed to connect to {sql_server_address}:1433 - socket hang up
at Connection.socketError ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2222:28)
at Connection.socketEnd ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2239:12)
at Socket.<anonymous> ([omitted]]backend/src/node_modules/tedious/src/connection.ts:2013:37)
at Socket.emit (node:events:549:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at processTicksAndRejections (node:internal/process/task_queues:82:21) {
code: 'ESOCKET',
isTransient: undefined
}
}
Configuration:
The connection is handled by sequelize.
{
username: '[OMITTED]',
password: '{OMITTED]',
host: '{OMITTED]',
logging: true,
}
I have tried passing recommended options but to no avail.
options: {
keepAlive: true,
encrypt: true,
enableArithAbort: true,
}
As previously mentioned: this works fine up to Node v16
Software versions
- NodeJS: 18.4.0
- node-mssql: 8.1.2
- tedious: 14.5.x | 14.6.x
- sequelize: 6.20.1
- SQL Server: SQL Server 2016 Service Pack 1 CU11 (13.0.4528.0)
About this issue
- Original URL
- State: open
- Created 2 years ago
- Reactions: 3
- Comments: 39 (7 by maintainers)
Actually, I now found a way to workaround this, but I’d only use it if there’s really no way to get a more secure certificate installed:
Any other security level higher than
0does change the list ofsigalgsthat are sent by OpenSSL in a way that makes the TLS connection fail.Ok, I think I finally figured out what’s going. 🙈
TLS Signature Algorithms extensions
Some background information first. TLS has a client side extension that is part of the
Hellomessage, called Signature Algorithms. That extension allows a client to specify what certificate signature algorithms it supports, and the TLS Server can then respond with a certificate that matches one of the allowed algorithms.If the Server does not have a signature that matches any of the signature algorithms specified, it can simply close the connection after receiving the Client’s
Hellomessage, as clearly the client won’t be able to do anything with it (otherwise it wouldn’t have specified which algorithms it can support).OpenSSL 3.0 / Node.js 17+
I’m not sure why this changed and whether this changed in OpenSSL or Node.js, but since the switch to OpenSSL 3.0 with the Node.js 17+ releases, the client TLS
Hellomessage sent by Node.js does not contain any signature algorithm that usesSHA-1. Use ofSHA-1in TLS certificate is hugely problematic, as they basically give zero security over an unencrypted connection. That’s why I believe this signature algorithm is not specified - it’s better to just fail hard and disallow encrypted but totally insecure connections.Unfortunately, even explicitly specifying
RSA+SHA1in the signature algorithms option in Node.js does not allow disabling this behaviour.Default Server certificate for SQL Server
In SQL Server, if you don’t install a custom certificate, SQL Server will generate a certificate for you. This is called the “Fallback certificate”. In older versions of SQL Server / Windows, this certificate uses the SHA1 algorithm. This, plus the behaviour I described above, leads to what you’re seeing here.
This certificate can be swapped with another self-signed certificate, which should fix this behaviour.
TL;DR
Node.js 17+ does not support certificates that use SHA1. The default certificate generated by SQL Server uses SHA1. That’s why the connection is closed by SQL Server after receiving the list of supported certificate algorithms from SQL Server. Switch the certificate on SQL Server to one that does not use SHA1, or switch to an unencrypted connection (absolutely not recommended), because using a SHA1 certificate is worse than using no encryption at all, as it adds no security but makes you think your connection is encrypted.
Something has been changed again, so neither ciphers nor maxVersion/minVersion tricks are working 😦 Any solution except downgrade to node 16?
@arthurschreiber Thanks for your effort and this great work!
This might be helpful for others: https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/configure-sql-server-encryption?view=sql-server-ver16#sql-server-generated-self-signed-certificates
It might be also worth to mention to not forget to add the
optionsproperty to the config object:Hey @arthurschreiber,
I found a relatively simple way to reproduce using an AWS EC2 instance:
npm install tedious, then runnode .This will succeed (return rows) for node 16.18.0 (latest), and an error for node 17 and later, here is the error I got on node 17.0.0
SQLServer could provide a C library that could be used by C/C++/PHP/ODBC/Ruby/Nodejs/JDBC, then all problem will be fixed quickly.
Hey @MichaelSun90, this specific DB server is not in Azure however our internal processes require all communication with DB servers be encrypted. Re option “options.trustServerCertificate” - yes, we already use this option (we needed this even with Node 16).
Tedious works fine when connecting to this DB server using Node 16, however in Node 18 (same codebase) tedious is unable to connect to the DB server. We can connect to other DB servers with tedious + Node 18, just not this one, so there is an environmental factor at play.
I am wondering if this issue may be the root cause, i.e. something to do with IPv6 + encryption: https://github.com/nodejs/node/issues/40537
Will need to try forcing the connection to use IP v4 to see if it resolves.
=== Follow-up: Forcing the use of IP v4 did not resolve
Just chiming in to say I have the exact same issue as @MartianH.
Server: SQL Server 2014 (12.0.5223.6) Windows Server 2012R2
Works great in Node 16 but upgrading to Node 18 causes the exact same failure as posted above.