Dear security experts, 

I would like to hear you about a security flaw still present in Java, and 
whether it is worth to submit a new feature (JEP) or not. 

It is about how passwords are managed in the memory. Actually, Meltdown and 
Spectre show us recently how much it is important to limit the risk of 
accessing passwords that live in the memory, because unfortunately Java doesn't 
prevent leaking passwords all along classicals processing chains. Leaking, in 
the sense that the data are not explicitely erased from the memory after using 
them. 

Here is a scenario of how a password is taken in charge by a typical Web 
application : 
0) a user is asked to login, and send its credentials to the server with HTTPS 
(not our concern, it is just the start of the story) 
1) the Web server decodes the HTTP request and retrieve the login/password 
2) it computes a crypt of the password (alternatively, it can ask a remote 
service to check it, such as an LDAP server to do it ; but let's stay in the 
same JVM) 
3) the access to the expected resource is granted (or not) to the authentified 
(or not) user 

The JVM let lots of traces here and there : 
1) Inside the Web server : what is annoying here is that whithin every Java Web 
server, since we are relying on HTTP and that HTTP is text, this text is 
available only in the form of Strings (and if you perform a BASIC AUTH, the 
password will be processed as text ; if you have a registration form, the 
password POST params will be processed as text), and we all know that a String 
is immutable ; when dropped, the clear password will live in the memory before 
being reclaimed by the GC and reallocated. 
Curiously, the crypto specification states that since Strings are immutable, 
char arrays are preferred for storing passwords ; this is exactly what 
happenned with the legacy swing JPasswordField (within which the password is 
given as a char array), but that was completely missed in servlets. 
I propose to fix this by : 
1a) changing how passwords are exposed to the users in Java (not only in 
webapps) : a Password class that ensure to erase the chars after using them, 
and in the meantime to hide them properly (see below), 
1b) and change the servlet specification accordingly in order to forbid using 
String for passwords (see below). 
2) Computing a crypt : first, the password must be converted to bytes, then 
processed by a hash algorithm. 
2a) About char encoding : first, if we have a close look on how the password 
characters are encoded to bytes, this is performed with the help of 
java.nio.ByteBuffer, CharBuffer, java.nio.charset.Charset, CharsetEncoder. 
A charset encoder will allocate an average amount of memory for the byte 
buffer, but this may not be the right size, which cause to reallocate a new 
array ; the previous array is just dropped and will be reclaimed (one day) by 
the GC, but in the meantime, partial data are still alive in the memory. 
I propose to fix this with a SafeBuffer class that cleans intermediate sensible 
data when they are no longer in use (buffer underflow/overflow) (see below). 
2b) Hashing : nowaday, computing a crypt from a password consists on applying a 
hash function on the password and repeat so that it will take -say- 100 ms. 
100 ms is a very very long time in CPU time, and unfortunately the password 
bytes are still clear in the memory during this time (this is the case for 
PBKDF2 and BCrypt if you look at the algorithms). 
Inside a Web server where several simultaneous logins are attempted by 
different users, the chance for an attacker to capture a password is 
significantly increased. 
PBKDF2 and BCrypt are using the input password at each loop, making the 
password exposed in clear during all the hashing process. Conversely, Argon2 
first prehash the password, then drop it, and use the prehash password during 
the loop. BCrypt-with-SHA2 (not sure if this variant is available in the Java 
platform, maybe supply by a provider, but it exists in a Python security 
library) also prehash the password with SHA2, which makes it better than BCrypt 
alone. 
I propose just to promote algorithms (like Argon2 and BCrypt-with-SHA2) that 
are prehashing the password before the big loop, since they avoid to hold the 
password in clear. 

Details of the proposals and implementation : 
Note that things are subject to evolve according to your feedbacks ; the 
packages are my own, but could be moved to some Java namespace if a JDK 
integration would become relevant. 
1a) How passwords are exposed to the users : we could let the user deal with 
char[], but are we sure that he will erase properly the sensitive data ? I 
suggest a wrapper like this : 
https://github.com/alternet/alternet.ml/blob/master/security/src/main/java/ml/alternet/security/Password.java
 that ensure to clear data after using them. 
Usage : 
http://alternet.ml/alternet-libs/security/security.html#passwords 
Additionally, while the password is not in use, it is encrypted inside this 
class. Encryption doesn't prevent an attacker to retrieve the bytes, retrieve 
the algorithm, and retrieve the key, but all that informations are not clear in 
the memory, and it is harder to get back the clear password than letting it 
as-is in the memory. Advanced usage could consider to store the encryption key 
outside the current JVM / machine, but I didn't implement such solution. 
Other helper classes are available : 
https://github.com/alternet/alternet.ml/tree/master/security/src/main/java/ml/alternet/security
 
1b) How passwords are exposed in servlets : the idea is to capture the bytes 
before they are processed by the Web server, and if they appear to be 
passwords, to encrypt them in the safe Password class, and to clean the memory 
where they come from. 
I didn't patch the servlet API right now, but it would be relevant to have 
inside javax.servlet.ServletRequest a new method like this : 
List<Password> getPasswords(String fields...); // FORM auth 
http://alternet.ml/alternet-libs/security/security.html#webapps 
Right now, as a proof of concept, I have agnostic bindings for Servlets and 
REST (JAX-RS) for FORM auth and BASIC auth (or FORMs that contain passwords, 
such as a "new user registration"): 
https://github.com/alternet/alternet.ml/tree/master/security/src/main/java/ml/alternet/security/web
 
and implementations for Tomcat : 
https://github.com/alternet/alternet.ml/tree/master/security-tomcat-8.0/src/main/java/ml/alternet/security/web/tomcat
 
and Jetty : 
https://github.com/alternet/alternet.ml/tree/master/security-jetty-9.1/src/main/java/ml/alternet/security/web/jetty
 
(Tomcat and Jetty hacks are just for demonstration, they certainly need a 
deeper integration, but I have a full example webapp with LDAP auth that works 
well, and full test scenarios that show various usage examples) 
2a) Decoding bytes to characters without leaking : just a class that takes care 
of the data created, and that ensure to erase them. 
Here is an example of implementation : 
https://github.com/alternet/alternet.ml/blob/master/security-auth/src/main/java/ml/alternet/security/binary/SafeBuffer.java
 

You will find in the following project detailed informations and a complete 
test-suite that ensure that everything works properly : 
http://alternet.ml/alternet-libs/security/security.html 
Additionally, there is an auth framework that use that Password class and 
ensure to clean properly sensitive data when hashing. 

All those considerations are not big security issues (do little security issues 
exist ?), but do you think they ought to be taken into account in a new 
proposal (JEP) ? 

Best Regards, 
Philippe 

Reply via email to