2

I'm currently creating the login functionality of a java web application just using java and JDBC. What built in java libraries are there to make the authentication process easier. I am able to query my PostgreSQL database and retrieve user information such as their password and username but I do not want to store it in plain text.Any tips would be great and o yeah I'm not using spring, which I see there is plenty for.

Nooby1
  • 49
  • 1
  • 6
  • 1
    Are you in a JEE type environment? If so, which one (i.e. Tomcat, Wildfly, etc.)? – stdunbar Jan 13 '22 at 01:37
  • Is JEE an IDE? If so I am using Intellij. If its a framework of any sort, than no I am not. – Nooby1 Jan 13 '22 at 01:41
  • Are you asking something like authentication to servlets? your API endpoints? or are you just trying to make a login page? I got confused when you said you don't want to store the credentials in plain text so I thought now you're asking how to store your passwords. – crimson589 Jan 13 '22 at 01:43
  • No, [JEE](https://stackoverflow.com/questions/7295096/what-exactly-is-java-ee) (previously J2EE) is a set of libraries and specifications but it sounds like this is a standalone Java program. Some of the code you've written would be useful. – stdunbar Jan 13 '22 at 01:48
  • I am currently only making the backend, API endpoints. I am not familiar with servlets. Just using Java JDBC with Postgres and an API I am storing the password in a PostgreSQL Database and am using a small web framework for controller. Does this make sense? – Nooby1 Jan 13 '22 at 01:48
  • O Java 1.8 if that helps – Nooby1 Jan 13 '22 at 01:51

1 Answers1

2

Generally, password matching is done by storing a one-way hash of the password, instead of storing the password itself as plain text. When someone tries to log in, your application generates a one-way hash of the password the user has entered, and checks whether it matches any of the hashes stored in the database.

Hashing is done with the MessageDigest class:

byte[] passwordBytes = password.getBytes(StandardCharsets.UTF_8);

byte[] passwordHash;
try {
    passwordHash = MessageDigest.getInstance("SHA-256").dist(passwordBytes);
} catch (NoSuchAlgorithmException e) {
    // It should be impossible to get here, since SHA-256 is
    // a standard algorithm supported by all Java runtimes.
    throw new RuntimeException(e);
}

The password column in your database should be defined as a binary type, like VARBINARY. Then you can store the bytes directly:

try (PreparedStatement statement =
        connection.prepareStatement(
            "INSERT INTO users (name, passwordhash) VALUES (?, ?)")) {

    statement.setString(1, name);
    statement.setBytes(2, passwordHash);
    statement.executeUpdate();
}

You can check whether a login attempt matches in a similar manner:

try (PreparedStatement statement =
        connection.prepareStatement(
            "SELECT name, email, phone FROM users"
            + " WHERE name = ? AND passwordHash = ?")) {

    statement.setString(1, enteredName);
    statement.setBytes(2, enteredPasswordHash);
    ResultSet results = statement.executeQuery();
    if (!results.next()) {
        throw new MyAppInvalidLoginException("No matching login found.");
    }

    String name = results.getString(1);
    String email = results.getString(2);
    String phone = results.getString(3);
}

I’m not a security expert, so I will leave it to people with expertise in that area to comment on whether SHA-256 is sufficiently secure for general needs.

VGR
  • 40,506
  • 4
  • 48
  • 63
  • ***For the paranoid:*** To have no lingering password in the server's JVM memory, you can afterwards do `Array.fill(passwordHash, (byte)0);` and likewise use `char[]` for the password and the corresponding statement setters. – Joop Eggen Jan 13 '22 at 13:14