You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express.js HTTPS API在AWS Lightsail运行数小时后出现SSL类错误求助

Node.js HTTPS API SSL相关错误排查与解决

我用Node.js开发了网站联系表单的API,部署在AWS Lightsail上,通过Cloudflare获取免费SSL证书。API启动5-6小时后,控制台会出现不影响运行的错误,初始警告如下:

(node:5532) Warning: An error event has already been emitted on the socket. Please use the destroy method on the socket while handling a 'clientError' event.
    at warnUnclosedSocket (node:_http_server:839:11)
    at TLSSocket.socketOnError (node:_http_server:853:5)
    at onParserExecuteCommon (node:_http_server:888:19)
    at onParserExecute (node:_http_server:809:3)

更新内容

我在代码中添加了打印错误到控制台的逻辑:

server.on("clientError", (error, socket) => {
    console.log(error)
});

得到了一系列不同的错误:

[Error: A00D0000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:c:\ws\deps\openssl\openssl\ssl\record\ssl3_record.c:355:
] {
  library: 'SSL routines',
  reason: 'wrong version number',
  code: 'ERR_SSL_WRONG_VERSION_NUMBER'
}
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
[Error: A00D0000:error:0A0000C1:SSL routines:tls_post_process_client_hello:no shared cipher:c:\ws\deps\openssl\openssl\ssl\statem\statem_srvr.c:2241:
] {
  library: 'SSL routines',
  reason: 'no shared cipher',
  code: 'ERR_SSL_NO_SHARED_CIPHER'
}
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
[Error: A00D0000:error:0A000102:SSL routines:tls_early_post_process_client_hello:unsupported protocol:c:\ws\deps\openssl\openssl\ssl\statem\statem_srvr.c:1677:
] {
  library: 'SSL routines',
  reason: 'unsupported protocol',
  code: 'ERR_SSL_UNSUPPORTED_PROTOCOL'
}
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
Error: read ECONNRESET
    at TLSWrap.onStreamRead (node:internal/stream_base_commons:217:20) {
  errno: -4077,
  code: 'ECONNRESET',
  syscall: 'read'
}
[Error: A00D0000:error:0A0000C1:SSL routines:tls_early_post_process_client_hello:no shared cipher:c:\ws\deps\openssl\openssl\ssl\statem\statem_srvr.c:1762:
] {
  library: 'SSL routines',
  reason: 'no shared cipher',
  code: 'ERR_SSL_NO_SHARED_CIPHER'
}
[Error: A00D0000:error:0A00006C:SSL routines:tls_parse_ctos_key_share:bad key share:c:\ws\deps\openssl\openssl\ssl\statem\extensions_srvr.c:646:
] {
  library: 'SSL routines',
  reason: 'bad key share',
  code: 'ERR_SSL_BAD_KEY_SHARE'
}

我的server.js代码:

const express = require('express');
const chalk = require("chalk");
const https = require('https');
const fs = require('fs');

const app = express();
const options = {
    key: fs.readFileSync('./ssl/private-key.pem'),
    cert: fs.readFileSync('./ssl/certificate.pem'),
};

const server = https.createServer(options, app);
server.listen(443, () => {    
    console.log(chalk.magenta(`[API]: `) + chalk.green('PORT : [ 443 ]'))
});

package.json代码:

{
  "name": "contact-api",
  "version": "1.0.0",
  "description": "Contact API",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "axios": "^1.4.0",
    "body-parser": "^1.20.2",
    "chalk": "^4.1.2",
    "cors": "^2.8.5",
    "crypto": "^1.0.1",
    "deep-email-validator": "^0.1.21",
    "express": "^4.18.2",
    "express-rate-limit": "^6.7.1",
    "figlet": "^1.6.0",
    "fs": "^0.0.1-security",
    "https": "^1.0.0",
    "moment": "^2.29.4",
    "nodemailer": "^6.9.3"
  }
}

问题原因与解决方案

原因分析

这些错误大多来自恶意扫描或不兼容的客户端请求:

  • ERR_SSL_WRONG_VERSION_NUMBER/ERR_SSL_UNSUPPORTED_PROTOCOL:客户端使用了过时的SSL/TLS版本(如SSLv3、TLSv1.0)连接服务,Node.js默认不支持这类不安全协议。
  • ERR_SSL_NO_SHARED_CIPHER/ERR_SSL_BAD_KEY_SHARE:客户端加密套件与服务不匹配,或是恶意构造的握手请求。
  • ECONNRESET:客户端在连接建立过程中主动断开,可能是扫描工具中断请求,或是网络波动导致。

初始警告是因为处理clientError事件时未正确销毁socket,触发Node.js的警告机制。

解决方案

  1. 正确处理clientError事件,消除警告
    修改clientError处理逻辑,按Node.js提示调用socket.destroy(),同时可选择性过滤频繁的非关键错误,避免日志刷屏:
server.on("clientError", (error, socket) => {
    // 仅记录非ECONNRESET的关键错误
    if (!error.message.includes('ECONNRESET')) {
        console.error('Client error:', error);
    }
    // 必须调用destroy关闭socket
    socket.destroy();
});
  1. 限制SSL/TLS版本与加密套件,提升安全性
    在HTTPS服务器选项中明确指定支持的安全TLS版本和加密套件,拒绝过时协议:
const options = {
    key: fs.readFileSync('./ssl/private-key.pem'),
    cert: fs.readFileSync('./ssl/certificate.pem'),
    // 仅支持安全的TLS版本
    minVersion: 'TLSv1.2',
    maxVersion: 'TLSv1.3',
    // 指定现代安全加密套件(可按需调整)
    ciphers: 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384'
};
  1. 利用Cloudflare过滤恶意请求
    既然已使用Cloudflare,直接在后台开启安全功能拦截无效请求:
  • 启用SSL/TLS严格模式,让Cloudflare处理前端SSL握手,后端只需与Cloudflare通信(可改为HTTP服务,简化本地SSL配置)。
  • 将安全级别设为“本质安全”或更高,自动拦截恶意扫描和过时协议请求。
  • 开启Bot Fight Mode或Super Bot Fight Mode,拦截自动化扫描工具。
  1. 可选:改用Cloudflare Tunnel替代本地SSL配置
    若不想在Lightsail上维护SSL证书,可使用Cloudflare Tunnel将本地服务直接暴露到Cloudflare网络,所有SSL由Cloudflare处理,既简化配置又提升安全性。

内容的提问来源于stack exchange,提问作者Enes Emre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:02:01