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

使用SSH.NET实现SFTP传输时,字符串转字节数组异常及密钥验证求助

正确验证SFTP主机密钥指纹(解决字符串转字节数组异常)

问题背景

使用SSH.NET通过SFTP传输文件时,需验证主机密钥指纹提升安全性。将从known-hosts获取的主机密钥(格式如ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP4cDyvxP/kbZ1XrPxxyMshbTtrY605xu5VL37uZt9mv7d2ZqD3TSWoEcUgHgtzGuRzkGTfDXdT9J=)以字符串存储在XML配置中,编写的字符串转字节数组方法抛出异常:

<![LOG[Failed: Exception occurred - Additional non-parsable characters are at the end of the string.]LOG]!>

错误原因

当前StringToByteArray方法是处理十六进制格式字符串的,但传入的是带算法前缀的Base64编码完整公钥,两者格式不匹配导致转换失败。另外,e.FingerPrint是主机密钥的哈希指纹字节数组,和直接解码Base64公钥得到的字节数组并非同一数据。

解决方案

提供两种验证方式,按需选择:

方案一:直接验证完整主机公钥(推荐,安全性更高)

直接使用known-hosts中的Base64公钥进行验证,无需计算指纹,避免哈希碰撞风险:

修改FtpHandler类的UploadFileSftp方法:

using System;
using System.IO;
using System.Linq;
using FsLogger;
using Renci.SshNet;

namespace FsUtils.FileOperations
{
    public class FtpHandler
    {
        public string User { get; set; }
        public string Password { get; set; }
        public string Server { get; set; }

        public void UploadFileSftp(string sourceFile, string targetDir, string sshHostKey)
        {
            // 拆分算法标识和Base64公钥部分
            var keyParts = sshHostKey.Split(new[] { ' ' }, 2);
            if (keyParts.Length != 2)
                throw new ArgumentException("Invalid host key format. Expected format: [algorithm] [base64-public-key]");

            string expectedAlgorithm = keyParts[0];
            byte[] expectedPublicKey = Convert.FromBase64String(keyParts[1]);

            using (var client = new SftpClient(Server, User, Password))
            {
                client.HostKeyReceived += (sender, e) =>
                {
                    // 对比算法和公钥字节数组
                    e.CanTrust = e.HostKey.Algorithm == expectedAlgorithm && 
                                 e.HostKey.Data.SequenceEqual(expectedPublicKey);
                };

                try
                {
                    client.Connect();

                    if (client.IsConnected)
                    {
                        // 确保目标路径包含文件名,避免上传到目录时出错
                        string targetPath = Path.Combine(targetDir, Path.GetFileName(sourceFile));
                        using (var fileStream = File.OpenRead(sourceFile))
                        {
                            client.UploadFile(fileStream, targetPath);
                        }
                    }
                    Logging.Info("File uploaded successfully");
                }
                catch (Exception ex)
                {
                    Logging.Error($"Exception occurred - {ex.Message}");
                }
                finally
                {
                    if (client.IsConnected)
                        client.Disconnect();
                }
            }
        }
    }
}

方案二:验证十六进制格式的指纹

如果坚持使用指纹验证,需先获取正确的十六进制指纹(可通过ssh-keyscan -t ecdsa-sha2-nistp256 <server> | ssh-keygen -lf -生成,格式如SHA256:abcdef1234...或AA:BB:CC:...),然后修改转换方法处理指纹格式:

修改FtpHandler类中的StringToByteArray方法及事件处理:

public void UploadFileSftp(string sourceFile, string targetDir, string sshHostKeyFingerprint)
{
    using (var client = new SftpClient(Server, User, Password))
    {
        client.HostKeyReceived += (sender, e) =>
        {
            byte[] receivedFingerprint = e.FingerPrint;
            byte[] providedFingerprint = StringToByteArray(sshHostKeyFingerprint);

            e.CanTrust = receivedFingerprint.SequenceEqual(providedFingerprint);
        };

        // 后续连接、上传逻辑同原代码...
    }
}

private byte[] StringToByteArray(string fingerprint)
{
    // 移除指纹中的分隔符(冒号或空格)
    string cleanHex = fingerprint.Replace(":", "").Replace(" ", "").Trim();
    // 移除可能的前缀(如SHA256:)
    if (cleanHex.Contains("SHA256:"))
        cleanHex = cleanHex.Substring(cleanHex.IndexOf(":") + 1);
    
    return Enumerable.Range(0, cleanHex.Length)
        .Where(x => x % 2 == 0)
        .Select(x => Convert.ToByte(cleanHex.Substring(x, 2), 16))
        .ToArray();
}

注意事项

  • 方案一无需额外转换公钥,直接验证原始密钥,安全性更高;
  • 方案二需确保指纹与目标服务器的主机密钥完全对应,避免因算法不一致导致验证失败;
  • 无论哪种方案,都要确保配置中的密钥/指纹来源可信,避免中间人攻击。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 22:44:55