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.
Related
I have a registration page where customers sign up and make an account. The account details are stored in an Apache derby database. There is an option for customers with existing accounts to log in to the webpage, how can I cross check that they have an account before allowing access to the site?
Below is the code I used to store the details in the dB. I am unsure how I can validate the users and have found nothing helpful online. Thanks in advance.
//using get parameter to get values from index.jsp
String fn=request.getParameter("firstname");
String ln=request.getParameter("lastname");
String ad=request.getParameter("address");
String em=request.getParameter("email");
String ph=request.getParameter("phone");
String ps=request.getParameter("password");
String conps=request.getParameter("confirmpass");
//connecting to dB
Connection conn=DriverManager.getConnection("jdbc:derby://localhost:1527/login","reg","reg");
Statement st=conn.createStatement();
//inserting values into dB
int i=st.executeUpdate("insert into login values('"+fn+"','"+ln+"','"+ad+"','"+em+"','"+ph+"','"+ps+"','"+conps+"')");
This code snippet can be used to check data is present in table, based on identifier like email -
String em=request.getParameter("email");
// Create a PreparedStatement object 1
PreparedStatement pstmt = con.prepareStatement(
"SELECT count(*) FROM login WHERE email=?");
pstmt.setString(1,em); // Assign value to input parameter 2
ResultSet rs = pstmt.executeQuery();
rs.next(); //Moving the cursor to the last row 3
System.out.println("Email id "+ em + " is present in table for " + rs.getInt("count(*)")+" times");
public int addUsers(int USER_ID,String FIRST_NAME,String LAST_NAME,String PASSWORD,String USERNAME,String USER_PERMISSION) throws SQLException {
Connection conn = null;
conn = getConnectivity(conn) ;
getConnectivity(conn);
String sqlSelect = "SELECT * from USER_DETAILS";
PreparedStatement pres = conn.prepareStatement(sqlSelect);
ResultSet rs1 = pres.executeQuery();
if(rs1.next()){
String Username = rs1.getString(5);
System.out.println("username found "+Username);
System.out.println("username input " + USERNAME);
System.out.println("password input " + PASSWORD);
if (Username.equals(USERNAME)){
System.out.println("Username already exists");
conn.close();
}
else{
System.out.println("FOUND ELSE");
String sql = "INSERT INTO USER_DETAILS VALUES (?,?,?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, USER_ID);
ps.setString(2, FIRST_NAME);
ps.setString(3,LAST_NAME);
ps.setString(4,PASSWORD);
ps.setString(5,USERNAME);
ps.setString(6,USER_PERMISSION);
int result = ps.executeUpdate();
System.out.println(result);
}
}
conn.close();
return USER_ID;
}
and for login I am using
public boolean login(String USERNAME, String PASSWORD) throws SQLException
{
boolean result = false;
Connection conn = null;
conn = getConnectivity(conn) ;
String sqlSelect = "SELECT * from USER_DETAILS";
PreparedStatement pres = conn.prepareStatement(sqlSelect);
ResultSet rs1 = pres.executeQuery();
if(rs1.next()){
String Username = rs1.getString(5);
String Password = rs1.getString(4);
String UserPermission = rs1.getString(6);
System.out.println("username found "+Username);
System.out.println("username input " + USERNAME);
System.out.println("password input " + PASSWORD);
if (Username.equalsIgnoreCase(USERNAME) && Password.equalsIgnoreCase(PASSWORD) && UserPermission.equalsIgnoreCase("blocked")){
System.out.println("User Logged in");
conn.close();
}
System.out.println("gets out of the code");
}
conn.close();
return result;
}
first of all it is allowing to enter more than one entry, so duplicates occurring regardless of my if statement, and when i add fresh new data and try to see I can log in, it still compares with previously added data and does not work. Can someone see what am i doing wrong here. please thanks
below is the system print out i get ,
Connection Valid
username found kamran (don't know why he is still picking up this column)
username input macbook (these i have already in my database)
password input hello (these i have already in my database)
gets out of the code
Connection Valid
Connection Valid
username found kamran (don't know why he is still picking up this column)
username input macho (these i have already in my database)
password input hello (these i have already in my database)
FOUND ELSE (dont know why it adds data when they already exist in database)
1
Your code doesn't make sense: you are querying for all users and only checking the first returned user if it matches. Of course that is going to fail if the first returned user doesn't match: in addUsers you will try to add the user if the first user returned doesn't match, in login a user can only login if it is the first user.
You need to use a WHERE clause to only request the user you want to check:
// Note: this assumes a case insensitive collation
String sqlSelect = "SELECT * from USER_DETAILS WHERE username = ?";
try (PreparedStatement pres = conn.prepareStatement(sqlSelect)) {
pres.setString(1, USERNAME);
try (ResultSet rs1 = pres.executeQuery()) {
if (!rs1.next) {
// user doesn't exist yet, create...
}
}
}
You need to do something similar for login (but then with if (rs1.next()) instead).
There are more problems with your current code: you are storing plaintext passwords: you should really hash them with a strong password hash like PBKDF2. Also please follow the java naming conventions. Variables and parameters are camelcase so not USERNAME but username (or userName), not UserPermission, but userPermission. This improves the readability for people who are used to the java naming conventions.
This is a code that i'm creating helping users to log in into my application a method login that gets two arguments username and password.
I want to be specified with my error messages to the user, so:
if the email does not exist in the table it shows "email is not registered"
if the email exists and the password is incorrect is shows " incorrect password"
Is my code efficient? I need your opinion. What do I need to improve\change?
Here's the method
private String command;
private ResultSet resultSet;
private PreparedStatement statement;
private Connection connection;
String jdbcUrl = "jdbc:mysql://localhost:3306/registered";
String jdbcUser = "...";
String jdbcPassword = "...";
public boolean login(String eml, String pwd) {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(jdbcUrl, jdbcUser,
jdbcPassword);
command = "SELECT Email FROM users WHERE Email LIKE '" + eml + "';";
statement = connection.prepareStatement(command);
resultSet = statement.executeQuery();
if (!resultSet.isBeforeFirst()) {
System.out.println("Email (" + eml + ") is not registered ! ");
// show error message
} else {
command = "SELECT Email,Password FROM users WHERE Email LIKE '"
+ eml + "' AND Password LIKE '" + pwd + "';";
statement = connection.prepareStatement(command);
resultSet = statement.executeQuery();
if (!resultSet.isBeforeFirst()) {
System.out.println("Password for Email (" + eml
+ ") is incorrect ! ");
// show error message
}
else {
System.out.println("Logged in!");
}
}
} catch (SQLException e) {
System.out.println("SQLException: " + e.getMessage());
System.out.println("Vendor error: " + e.getErrorCode());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return false;
}
Is my code efficient?
No, it is not. The main problem in the performance of this method is that you open the connection manually here:
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(jdbcUrl, jdbcUser, jdbcPassword);
This is a bottleneck because you will open a physical connection to the database and close it, and this is a high-cost operation. This should be replaced for a database connection pool and retrieve the connection from there. Some options to implement a database connection pool:
BoneCP
c3po
Apache Commons DBCP
More info:
Java Connection Pooling
Should a database connection stay open all the time or only be opened when needed?
What do I need to improve\change?
Apart of the way you obtain the connection, the current code is prone to SQL Injection because you concatenate the string to generate the SQL statement:
command = "SELECT Email FROM users WHERE Email LIKE '" + eml + "';";
Use PreparedStatement accordingly and set parameters:
command = "SELECT Email FROM users WHERE Email = ?";
statement = connection.prepareStatement(command);
statement.setString(1, eml);
resultSet = statement.executeQuery();
Not really a problem with your code but with your design. The password of the users should be encrypted and validated on database only. Looks like you're storing the password as plain text, which is a valid option for learning purposes, but not to use in real world applications.
let us say i'm having a table(login) that has usernames(unique key) and passwords, used for login purposes.
Now, in the registration module(that creates a new account by adding a new row in login table),is it okay if i just execute the insert and check if the username is already in the table when the SQLException() raises???. is it a good practice???
Here's an example of registration module:
enter code here
String uname = request.getParameter("username");
String passwd = request.getParameter("password");
try
{
statement.executeUpdate("insert into login(username,password) values (" + uname + "," + passwd + ")");
}
catch(SQLException e)
{
if((e.getErrorCode())==1) //error code when primary key violated
{
// username already exists....
}
//some other code
}
//username is available....rest of the code goes here
in the firs place i thought of a select query to check if the username (user has entered while registering) is already in the table....but it seemed redundant to me
because i thought, even doing so wouldnt prevent the DBMS to check the uniqueness violation, right????
Thanks in advance.
What I would recommend is do a validation before insert, in case you change underlying database which change the error code in SQLException.getErrorCode(). This also enable you do validation before user submit the form. You can create a custom exception the notify your service caller that username is already in use.
Retrieves the vendor-specific exception code for this SQLException
object.
SELECT COUNT(*) FROM LOGIN WHERE USERNAME = :username
via a service method, for example:
public class UserService {
public boolean isValidUsername(String username) {
//validate
}
public void registerUser(User user) throws UsernameInUseException {
if(!isValidUsername(user.getUsername()) {
throw new UsernameInUseException("Usernaame " + user.getUsername() + " is already in use.");
}
// continue
}
}
It will be cool if you could tell the user before form submission that username already exists using AJAX calls.
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.