Understanding how to defend against SQL injection is as important as knowing how to exploit it. This final lesson covers comprehensive defense strategies to protect applications from SQL injection attacks.
Having explored the full spectrum of SQL injection techniques, we now focus on implementing robust defenses that prevent these vulnerabilities from existing in the first place.
Parameterized queries are the most effective defense against SQL injection. They separate the query structure from the data, preventing user input from altering the query's meaning.
# Vulnerable code
query = "SELECT * FROM users WHERE id = " + user_input
cursor.execute(query)
# Secure code with parameterized query
query = "SELECT * FROM users WHERE id = %s"
cursor.execute(query, (user_input,))prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
?>Stored procedures can provide another layer of defense when implemented correctly. However, they must use parameters internally to be effective.
-- Secure stored procedure
CREATE PROCEDURE GetUserById
@UserId INT
AS
BEGIN
SELECT * FROM users WHERE id = @UserId
END
-- Call from application
EXEC GetUserById @UserId = ?⚠️ Stored procedures are only secure if they don't use dynamic SQL with string concatenation. A stored procedure that builds queries dynamically is still vulnerable.
While not a complete solution, input validation provides defense in depth. Validate type, length, format, and range of all user input.
import re
def validate_user_id(user_id):
# Type validation
if not isinstance(user_id, int):
try:
user_id = int(user_id)
except ValueError:
raise ValueError("User ID must be numeric")
# Range validation
if user_id < 1 or user_id > 999999:
raise ValueError("User ID out of valid range")
return user_id
def validate_username(username):
# Format validation
if not re.match(r'^[a-zA-Z0-9_]{3,20}$', username):
raise ValueError("Invalid username format")
return usernameDatabase accounts used by applications should have minimal permissions. This limits the impact if SQL injection is successful.
-- Create application-specific user with limited permissions
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong_password';
-- Grant only necessary permissions
GRANT SELECT, INSERT, UPDATE ON app_db.* TO 'app_user'@'localhost';
-- Explicitly deny dangerous permissions
-- No DROP, no FILE, no SUPER, no GRANT OPTION
-- For read-only operations, use a separate user
CREATE USER 'app_readonly'@'localhost' IDENTIFIED BY 'another_password';
GRANT SELECT ON app_db.* TO 'app_readonly'@'localhost';When parameterized queries aren't possible, use database-specific escaping functions. ORM frameworks can also help prevent SQL injection.
# Using SQLAlchemy ORM (Python)
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('mysql://user:pass@localhost/db')
Session = sessionmaker(bind=engine)
session = Session()
# ORM query - automatically parameterized
user = session.query(User).filter(User.id == user_input).first()
# Using Django ORM
from myapp.models import User
# Safe - Django parameterizes automatically
user = User.objects.get(id=user_input)
# Raw queries - must use params
User.objects.raw('SELECT * FROM users WHERE id = %s', [user_input])💡 Modern frameworks like Django, Rails, and Laravel use parameterized queries by default. Always use the framework's query methods instead of raw SQL when possible.
Implement multiple layers of defense to protect against SQL injection even if one layer fails.
Regularly test your applications to ensure defenses are working. Use both automated tools and manual testing.
# Automated scanning with sqlmap
sqlmap -u 'http://yoursite.com/page.php?id=1(opens in new tab)' --batch --level=3
# Manual testing checklist
# [ ] Test all input points with basic payloads
# [ ] Verify parameterized queries are used
# [ ] Check database permissions
# [ ] Review error handling
# [ ] Test with encoded payloads
# [ ] Verify WAF rules are activeVerify exercises to earn ★ 180 XP and unlock next lab level.