How does Console.readPassword() work, and why does it return a char[] instead of a String?
answer
- No echo: typed chars not shown
- Returns char[] = wipeable; String = immutable, can't clear
- Arrays.fill(pwd, '\\0') in a finally block
- Overload takes a format-string prompt
- String could linger in heap dump until GC
basics
~20 sreadPassword() reads a line of input from the terminal without showing the typed characters (no echo). It returns a char[] instead of a String so you can erase the password from memory afterward by filling the array with zeros - Strings are immutable and can't be wiped.
solid answer
~40 sConsole.readPassword() reads one line from the terminal with echoing disabled, so the typed characters are not displayed - ideal for passwords. It returns a char[] rather than a String for security: Strings in Java are immutable, so you cannot clear their contents, and they may linger in the heap (and even the string pool) until garbage collected, where a memory dump could expose them. A char[] is mutable, so after using the password you call Arrays.fill(pwd, '\0') (or '') to overwrite it immediately, shrinking the window in which the secret sits in memory. There is also an overload readPassword(String fmt, Object... args) that prints a formatted prompt first. Like all Console methods, it requires a non-null Console; if System.console() is null (redirected input, IDE), readPassword is unavailable and you must handle that case.
code
java · 13 linesConsole console = System.console();
if (console == null) {
throw new IllegalStateException("No interactive console available");
}
char[] password = console.readPassword("Enter password: ");
try {
boolean ok = authenticate(currentUser, password);
console.printf(ok ? "Welcome%n" : "Access denied%n");
} finally {
// Overwrite the secret as soon as we're done with it.
java.util.Arrays.fill(password, '');
}go deeper
Knows readPassword hides typed characters and returns a char[], and that you should clear it after use.
Explains the immutability/wipeability rationale (String can't be cleared, char[] can via Arrays.fill) and uses a finally block.
Discusses the threat model (heap dumps, GC timing), the best-effort nature of wiping, avoiding new String(pwd), and preferring char[]-accepting crypto APIs.
Sets org-wide secret-handling conventions, weighs JVM-level limits of in-memory wiping, and chooses interfaces (KeyStore/PBEKeySpec) that keep secrets in char[]/byte[] end to end.
## The two jobs readPassword does `Console.readPassword()` does two security-relevant things that ordinary input cannot: 1. **No echo.** Normally a terminal *echoes* - it shows each character as you type it. When reading a password you do not want it visible on screen (shoulder-surfing). `readPassword` switches the terminal so typed characters are **not** displayed, then restores normal echo when done. 2. **Returns a wipeable buffer.** It returns the typed line as a `char[]` (an array of characters), not a `String`. There is also a prompting overload: ```java Console console = System.console(); char[] pwd = console.readPassword("Enter password for %s: ", username); ``` The first argument is a **format string** (same grammar as printf) and the rest are its arguments, so you can print a prompt and read in one call. ## Why char[] and not String - the core point ### Strings are immutable A Java `String` cannot be changed after creation. There is **no method to overwrite its characters**. So once a password lives in a String, you cannot erase it; you can only drop your reference and wait for the **garbage collector** (the JVM subsystem that reclaims unused memory) to eventually free it - and you do not control *when* that happens. ### Secrets should not linger While the password sits in memory, it is exposed to risks: a **heap dump** (a snapshot of the program's memory, e.g. after a crash or taken by an attacker/admin) could reveal it; swap files could persist it. Best practice for secrets is to **minimize the time** they exist in memory in readable form. ### char[] is mutable - you can wipe it Because an array is mutable, you can zero it as soon as you are done: ```java char[] pwd = console.readPassword("Password: "); try { authenticate(pwd); // use it } finally { java.util.Arrays.fill(pwd, '\0'); // overwrite immediately } ``` This overwrites every character with the null character `''`, so even if the memory is later dumped, the password is gone. The `finally` block ensures the wipe happens even if authentication throws. > Caveat (honesty): wiping a char[] is best-effort, not absolute. The JVM may copy data around, and some APIs you pass the password to may internally create Strings. But char[] is strictly better than String because it at least makes wiping *possible*. ## Terms defined - **Echo**: the terminal displaying characters as you type them; disabled here. - **Immutable**: cannot be modified after creation (Strings are immutable). - **char[]**: an array of `char` values - mutable, so its contents can be overwritten. - **Garbage collector (GC)**: automatic memory reclaimer; you cannot force *when* it runs. - **Heap dump**: a snapshot of the JVM's memory that can be inspected. - **Arrays.fill(arr, value)**: utility that sets every element of an array to a given value. ## How to derive the answer Start from "passwords are secrets that should not be displayed and should not linger." No-echo handles display. The lingering problem requires the ability to erase the secret; only a mutable container (char[]) allows that, while String (immutable) does not. That is exactly why the API returns char[].
- After reading the password, you call new String(pwd) to pass it to a method that takes a String. What's wrong with that?It recreates the immutable-String problem: the secret now lives in a String you can't wipe and may persist until GC. Prefer APIs that accept char[] (e.g. PBEKeySpec, KeyStore), and wipe the array; only convert to String if you truly cannot avoid it.
- Why use a finally block to wipe the array?So the wipe runs even if the code in between throws an exception, guaranteeing the secret doesn't survive in memory after an error path.
saying these in an interview costs you the question
- Saying it returns a String
- Claiming wiping the char[] is 100% guaranteed (it's best-effort)
- Forgetting to wipe the array after use
- Immediately converting the char[] to a String (new String(pwd)) - defeats the purpose
- Thinking no-echo means the input is encrypted (it's just not displayed)