basic-ftp
Advanced tools
+2
-1
@@ -24,3 +24,4 @@ "use strict"; | ||
| const defaultClientOptions = { | ||
| allowSeparateTransferHost: true, | ||
| /** For security reasons this library should not allow separate transfer hosts by default. */ | ||
| allowSeparateTransferHost: false, | ||
| maxListingBytes: 40 * 1024 * 1024 | ||
@@ -27,0 +28,0 @@ }; |
@@ -16,2 +16,6 @@ import { Socket } from "net"; | ||
| /** | ||
| * Returns true if an IP address is a loopback address. | ||
| */ | ||
| export declare function isLoopback(ip: string): boolean; | ||
| /** | ||
| * Returns true if an IP is a private address according to https://tools.ietf.org/html/rfc1918#section-3. | ||
@@ -18,0 +22,0 @@ * This will handle IPv4-mapped IPv6 addresses correctly but return false for all other IPv6 addresses. |
+7
-0
@@ -6,2 +6,3 @@ "use strict"; | ||
| exports.upgradeSocket = upgradeSocket; | ||
| exports.isLoopback = isLoopback; | ||
| exports.ipIsPrivateV4Address = ipIsPrivateV4Address; | ||
@@ -52,2 +53,8 @@ const tls_1 = require("tls"); | ||
| /** | ||
| * Returns true if an IP address is a loopback address. | ||
| */ | ||
| function isLoopback(ip) { | ||
| return ip === "::1" || ip.startsWith("127."); | ||
| } | ||
| /** | ||
| * Returns true if an IP is a private address according to https://tools.ietf.org/html/rfc1918#section-3. | ||
@@ -54,0 +61,0 @@ * This will handle IPv4-mapped IPv6 addresses correctly but return false for all other IPv6 addresses. |
@@ -1,2 +0,2 @@ | ||
| import { Writable, Readable } from "stream"; | ||
| import { Readable, Writable } from "stream"; | ||
| import { FTPContext, FTPResponse } from "./FtpContext"; | ||
@@ -18,5 +18,7 @@ import { ProgressTracker, ProgressType } from "./ProgressTracker"; | ||
| /** | ||
| * Prepare a data socket using passive mode over IPv4. Ignore the IP provided by the PASV response, | ||
| * and use the control host IP. This is the same behaviour as with the more modern variant EPSV. Use | ||
| * this to fix issues around NAT or provide more security by preventing FTP bounce attacks. | ||
| * Prepare a data socket using passive mode over IPv4. | ||
| * | ||
| * Will throw an error if the IP provided by the PASV response doesn't match the one of the control connection. | ||
| * The error will contain detailed information. This is done to provide more security by preventing FTP bounce | ||
| * attacks. | ||
| */ | ||
@@ -23,0 +25,0 @@ export declare function enterPassiveModeIPv4_forceControlHostIP(ftp: FTPContext): Promise<FTPResponse>; |
+15
-5
@@ -11,5 +11,5 @@ "use strict"; | ||
| exports.downloadTo = downloadTo; | ||
| const netUtils_1 = require("./netUtils"); | ||
| const stream_1 = require("stream"); | ||
| const tls_1 = require("tls"); | ||
| const netUtils_1 = require("./netUtils"); | ||
| const parseControlResponse_1 = require("./parseControlResponse"); | ||
@@ -69,5 +69,7 @@ /** | ||
| /** | ||
| * Prepare a data socket using passive mode over IPv4. Ignore the IP provided by the PASV response, | ||
| * and use the control host IP. This is the same behaviour as with the more modern variant EPSV. Use | ||
| * this to fix issues around NAT or provide more security by preventing FTP bounce attacks. | ||
| * Prepare a data socket using passive mode over IPv4. | ||
| * | ||
| * Will throw an error if the IP provided by the PASV response doesn't match the one of the control connection. | ||
| * The error will contain detailed information. This is done to provide more security by preventing FTP bounce | ||
| * attacks. | ||
| */ | ||
@@ -84,3 +86,11 @@ async function enterPassiveModeIPv4_forceControlHostIP(ftp) { | ||
| } | ||
| await connectForPassiveTransfer(controlHost, target.port, ftp); | ||
| // Strip IPv4-mapped IPv6 prefix (e.g. "::ffff:1.2.3.4" → "1.2.3.4") so the | ||
| // comparison works regardless of whether the OS uses a dual-stack socket. | ||
| const normalizedControlHost = controlHost.replace(/^::ffff:/i, ""); | ||
| const hostsAreCompatible = normalizedControlHost === target.host | ||
| || ((0, netUtils_1.isLoopback)(normalizedControlHost) && (0, netUtils_1.isLoopback)(target.host)); | ||
| if (!hostsAreCompatible) { | ||
| throw new Error(`PASV returned another host (${target.host}) for data transfer that you have connected to (${controlHost}). Even though the FTP protocol allows this, basic-ftp disables this feature by default for security reasons. If you do need this feature, instantiate the Client with the optional paramter "allowSeparateTransferHost: true". See the README documentation for more information.`); | ||
| } | ||
| await connectForPassiveTransfer(normalizedControlHost, target.port, ftp); | ||
| return res; | ||
@@ -87,0 +97,0 @@ } |
+1
-1
| { | ||
| "name": "basic-ftp", | ||
| "version": "5.3.1", | ||
| "version": "6.0.0", | ||
| "description": "FTP client for Node.js, supports FTPS over TLS, IPv6, Async/Await, and Typescript.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index", |
+1
-1
@@ -72,3 +72,3 @@ # Basic FTP | ||
| - `allowSeparateTransferHost (boolean)`, the FTP spec makes it possible for a server to tell the client to use a different IP address for file transfers than for the initial control connection. Today, this feature is very rarely used. Still, the default for this is set to `true` for backwards-compatibility reasons. If you experience any issues with NAT traversal in local networks or want to provide more security and prevent FTP bounce attacks, set this to `false`. | ||
| - `allowSeparateTransferHost (boolean)`, the FTP spec makes it possible for a server to tell the client to use a different IP address for file transfers than for the initial control connection. This is a potential vector for FTP bounce attacks, so by default this is set to `false` and the library will throw an error if a server tries to redirect transfers to a different host. Set this to `true` only if you are connecting to a server that legitimately requires it. | ||
@@ -75,0 +75,0 @@ `close()` |
140725
0.9%3123
0.81%