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

使用SSHy与sshpk-browser实现SSH公钥认证时签名无效问题排查

SSH公钥认证签名无效问题排查(SSHy + sshpk-browser)

我在浏览器端使用SSHy库实现SSH设备连接,正在添加公钥认证支持,但服务器始终返回签名无效错误。不带签名的第一个SSH_MSG_USERAUTH_REQUEST能收到SSH_MSG_USERAUTH_PK_OK响应,但发送带签名的请求时,总是得到SSH_MSG_USERAUTH_FAILURE。我用sshpk-browser库进行签名,基于RFC4252规范构造签名,代码如下,求排查构造过程中的潜在问题。

const decodedPublicKey = config.privateKey.toPublic().toString('ssh', { hashAlgo: 'sha512' }).split(' ')[1];
const publicKey = atob(decodedPublicKey);

var m = new SSHyClient.Message();
m.add_bytes(String.fromCharCode(SSHyClient.MSG_USERAUTH_REQUEST));
m.add_string(this.termUsername);
m.add_string('ssh-connection');
m.add_string('publickey');
m.add_boolean(true); // has signature
m.add_string('rsa-sha2-512'); // public key algorithm name
m.add_string(publicKey); // public key

// Create signature
var sigMsg = new SSHyClient.Message();
sigMsg.add_string(SSHyClient.kex.sessionId);
sigMsg.add_bytes(String.fromCharCode(SSHyClient.MSG_USERAUTH_REQUEST));
sigMsg.add_string(this.termUsername);
sigMsg.add_string('ssh-connection');
sigMsg.add_string('publickey');
sigMsg.add_boolean(true); // has signature
sigMsg.add_string('rsa-sha2-512');
sigMsg.add_string(publicKey);
const sigMsgString = sigMsg.toString();

// Sign signature
const sign = config.privateKey.createSign('sha512');
sign.update(sigMsgString);
const signature = sign.sign();

m.add_string(atob(signatureToString)); // signature

this.parceler.send(m);

潜在问题及修正方案

1. 未定义变量引用错误

代码最后一行使用了未定义的signatureToString变量,实际签名结果存储在signature变量中,这会导致传入atob的参数无效,生成错误的签名内容。

修正:
根据sshpk的返回值类型调整:

// 若sign.sign()返回Buffer,转base64后再解码为二进制字符串
m.add_string(atob(signature.toString('base64')));
// 若sign.sign()直接返回base64字符串
m.add_string(atob(signature));

2. 签名的SSH格式封装缺失

SSH协议要求签名字段必须是包含算法名和签名二进制的结构化字符串(格式为string(算法名) + string(签名二进制)),直接传入原始签名数据不符合规范。

修正:
先构造符合SSH规范的签名封装结构,再添加到请求中:

// 构造签名的SSH格式包装
const sigWrapper = new SSHyClient.Message();
sigWrapper.add_string('rsa-sha2-512');
sigWrapper.add_string(signature); // signature需为二进制格式

// 将包装后的签名加入主请求
m.add_string(sigWrapper.toString());

3. 签名数据的编码损坏

sigMsg.toString()会将二进制消息转换为UTF-8字符串,这会破坏非ASCII字节,导致签名内容与服务器预期的原始二进制流不符。

修正:
使用SSHy Message提供的原始二进制获取方法(如toBuffer()或getBytes(),取决于SSHy API):

// 替换sigMsg.toString()为原始二进制数据
const sigMsgBinary = sigMsg.toBuffer();
const sign = config.privateKey.createSign('sha512');
sign.update(sigMsgBinary);
const signature = sign.sign();

4. 签名算法指定不精确

仅指定sha512可能无法触发rsa-sha2-512组合算法,部分库需要完整的算法标识符来确保签名逻辑匹配。

修正:
改用完整的算法名称:

const sign = config.privateKey.createSign('rsa-sha2-512');

5. 公钥处理的冗余步骤

手动拆分SSH格式公钥的base64部分再解码的步骤可以简化,直接使用sshpk提供的二进制公钥获取方法,避免手动解析出错。

修正:

// 直接获取公钥的二进制数据
const publicKey = config.privateKey.toPublic().toBuffer().toString('binary');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 18:03:28