This repository is a personal project created to explore SQL security practices using PostgreSQL and Flask. It is not a tutorial or production-ready application, but rather a learning artifact documenting experiments with SQL injection, secure query patterns, and database hardening.
The goal of this lab is to gain hands-on experience with:
- Understanding SQL injection vulnerabilities and exploitation
- Implementing secure query patterns using parameterized SQL
- Using PostgreSQL role-based access control
- Enabling Row-Level Security (RLS) for tenant isolation
- Monitoring PostgreSQL using
pg_stat_statements - Enforcing SSL and SCRAM-SHA-256 authentication
- Applying least-privilege principles
sql_security_lab/
├── app/
│ ├── config.py # Database configuration and environment loading
│ ├── db.py # Secure and insecure DB connection helpers
│ ├── seed.py # Initializes schema and seeds data
│
├── database/
│ ├── roles.sql # Defines database roles and permissions
│ ├── schema.sql # Defines the application schema
│ ├── seed_data.sql # Inserts sample user data
│
├── scripts/
│ ├── start_postgres.sh # Script to start PostgreSQL service
│ ├── init_db.sh # Wrapper for running SQL setup scripts
│
├── vulnerable_app.py # Insecure Flask app (vulnerable to SQLi)
├── secure_app.py # Secure Flask app (parameterized queries & RLS)
├── requirements.txt # Python dependencies
├── .env # Environment file for DB credentials
└── README.md # Project documentation
This project is separated into four phases:
- Create a basic Flask app that connects to PostgreSQL
- Implement a login form vulnerable to SQL injection
- Insert sample users into the database
- Use
vulnerable_app.pyto demonstrate an injection attack (e.g.' OR TRUE --)
- Create distinct roles:
app_user,app_reader,admin - Use least-privilege access controls
- Remove superuser privileges from
app_user - Revoke default privileges
- Configure SCRAM-SHA-256 authentication and enforce SSL
- Implement
secure_app.pyusing parameterized queries - Use proper role and SSL context in DB connection
- Enable basic user isolation with a
tenant_idfield - Optionally apply Row-Level Security (RLS)
- Enable
pg_stat_statementsinpostgresql.conf - Query execution stats to monitor access patterns
- Review tracked queries from
secure_app.pyandvulnerable_app.py
Screenshots for each phase can be found in /screenshots:
phase1_injection_demo.pngphase2_roles_permissions.pngphase2_ssl_config.pngphase3_secure_app_login.pngphase4_pg_stat_activity.png
- Linux Mint or Ubuntu VM
- PostgreSQL (tested with version 14+)
- Python 3 and virtualenv
Install dependencies using:
pip install -r requirements.txt- Flask
- psycopg2-binary
- python-dotenv
git clone https://github.com/yourname/sql_security_lab.git
cd sql_security_lab
python3 -m venv venv
source venv/bin/activate
sudo -u postgres psql -f database/roles.sql
sudo -u postgres psql -f database/schema.sql
sudo -u postgres psql -f database/seed_data.sql
python vulnerable_app.py
[ OR ]
python secure_app.py
- Unsafe query construction opens the door for SQL injection
- Parameterized queries mitigate injection entirely
- Least privilege roles help minimize damage from compromised web apps
- PostgreSQL Row-Level Security enables powerful tenant isolation
- Monitoring with
pg_stat_statementssupports both security and optimization
This project is licensed under the MIT License. See the LICENSE file for details.
- This is an educational project; do not deploy in production
- All testing was performed on an isolated VM
- Feel free to fork or modify for your own learning