Security Best Practices for Web Apps

Security is one of the most critical aspects of web development. Poor security practices can lead to data breaches, unauthorized access, and cyber attacks. In this tutorial, we’ll cover the best security practices for Flask and Django web applications.


1. Keep Your Dependencies Updated

Using outdated libraries can introduce vulnerabilities. Always keep your dependencies updated:

For Flask:

pip list --outdated
pip install --upgrade <package-name>

For Django:

pip list --outdated
pip install --upgrade django

You can also use pip-audit to check for vulnerabilities:

pip install pip-audit
pip-audit

2. Use Environment Variables for Secrets

Never store API keys, database credentials, or secret keys in code. Instead, use environment variables.

Flask Example:

import os
SECRET_KEY = os.getenv("SECRET_KEY", "default-secret-key")

Set it in your .env file:

SECRET_KEY=mysecurekey123

Django Example:

import os
SECRET_KEY = os.environ.get("SECRET_KEY", "default-secret-key")

Use python-dotenv to load environment variables:

pip install python-dotenv

3. Secure Database Connections

  • Never expose your database credentials in code.
  • Use an ORM (like SQLAlchemy or Django ORM) to prevent SQL injection attacks.
  • Disable remote access to your database unless absolutely necessary.

Django Settings for Secure Database Connections:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.getenv("DB_NAME"),
        'USER': os.getenv("DB_USER"),
        'PASSWORD': os.getenv("DB_PASSWORD"),
        'HOST': os.getenv("DB_HOST"),
        'PORT': '5432',
    }
}

4. Protect Against SQL Injection

SQL injection is one of the most common attacks on web applications.

Bad Example (Vulnerable to SQL Injection):

cursor.execute(f"SELECT * FROM users WHERE username = '{username}'")

Secure Example Using ORM:

User.objects.filter(username=username).first()  # Django ORM
db.session.query(User).filter_by(username=username).first()  # Flask SQLAlchemy

5. Prevent Cross-Site Scripting (XSS)

XSS attacks inject malicious scripts into web pages.

Django Automatically Escapes Input in Templates:

<p>{{ user_input }}</p>  <!-- Secure -->

Flask Uses Jinja2 (which escapes input by default):

<p>{{ user_input }}</p>  <!-- Secure -->

But be careful when using |safe:

<p>{{ user_input | safe }}</p>  <!-- Risky -->

6. Use CSRF Protection

CSRF (Cross-Site Request Forgery) tricks users into submitting unauthorized actions.

In Django (CSRF Protection is Enabled by Default)

Make sure your templates include:

<form method="POST">
    {% csrf_token %}
    <input type="submit" value="Submit">
</form>

In Flask, Use Flask-WTF for CSRF Protection:

pip install flask-wtf

Then, add CSRF protection:

from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)

7. Implement Strong Authentication and Authorization

  • Use secure password hashing (bcrypt, Argon2, PBKDF2).
  • Implement multi-factor authentication (MFA) for sensitive actions.
  • Use Django’s built-in authentication system or Flask extensions like Flask-Login.

Django Password Hashing:

from django.contrib.auth.hashers import make_password
hashed_password = make_password("mypassword")

Flask Password Hashing (Using Werkzeug):

from werkzeug.security import generate_password_hash
hashed_password = generate_password_hash("mypassword")

8. Secure Session Management

  • Use HTTPS-only cookies to prevent session hijacking.
  • Set secure session cookies in Django and Flask.

Django Session Settings:

SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

Flask Secure Sessions:

app.config['SESSION_COOKIE_SECURE'] = True
app.config['REMEMBER_COOKIE_SECURE'] = True

9. Enable HTTPS with SSL/TLS

Always encrypt data in transit with HTTPS.

For Django:

pip install django-sslserver

Enable SECURE_SSL_REDIRECT in settings:

SECURE_SSL_REDIRECT = True

For Flask:

Use Flask-Talisman:

pip install flask-talisman
from flask_talisman import Talisman
Talisman(app)

10. Prevent Clickjacking (X-Frame-Options Header)

Clickjacking tricks users into clicking hidden UI elements.

Django Security Settings:

X_FRAME_OPTIONS = 'DENY'

Flask Security Headers (Using Flask-Talisman):

Talisman(app, frame_options="DENY")

11. Regularly Audit Your Web Application

  • Use security scanners like OWASP ZAP or Burp Suite.
  • Run static code analysis tools (e.g., Bandit for Python).
pip install bandit
bandit -r myproject/
  • Monitor logs and detect suspicious activity.

Conclusion

By implementing these security best practices, you can protect your Flask and Django applications from common vulnerabilities.

  • Keep dependencies updated
  • Secure your database connections
  • Prevent SQL injection & XSS
  • Use CSRF protection
  • Implement strong authentication
  • Secure sessions & enable HTTPS
  • Prevent clickjacking & audit your app