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

如何用Node.js Net模块实现字符模式输入而非行模式输入?

实现Telnet/TCP服务器的实时密码输入隐藏(替换为*)

要解决这个问题,核心是让客户端终端切换到字符模式(逐键发送输入),并关闭本地回显,由服务器控制输入的显示逻辑。默认Telnet采用行模式,只有按下回车才会把数据发送给服务器,所以需要通过Telnet协议协商调整行为。

解决方案代码

const Net = require('net');

// Telnet协议指令常量
const IAC = 0xff; // 交互命令起始标记
const WILL = 0xfb; // 表示愿意启用某选项
const DO = 0xfd; // 请求对方启用某选项
const ECHO = 0x01; // 回显控制选项
const SUPPRESS_GO_AHEAD = 0x03; // 抑制前进选项(用于切换字符模式)

const server = Net.Server();

server.on('connection', (socket) => {
  let password = '';
  let isProcessingTelnetCmd = false;
  let telnetCmdBuffer = [];

  // 发送Telnet协商指令:要求客户端切换字符模式,由服务器控制回显
  socket.write(Buffer.from([IAC, DO, SUPPRESS_GO_AHEAD]));
  socket.write(Buffer.from([IAC, WILL, ECHO]));

  socket.write('Password: ');

  socket.on('data', (data) => {
    for (const byte of data) {
      // 处理Telnet协商指令,跳过无关的控制包
      if (isProcessingTelnetCmd) {
        telnetCmdBuffer.push(byte);
        if (telnetCmdBuffer.length === 2) {
          isProcessingTelnetCmd = false;
          telnetCmdBuffer = [];
        }
        continue;
      }
      if (byte === IAC) {
        isProcessingTelnetCmd = true;
        continue;
      }

      // 处理实际输入字符
      switch (byte) {
        case 0x0d: // 回车符
        case 0x0a: // 换行符
          socket.write('\n');
          console.log('用户输入的密码:', password);
          // 此处可添加密码验证逻辑
          password = '';
          socket.write('Password: ');
          break;
        case 0x7f: // 退格键(ASCII DEL)
          if (password.length > 0) {
            password = password.slice(0, -1);
            // 发送退格+空格+退格,清除终端上的一个`*`
            socket.write('\x08 \x08');
          }
          break;
        default:
          // 只处理可打印ASCII字符
          if (byte >= 0x20 && byte <= 0x7e) {
            password += String.fromCharCode(byte);
            // 回显`*`替代输入字符
            socket.write('*');
          }
          break;
      }
    }
  });

  socket.on('end', () => {
    console.log('连接已断开');
  });
});

server.listen(3000, () => {
  console.log('服务器监听在 127.0.0.1:3000');
});

关键逻辑说明

  • Telnet协商:通过发送IAC DO SUPPRESS_GO_AHEAD让客户端切换到字符模式(逐键发送输入),IAC WILL ECHO告知客户端由服务器控制回显,禁止客户端本地显示输入内容。
  • 逐字符处理:遍历收到的每个字节,过滤Telnet控制指令,只处理实际的输入字符。
  • 退格兼容:处理用户退格操作时,同步删除密码缓存的最后一位,并通过终端控制序列清除界面上的一个*,保证显示与实际输入一致。
  • 输入收尾:用户按下回车时,服务器输出完整密码,重置缓存并重新提示输入。

可选变体方案

  • 完全无显示输入:如果不需要显示密码长度,直接删除回显*的代码即可,用户输入时终端无任何反馈,仅服务器能看到完整密码。
  • 适配特殊终端:针对Windows Cmd自带的Telnet等特殊客户端,可额外添加ANSI终端控制序列处理,但上述代码已覆盖绝大多数标准Telnet客户端场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:03:14