
本文介绍使用 golang.org/x/crypto/ssh/terminal.ReadPassword 实现无回显密码输入的完整方案,替代不安全的 fmt.Scan,避免明文暴露敏感信息。
本文介绍使用 `golang.org/x/crypto/ssh/terminal.readpassword` 实现无回显密码输入的完整方案,替代不安全的 `fmt.scan`,避免明文暴露敏感信息。
在命令行程序中读取密码时,直接使用 fmt.Scan 或 fmt.Scanf 会导致用户输入的密码以明文形式显示在终端上,存在严重安全隐患。Go 标准库本身不提供跨平台的密码隐藏输入函数,但官方维护的扩展包 golang.org/x/crypto/ssh/terminal 提供了经过充分测试、支持 Unix/Linux/macOS 及 Windows 的安全方案:terminal.ReadPassword。
该函数从指定文件描述符(通常为 0,即 os.Stdin.Fd())读取输入,自动禁用终端回显,并在用户按下回车后返回字节切片。它会正确处理退格、删除等编辑操作,且不将密码缓存于可读内存中(如未做额外拷贝),符合基本安全实践。
以下是一个最小可用示例:
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 characters)\n", len(password))
// 注意:实际应用中请勿打印或记录明文密码!此处仅作演示。
}? 关键注意事项:
- 必须手动执行 go get golang.org/x/crypto/ssh/terminal 安装依赖;
- ReadPassword 返回 []byte,如需字符串请用 string(pwd) 转换,但应尽快清空原始字节切片(例如用 bytes.Fill(password, 0))以减少内存残留风险;
- 该函数默认读取至换行符,不支持超时或取消机制,如需高级控制(如带超时、中断支持),建议结合 syscall 或第三方库(如 github.com/AlecAivazis/survey/v2)实现;
- 在 Windows 下依赖 golang.org/x/sys/windows,但 x/crypto/ssh/terminal 已内部处理兼容性,无需额外干预。
✅ 总结:永远不要用 fmt.Scan 读取密码;优先选用 terminal.ReadPassword —— 它是 Go 生态中事实标准、跨平台、安全可靠的解决方案。开发涉及认证的 CLI 工具时,应将其作为密码输入的默认实现。










