This project is a simple Node.js, Express, and MySQL application built to demonstrate two major security flaws and, more importantly, how to fix them.
It provides a hands-on comparison of a dangerously vulnerable login system versus a modern, secure one.
This app features three routes to illustrate key security concepts:
-
/register(Flawed but functional):- Securely validates input (e.g., password length).
- Securely hashes the password using
bcrypt. - 🚨 Major Flaw: It also saves the plain text password in a
password_clearcolumn, completely defeating the purpose of hashing.
-
/login(Extremely Vulnerable):- 🚨 Flaw 1 (SQL Injection): This route builds its query by concatenating strings, making it vulnerable to a classic
' OR 1 = 1 #SQL injection attack. - 🚨 Flaw 2 (Plain Text): It works by checking against the
password_clearcolumn, demonstrating an insecure authentication method.
- 🚨 Flaw 1 (SQL Injection): This route builds its query by concatenating strings, making it vulnerable to a classic
-
/login-secure(The Correct Way):- ✅ Secure (Parameterized Queries): This route uses prepared statements (
?placeholders), which makes SQL injection impossible. - ✅ Secure (Hashing): It only reads the
bcrypthash and uses thebcrypt.compare()function to safely verify the user's password.
- ✅ Secure (Parameterized Queries): This route uses prepared statements (
- Node.js
- MySQL (Workbench or server)
- Clone the repository:
git clone https://github.com/antoineburet/sql-injection-prevention-demo.git cd sql-injection-prevention-demo - Install dependencies:
npm install
- Set up the database:
- Open MySQL Workbench and connect to your server.
- Create a database named
accounts. - Create the
credentialstable using the following SQL. (This schema is intentionally insecure.)USE accounts; CREATE TABLE credentials ( id INT NOT NULL AUTO_INCREMENT, user VARCHAR(45) NOT NULL, password VARCHAR(255) NOT NULL, -- For the bcrypt hash password_clear VARCHAR(45) NULL, -- INTENTIONALLY INSECURE COLUMN PRIMARY KEY (id), UNIQUE INDEX user_UNIQUE (user ASC) );
- Create your environment file:
- Create a file named
.envin the root of the project. - Add your database credentials:
DB_HOST=localhost DB_USER=root DB_PASSWORD=your_mysql_password DB_NAME=accounts
- Create a file named
node server.jsThe server will be running on http://localhost:3000.
-
Create an Account:
- Use the "Create Account" form. (e.g.,
user: admin,pass: password123) - Observe: The
credentialstable now contains both abcrypthash and the plain text "password123".
- Use the "Create Account" form. (e.g.,
-
Test the Vulnerable Login:
- Test 1 (Normal Login): Use
user: admin,pass: password123. It will work because it reads the plain text column. - Test 2 (SQL Injection): Use
user: ' OR 1 = 1 #,pass: (anything). It will work and log you in as the first user in the database.
- Test 1 (Normal Login): Use
-
Test the Secure Login:
- Test 1 (Normal Login): Use
user: admin,pass: password123. It will work because it correctly usesbcrypt.compare(). - Test 2 (SQL Injection): Use
user: ' OR 1 = 1 #,pass: (anything). It will FAIL (as it should). The parameterized query treats the entire string as a username, and no user exists with that literal name.
- Test 1 (Normal Login): Use