当前位置: 首页 > news >正文

如何在 Go 中安全高效地将 SSH 公钥复制到远程服务器

本文介绍使用 Go 标准库 os/exec 直接将本地 SSH 公钥写入远程服务器 ~/.ssh/authorized_keys 的正确方法,避免 shell 字符串拼接风险,兼容 macOS/Linux 环境,且不依赖 ssh-copy-id。 本文介绍使用 go 标准库 `os/exec` 直接将本地 ssh 公钥写入远程服务器 `~/.ssh/authorized_keys` 的正确方法,避免 shell 字符串拼接风险,兼容 macos/linux 环境,且不依赖 `ssh-copy-id`。在 Go 中通过命令行方式(如 cat key.pub | ssh user@host 'cat >> ~/.ssh/authorized_keys')实现公钥分发看似直观,但原代码存在多个关键问题: ? 错误调用 exec.Command(identity, address):将两个独立命令(cat ... 和 ssh ...)作为参数传给单个 exec.Command,实际会尝试执行名为 cat /home/foo/.ssh/foobar.pub 的二进制文件(显然不存在); ? 未正确构建管道逻辑:Go 的 exec.Command 不会自动解析 shell 管道符 |,需显式设置 Stdin; ? 路径硬编码与拼接风险:~/.shh/authorized_keys(注意 typo:shh 应为 ssh)和字符串格式化易引入路径注入或权限错误; ? 忽略 SSH 连接前置条件:如目标用户 .ssh 目录权限(应为 700)、authorized_keys 文件权限(推荐 600),否则 OpenSSH 会拒绝加载。? 正确做法是:用 Go 原生读取公钥文件内容,并将其作为 stdin 流式传递给 ssh 进程。这样既规避了 shell 解析的不确定性,又提升安全性与可移植性。以下是完整、健壮的实现:import ( "io" "log" "os" "os/exec" "path/filepath")func copySSHPubKeyToServer(username, hostname, keyName string) error { // 1. 构建公钥文件路径(使用 filepath.Join 避免路径拼接漏洞) homeDir := os.Getenv("HOME") if homeDir == "" { return fmt.Errorf("HOME environment variable not set") } keyPath := filepath.Join(homeDir, ".ssh", keyName+".pub") // 2. 打开公钥文件 keyFile, err := os.Open(keyPath) if err != nil { return fmt.Errorf("failed to open public key %s: %w", keyPath, err) } defer keyFile.Close() // 3. 构建 ssh 命令:注意目标路径必须为 ~/.ssh/authorized_keys(修正 typo) // 使用绝对路径更可靠(如 $HOME/.ssh/authorized_keys),但 ~ 在 ssh 上下文中通常可被服务端 shell 展开 sshTarget := username + "@" + hostname cmd := exec.Command("ssh", sshTarget, "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys") // 4. 将公钥文件设为命令标准输入 cmd.Stdin = keyFile // 5. 捕获输出以便调试 output, err := cmd.CombinedOutput() if err != nil { log.Printf("SSH command failed (output: %s)", string(output)) return fmt.Errorf("failed to copy SSH key to %s: %w", sshTarget, err) } log.Printf("Successfully added %s.pub to %s's authorized_keys", keyName, sshTarget) return nil}? 关键注意事项: RedClaw 百度推出的手机端万能AI Agent助手

http://www.jsqmd.com/news/669446/

相关文章:

  • 用一颗6脚5050RGB,我复刻了同事那个超省资源的跑马呼吸灯方案
  • 【UCIe】Sideband:芯片互连的“幕后指挥官”
  • STmin和BS别再乱设了!手把手教你调优CAN-TP大数据传输
  • Selenium自动化测试中,页面一刷新就报错?手把手教你搞定StaleElementReferenceException
  • Unity程序化建模避坑指南:手搓一个可捏的陶罐,我踩了这些法线和UV的坑
  • DeepMind的哲学家其人及研究方向
  • 构建跨平台物联网协议解析器:基于CGO与LuaJIT的Go/Lua混合编程实践
  • 告别硬编码!Spring Security 6.x 配置类实战:如何优雅管理用户角色与API权限
  • IEC61850 GOOSE报文实战解析:用Wireshark抓包看懂变电站的‘心跳’
  • 超越假设检验:Neyman-Pearson准则在机器学习模型评估与A/B测试中的高级玩法
  • Unity实战:从零构建物理驱动的小车移动系统
  • ISP色彩校正矩阵(CCM)揭秘:从人眼感知到Sensor数据的数学桥梁
  • 01华夏之光永存:黄大年茶思屋榜文解法「难题揭榜第9期 第1题」异构网络QoS保障下带宽四倍提升与高效传输协议工程化解法
  • Triton实战:用‘建墙’比喻彻底搞懂Grid和Program ID(含避坑指南)
  • Python 3.12 Special Attribute - 28 - __match_args__
  • 【ROS进阶篇】第八讲(下) URDF实战:从语法到机器人建模
  • 3分钟让Windows和Linux拥有macOS精致光标体验:开源免费解决方案
  • 智能座舱必备!手把手教你DIY安装流媒体后视镜(含避坑指南)
  • 系统集成岗真相:除了上架设备巡检打杂,技术人还能怎么成长?
  • Cisco交换机SSH配置全流程:从基础设置到安全加固(附常见问题排查)
  • 穿越机电调协议进化史:从PWM到DShot1200的性能对比实测
  • 人类的打标与机器的打标不同
  • 别再傻傻点图标了!用CMD命令mstsc连接远程桌面,效率翻倍的5个隐藏技巧
  • DPDK老司机避坑指南:I210网卡Force Link Mode的真实含义与EEE模式关闭实操
  • 从入门到精通:LIN总线协议深度解析与实战应用
  • 从零部署Neo4j到实战API调用:一份避坑指南
  • 别再只写ToDoList了!用微信小程序做个五子棋,面试作品集瞬间出彩
  • 从响应头到恶意探测:手把手教你像黑客一样‘指纹识别’主流WAF(附奇安信、阿里云案例)
  • 02华夏之光永存:黄大年茶思屋榜文解法「难题揭榜第9期 第2题」异构组网多设备智能资源协同调度算法工程化解题全解
  • CentOS7部署DockerCompose:从零搭建容器编排环境