基于gliderlabs/ssh的SSH公钥匹配兼容问题求助
解决不同类型SSH公钥的匹配兼容问题
要实现rsa、ed25519等不同类型SSH公钥的兼容匹配,核心是不要直接对比MarshalAuthorizedKey生成的格式化字符串(不同类型公钥的格式开头不同,且可能包含注释差异),而是提取公钥的唯一标识来存储和对比,具体方案如下:
方案一:使用SHA256指纹作为唯一标识
指纹是公钥的哈希值,同一公钥的指纹唯一,不受类型和注释影响。
1. 处理用户上传的公钥,存储指纹
// 解析用户上传的公钥字符串(支持rsa/ed25519等所有SSH标准类型) uploadedKeyStr := "ssh-rsa AAAA..." // 或用户上传的其他类型公钥 keyBytes := []byte(uploadedKeyStr) pubKey, _, _, _, err := ssh.ParseAuthorizedKey(keyBytes) if err != nil { // 处理解析错误,比如非法公钥格式 panic(err) } // 生成SHA256格式的指纹,作为唯一标识存入数据库 fingerprint := ssh.FingerprintSHA256(pubKey) // 将fingerprint与用户信息关联后存储到数据库
2. 在SSH认证时对比指纹
// gliderlabs/ssh的公钥认证回调函数 func authHandler(ctx ssh.Context, key ssh.PublicKey) bool { // 从会话中获取客户端公钥,生成对应指纹 sessionFingerprint := ssh.FingerprintSHA256(key) // 查询数据库,校验指纹是否存在 exists, userData := queryUserByFingerprint(sessionFingerprint) if exists { // 将用户数据存入上下文,供后续请求使用 ctx.Set("user", userData) return true } return false } // 初始化SSH服务器时配置认证回调 func main() { server := &ssh.Server{ Addr: ":2222", PublicKeyHandler: authHandler, // 其他服务器配置... } if err := server.ListenAndServe(); err != nil { panic(err) } }
方案二:使用公钥原始二进制数据对比
ssh.PublicKey的Marshal()方法返回符合SSH协议的公钥原始二进制数据,同一公钥的该数据唯一,也可用于匹配。
1. 存储上传公钥的二进制数据
uploadedPubKeyBytes := pubKey.Marshal() // 将uploadedPubKeyBytes与用户信息关联后存储到数据库(注意存储为二进制字段)
2. 认证时对比二进制数据
func authHandler(ctx ssh.Context, key ssh.PublicKey) bool { sessionPubKeyBytes := key.Marshal() // 查询数据库,对比二进制数据是否匹配 exists, userData := queryUserByPubKeyBytes(sessionPubKeyBytes) if exists { ctx.Set("user", userData) return true } return false }
关键说明
- 你之前测试不匹配的原因:
MarshalAuthorizedKey生成的是带格式的字符串(比如开头区分ssh-rsa/ssh-ed25519),且可能包含客户端注释,直接对比必然因类型或注释差异失败。 - 两种方案都能兼容所有SSH标准公钥类型,推荐使用SHA256指纹,存储和查询更便捷。
内容的提问来源于stack exchange,提问作者Gaurav Gola
相关产品推荐
相关产品推荐

