
本文介绍使用 Go 标准扩展包 golang.org/x/crypto/ssh/terminal 中的 ReadPassword 函数,安全、跨平台地隐藏用户密码输入,避免明文显示和缓冲区残留风险。
本文介绍使用 go 标准扩展包 `golang.org/x/crypto/ssh/terminal` 中的 `readpassword` 函数,安全、跨平台地隐藏用户密码输入,避免明文显示和缓冲区残留风险。
在 Go 命令行程序中,直接使用 fmt.Scan 或 fmt.Scanf 读取密码存在严重安全隐患:不仅密码会以明文形式实时显示在终端上,还可能被命令历史、进程参数或调试日志意外捕获。这与 Bash 中 read -s 的静默输入行为截然不同,因此必须采用专门的终端控制方式。
推荐方案是使用 golang.org/x/crypto/ssh/terminal 包提供的 terminal.ReadPassword(int) 函数。该函数底层调用系统级终端 API(如 Unix 的 ioctl 或 Windows 的 SetConsoleMode),临时关闭当前标准输入(os.Stdin)的回显模式,读取字节流后立即恢复,全程不缓存明文到可检索的字符串变量中(返回的是 []byte),显著提升安全性。
以下为完整可运行示例:
package main
import (
"fmt"
"golang.org/x/crypto/ssh/terminal"
"os"
)
func main() {
fmt.Print("Enter password: ")
password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read password: %v\n", err)
os.Exit(1)
}
fmt.Println() // 换行,避免密码输出紧贴提示符
fmt.Printf("Password received (%d bytes)\n", len(password))
// ⚠️ 注意:实际业务中应立即哈希或清空 password 切片
// 例如:for i := range password { password[i] = 0 }
}关键注意事项:
- 需先安装依赖:go get golang.org/x/crypto/ssh/terminal;
- ReadPassword 接收文件描述符(通常为 os.Stdin.Fd()),在 Windows 和类 Unix 系统均兼容;
- 返回值为 []byte 而非 string,既避免 UTF-8 解码开销,也便于后续安全擦除(通过循环置零);
- 函数会自动处理回车键(\r 或 \n),不将其包含在结果中;
- 若需支持自定义输入流(如重定向场景),注意 ReadPassword 仅适用于真实终端——可通过 terminal.IsTerminal(os.Stdin.Fd()) 预检。
总之,terminal.ReadPassword 是 Go 生态中事实标准的密码静默输入方案,兼顾安全性、可移植性与简洁性,应作为命令行工具中密码采集的首选实践。










