使用ssl的ftp连接的php到nodejs代码示例

a0zr77ik  于 2023-05-28  发布在  Node.js
关注(0)|答案(1)|浏览(114)

我有一个PHP代码与工作罚款。

$host = 'ftp.someserver.com';
$port = 21;
$pass = 'xxxx';
$user = 'username';

$connect = ftp_ssl_connect($host, $port);
$login = ftp_login($connect, $user, $pass);

if ($login) {
    ftp_pasv($connect, true);
    $list = ftp_mlsd($connect, ".");
    var_dump($list);
}
else {
   exit(error_get_last());
}

ftp_close($connect);

从WinSCP连接(c#示例):

SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Ftp,
    HostName = "ftp.someserver.com",
    UserName = "username",
    Password = "xxxx",
    FtpSecure = FtpSecure.Explicit,
    TlsHostCertificateFingerprint = "dd:70:5c:67:xx:xx:xx:....",
    TimeoutInMilliseconds = 45000,
};

sessionOptions.AddRawSettings("FtpForcePasvIp2", "1");

我需要在nodejs上写这个,试图使用basic-ftp包,但总是给予错误:

SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:332:
] {
  library: 'SSL routines',
  function: 'ssl3_get_record',
  reason: 'wrong version number',
  code: 'ERR_SSL_WRONG_VERSION_NUMBER'
}

UPD:

这是我在node.js上的示例代码,在我的本地windows机器上,我得到了如上所述的错误,在其他机器上,就像这样。不太明白是什么原因,需要插入到secureOptions,但认为它需要。

const ftp = require("basic-ftp") 
const config = {
    host: "ftp.someserver.com",
    user: "username",
    password: "xxxx",
    port: 21,
    secure: true,
}

const client = new ftp.Client()
// client.ftp.verbose = true
try {
    await client.access(config)
    console.log(await client.list())
}
catch(err) {
    console.log(err)
}
client.close()

控制台输出(在我看来隐藏了一些不重要的细节):

Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: Host: ftp.shopdrawing.co.il. is not in the cert's altnames: DNS:cp31.box.co.il
    at new NodeError (node:internal/errors:387:5)
    at Object.checkServerIdentity (node:tls:354:12)
    at TLSSocket.onConnectSecure (node:_tls_wrap:1545:27)
    at TLSSocket.emit (node:events:513:28)
    at TLSSocket._finishInit (node:_tls_wrap:949:8)
    at TLSWrap.ssl.onhandshakedone (node:_tls_wrap:730:12) {
  reason: "Host: ftp.shopdrawing.co.il. is not in the cert's altnames: DNS:cp31.ox.co.il",
  host: 'ftp.shopdrawing.co.il',
  cert: {
    subject: ...,
    issuer: [Object: null prototype] { ... },
    subjectaltname: 'DNS:cp31.box.co.il',
    infoAccess: [Object: null prototype] { ... },
    modulus: '....',
    bits: 2048,
    exponent: '0x10001',
    pubkey: <Buffer 30 82 01 ... >,
    valid_from: 'Mar 24 00:00:00 2023 GMT',
    valid_to: 'Jun 22 23:59:59 2023 GMT',
    fingerprint: '8A:99:3A:xx:xx:......',
    fingerprint256: 'DD:70:5C:xx:xx:......',
    fingerprint512: '4F:84:8A:xx:xx:......',
    serialNumber: '....',
    raw: <Buffer 30 82 05 d2 ... >,
    issuerCertificate: { ... },
    code: 'ERR_TLS_CERT_ALTNAME_INVALID'
  }
}
eivnm1vs

eivnm1vs1#

reason:“主持人:ftp.shopdrawing.co.il.不在证书的别名中:DNS:cp31.ox.co.il“,
您正在尝试连接到名称为“www.example.com”的主机ftp.shopdrawing.co.il。该主机的FTP服务器的证书是“cp31.ox.co.il”,但与您连接的名称不匹配。这就是为什么你得到这个错误。
已通过secureOptions: {checkServerIdentity: () => {return null;}}解决,但不确定禁用服务器名称检查是否完全正确
即使禁用证书验证的一部分也不是一个好主意。在这种情况下,您禁用了主机名验证,这意味着攻击者可以使用由受信任的CA颁发的任意有效证书来发起中间人攻击。
不幸的是,FTP服务器的设置似乎是一团糟。证书中的名称(“cp31.box.co.il“)无法解析为IP地址,因此您无法将其用作目标。最好的方法是正确地使用定义一个checkServerIdentity,就像你建议的那样,但不是接受任何东西,而是只接受具有特定指纹或特定主题的证书-请参阅此处以获取您可以从证书对象访问的属性。
例如,您可以检查subjectaltname:

const config = {
    host: "ftp.shopdrawing.co.il",
    ...
    secureOptions: {checkServerIdentity: (name,cert) => {
        if (cert.subjectaltname != "DNS:cp31.box.co.il") {
            return Error("unexpected certificate");
        }
        return null;
    }},
}

或通过指纹检查特定证书:

const config = {
    host: "ftp.shopdrawing.co.il",
    ...
    secureOptions: {checkServerIdentity: (name,cert) => {
        if (cert.fingerprint256 != "DD:70:5C:67:A9:93:C3:08:C5:88:12:E5:80:9B:7C:86:7D:CA:D8:8B:1D:E3:05:66:72:5D:D2:D2:8C:03:15:0A") {
            return Error("unexpected certificate: " + cert.fingerprint256);
        }
        return null;
    }},
}

相关问题