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.
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.
Related
Here is a method authenticate the user password. It verify the user email and password from the database.
public long authenticate(String email, String encodePassword) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try (
Connection conn = DriverManager.getConnection("jdbc:connection", "adminusername","password");/* a) Database User Profile: root is who the user is b) Database user password */
Statement stmt = conn.createStatement();
) /* execute mysql queries */ {
String query = "Select id from User where email = '" + email + "' and password = '" + encodePassword + "'";
System.out.println("query: " + query);
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
// if the user id is there get it
return rs.getLong("id");
}
} catch (SQLException e) {
e.printStackTrace();
}
// if the user id not there return -1 (authority failed)
return -1;
}
To determine whether my lecture is right that I have hard-coded SQL queries values in my code
Your lecturer is trying to warn you about SQL injection.
SQL injection is a web security vulnerability that allows an attacker to interfere with the queries that an application makes to its database. It generally allows an attacker to view data that they are not normally able to retrieve. This might include data belonging to other users, or any other data that the application itself is able to access. In many cases, an attacker can modify or delete this data, causing persistent changes to the application's content or behavior.
The corresponding part in your code is the following
String query = "Select id from User where email = '" + email + "' and password = '" + encodePassword + "'";
If the query returns the id of a user, then the login is successful. Otherwise, it is rejected.
Here, an attacker can log in as any user without a password simply by using the SQL comment sequence -- to remove the password check from the WHERE clause of the query. For example, submitting the email some#email'-- and a blank password results in the following query:
SELECT id FROM users WHERE email = 'some#email'--' AND password = ''
This query returns the user whose email is some#email and successfully logs the attacker in as that user without checking the password.
I'm practicing programming using Java and MySQL using NetBeans IDE. I can log-in my application using the code below. But if I will encrypt my password using the aes_encrypt feature of MySQL, I don't know how to decrypt it. I know there is aes_decrypt but I had a hard time with the syntax.
private void btnLoginActionPerformed(java.awt.event.ActionEvent evt) {
if(lblUsername.getText().length()==0) // Checking for empty field
JOptionPane.showMessageDialog(null, "Empty fields detected ! Please fill up all fields");
else if(password.getPassword().length==0) // Checking for empty field
JOptionPane.showMessageDialog(null, "Empty fields detected ! Please fill up all fields");
else{
String user = lblUsername.getText(); // Collecting the input
char[] pass = password.getPassword();
String pwd = String.copyValueOf(pass); // converting from array to string
if(validate_login(user,pwd)){
JOptionPane.showMessageDialog(null, "Correct Login Credentials");
MainStudentRecord mainstudentrecord = new MainStudentRecord();
mainstudentrecord.setVisible(true);
this.dispose();
}
else{
JOptionPane.showMessageDialog(null, "Incorrect Login Credentials");
lblUsername.setText("");
password.setText("");
}
}
}
private boolean validate_login(String username,String password) {
try{
Class.forName("com.mysql.jdbc.Driver"); // MySQL database connection
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/studentrecord","neil","basabe");
PreparedStatement pst = conn.prepareStatement("Select * from user where username=? and password=?");
pst.setString(1, username);
pst.setString(2, password);
ResultSet rs = pst.executeQuery();
if(rs.next())
return true;
else
return false;
}
catch(Exception e){
e.printStackTrace();
return false;
}
}
Here is my table definition:
username varchar(16)
password varchar(16)
to:
username varchar(16)
password blob --------- this is for me to use aes_encrypt
I know this is the part that I should edit:
PreparedStatement pst = conn.prepareStatement("Select * from user where username=? and password=?");
to:
PreparedStatement pst = conn.prepareStatement("Select * from user where username=? and password=_______this is the confusing part_________");
Please help!
There are multiple issues here. I'll address the one that you have identified first:
You have transformed the password in some way to store it in the database. Perform the same transformation on it to determine if it is stored there rather than trying to reverse the transformation on the data you have stored.
The transformation you have used is a reversible encryption. You should store your passwords non-reversible hash (and salt) of the (salted) password. It is a good idea for this to be a computationally expensive operation, considering both time and space. Using something like scrypt to generate the password hashes helps to meet that requirement.
How to store passwords is a topic that I won't go in to any further. However, if it is possible not to store password data at all and use a third party (think all of those websites that allow you to log in with google/facebook/twitter/etc ... just like this one does), do that, they're much more likely than you to get secure password storage correct.
i've been trying to make this piece of code work work for a while now but seems like it wont. My User inputs Username and Password and then the program compares it to the DB. However it displays Invalid Credentials even though when i output the password it displays the exact same i've input.Just a few points, i know some of you are going to point on things like Using a seperate class for Connection, Check against username for password instead of using Select *, use hashings and all. But right now at the moment i just need to get this code work. Only after that i will be able to work on other aspects to ENHANCE its efficiency. Thank you all in advance.:)
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
Username1 = "jTextField1.getText()";
Password1 = "jPassword1Field2.geText()";
try
{
Class.forName("com.mysql.jdbc.Driver").newInstance();
String url = "jdbc:mysql://localhost:3306/";
String dbName = "VideoSystem" ;
String userName = "root";
String passWord = "**mypassword**";
Connection conn = DriverManager.getConnection(url+dbName, userName, passWord);
Statement st = conn.createStatement();
String sql = ("SELECT * FROM Identification");
ResultSet rs = st.executeQuery(sql);
while(rs.next())
{
password = rs.getString("Password");
if( Password1.equals(password))
{
MenuSelection obj1 = new MenuSelection();
obj1.setVisible(true);
}
else
{
JOptionPane.showMessageDialog(null, "Invalid Credentials", "System Message", JOptionPane.INFORMATION_MESSAGE);
}
}
conn.close();
}
catch (Exception e)
{
System.err.println("Got an exception! ");
System.err.println(e.getMessage());
}
}
Those two lines:
Username1 = "jTextField1.getText()";
Password1 = "jPassword1Field2.geText()";
They are string literals, so unless your password is literally jPassword1Field2.geText(), there's not gonna be a match. I think you meant:
Username1 = jTextField1.getText();
Password1 = jPassword1Field2.getText();
Note however, that JPasswordField.getText() is deprecated since Java 2. You should use getPassword() instead:
Password1 = new String(jPassword1Field2.getPassword());
The documentation justifies the deprecation of getText() with "security reasons" that I can't claim to understand, but you still shouldn't use deprecated parts of the API.
And I know you some of the below already and none of that is part of your question, but I really suggest that you
Check against the username. It should be obvious why.
Hash passwords. Always.
Only fetch what you need, mostly for performance reasons. Usually the best way is to use a WHERE clause in SQL (that brings the need to sanitize your input, but you should do that anyway) and building a list of columns instead of fetching *.
Use backticks for database/table/column names in SQL to avoid things like accidentally using a keyword as table/column name or so.
Applying the above, I suggest the following query (assuming the name field is called Username):
PreparedStatement st = conn.prepareStatement("SELECT `Password` FROM `Identification` WHERE `Username` = ?");
st.setString(1, Username1);
ResultSet rs = st.executeQuery();
How do I validate a certain email and password while an user logs in?
protected void doPost(HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException {
String email=request.getParameter("email");
String pass=request.getParameter("pass");
OutputStream out = res.getOutputStream();
try{
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:8080/college", "root", "root");
Statement st=con.createStatement();
String strSQL = "SELECT email,password FROM student";
How do I continue after the SELECT statement? I would prefer using the if...else statement to do the validation.
First close all connection resources properly - use a Java 7 try-with-resources.
Here is an simple example:
final String email = request.getParameter("email");
final String pass = request.getParameter("pass");
try (final Connection con = DriverManager.getConnection("jdbc:mysql://localhost:8080/student", "root", "root");
final PreparedStatement statement = con.prepareStatement("SELECT COUNT(*) AS count FROM student WHERE email=? AND password=?");) {
statement.setString(1, email);
statement.setString(2, pass);
try (final ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
final int rows = resultSet.getInt("count");
if (rows > 1) {
throw new IllegalStateException("More than one row returned!");
}
boolean validUser = rows == 1;
}
}
}
But really you should hash passwords in the database. Use something like jBcrypt. Your code would then look like:
final String email = request.getParameter("email");
final String pass = request.getParameter("pass");
try (final Connection con = DriverManager.getConnection("jdbc:mysql://localhost:8080/student", "root", "root");
final PreparedStatement statement = con.prepareStatement("SELECT pass FROM student WHERE email=?");) {
statement.setString(1, email);
statement.setString(2, pass);
try (final ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
final String hash = resultSet.getString("pass");
final boolean valid = BCrypt.checkpw(pass, hash);
}
}
}
Obviously you need to add error checking if there are no rows returned from the query. You also need to check that only one row is returned. But I leave that as an exercise.
you can use if, if you like. Use the input as your where statement and then check to see if there is a match, error or null, then execute whatever you want it to do.
You can use email and password in the SQL statement itself. like:
SELECT email, password from student where email = ? and password = ?
prepare above statement and bind the parameters.
This way validation will be done on the DB and you just need to check the result count (which has to be 1). You should have index on email column to have better SQL performance.
Do you relay need to fetch all students?
PreparedStatement st = con.prepareStatement("SELECT count(*) FROM student WHERE email=? AND password=?");
st.setString(1, email);
st.setString(2, pass);
ResultSet rs = st.executeQuery();
rs.next();
int count = rs.getInt(1);
if (count == 1) {
// password and email are correct
}
For this answer, I'll assume that by "validate email and password", what you mean is you want to authenticate the user based on their email address and a password. And not that you want to check whether the email address is a real email address.
So, the first thing you need to do is encrypt the passwords in your database, using a hash algorithm and a random salt. You record the salt alongside the hashed password.
Next thing is, when the user logs in, you look up the salt for that user, and you perform the same hash with the salt. Then you compare the result of that with the previously saved password hash, and if they're the same, then the passwords were the same.
It's important that the salt be random and different for every user.
Plenty of reading to be found on the above terms on the Internets.
Once you've done that, you should also apply the very sensible suggestions in other answers to only select the user you want, and handle your resources correctly.
WARNING I am not an expert on security, and neither are you. If you're implementing a log-in system for an exercise, fine. If it's for the real world, use something that's been written by someone who knows what they're doing.
I need to perform a task for a webpage application, that is to have a page to display the client's information by querying for them
via the client's session id (or some other method) and do a mySQL query into my membership database.
The sequence should be as follows:
1. client logs in
2. compare of client's password and membership database, if match, client will be able to access some pages
3. one of these accessible pages(mentioned in 2)in will contain a link which will then query for the client's information in membership database
4. queried rows(results) will be displayed in the webpage with proper css
just a disclaimer, I am a total beginner at java
Membership database
table's name = member
id | first name | last name | address | telephone number
I have already created and setup a jdbc connection to database:
public void init () throws ServletException {
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/membership","root","");
stmt = conn.createStatement();
} catch (ClassNotFoundException ex) { // for Class.forName()
ex.printStackTrace();
} catch (SQLException ex) { // for getConnection()
ex.printStackTrace();
}
}
String query = "SELECT * FROM member WHERE xxx ";
ResultSet rset = stmt.executeQuery(query);
my question is: how do i grab the necessary rows for my problem here? and how should i approach to solve this question?
many thanks for your advice
"my question is: how do i grab the necessary rows for my problem here?"
Use your ResultSet object (rset). Then retrieve any columns you need.
Something similar to this:
while (rs.next()) {
int ID = rs.getInt("id");
String fName = rs.getString("first_name");
String lName = rs.getString("last_name");
String address = rs.getString("address");
String phone = rs.getString("telephone_number");
}
First, I strongly recommend you have no spaces in your column names (eg use '_' instead).
What are your user credentials for logging in? I imagine it's username or email_address as well as password. Whatever the first part of that is (eg username) you could use that as the primary key on your member table. So after they've logged in, you already have username and that forms the 'where' clause in your SQL query. (If they log in with email_address, everything works the same, using that in place of username.)
So the steps are
Take username + password from user
Select count of rows matching that pair
If count == 1 then they're authenticated, otherwise reject
Select other fields matching username
Display to user
Don't store passwords plaintext, so whatever transform you apply for storing them, also apply that to the given password before doing #2. If you choose to have username not be a primary key, ensure you make it at least 'unique' via a constraint.