镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Fix NET-746: Add FTPClient.login(String, char[]) and char[] sendCommand/pass overloads - #419

Open
Inf1mum wants to merge 1 commit into
apache:masterfrom
Inf1mum:fix/NET-746-char-array-password
Open

Inf1mum wants to merge 1 commit into
apache:masterfrom
Inf1mum:fix/NET-746-char-array-password

Conversation

@Inf1mum

@Inf1mum Inf1mum commented Nov 4, 2026

Copy link
Copy Markdown

Overview

NET-746: FTPClient#login(String, String) takes the password as a String, which cannot be reliably wiped after use. This PR adds a char[]-based login path so that sensitive data never has to be materialized into a String, and zeroes the password array once it has been transmitted to the server.

Changes

  • FTPClient.login(String user, char[] password) (new): mirrors the existing login(String, String) flow, sends PASS through the new char[] path, and clears the password array with Arrays.fill(password, '\0') in a finally block once the password has been handed to the control connection (i.e. only when the password was actually transmitted; if the server never asks for a password, the array is left untouched).
  • FTP.pass(char[]) (new): symmetric with the existing pass(String).
  • FTP.sendCommand(String, char[]) and FTP.sendCommand(FTPCmd, char[]) (new): build and write the command as char[] end-to-end (buildMessage(String, char[]) and send(char[]) are new private helpers), so the sensitive arguments are never converted to a String. The ProtocolCommandEvent fired to command listeners reports the arguments as masked (PASS ******), unlike the String path, to keep secrets out of listener logs.
  • FTPSClient: the CCC post-processing was extracted into a private postSendCCC(...) helper and a matching sendCommand(String, char[]) override was added so that FTPSClient behaves identically for the new overload (previously only sendCommand(String, String) restored the plain socket after CCC).
  • Disambiguated existing bare-null call sites (sendCommand(command, null) in FTP) with (String) casts, since the new overloads otherwise make those calls ambiguous.

Tests

  • New FTPClientLoginCharPasswordTest with a local scripted FTP server:
    • login(String, char[]) sends PASS <password> on the wire and clears the array afterwards (even on a 530 rejection);
    • the password is not leaked to ProtocolCommandListeners (they see PASS ******);
    • the array is left untouched when the server never requests a password;
    • FTP.pass(char[]) returns the expected reply code.
  • FTPTest: CR/LF rejection tests for the new char[] argument path, symmetric with the existing String tests.

mvn test -Dtest=FTPTest,FTPClientTest,FTPClientLoginCharPasswordTest,FTPSClientTest passes.

Notes

  • The existing String-based API is unchanged; the new overloads are additive (@since 3.13.1).
  • changes.xml entry added under 3.13.1.

Thanks for considering this contribution!

…r FTP

FTPClient.login(String, char[]) sends the password as a char array and
clears the array once it has been transmitted to the server. The command
is built and written to the control connection as char[] end-to-end so
that sensitive data is never materialized into a String; command
listeners receive a masked ProtocolCommandEvent. FTPSClient gets a
symmetric sendCommand(String, char[]) override so the CCC transition is
preserved for the new overload.

Signed-off-by: Inf1mum <vadim.lazuk@mail.ru>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant