This application has no session management whatsoever, demonstrating one of the most critical security flaws possible in a web application.
Overview
Session management is the process of securely handling multiple requests to a web application from the same user. Proper session management is critical for maintaining user authentication state and protecting user data.
The Normo Unsecure PWA demonstrates what happens when an application has zero session management - every page load is treated as a new, unauthenticated request.
Critical Session Management Flaws
No Session Tracking
The application does not implement any session tracking mechanism:
@app.route ( "/" , methods = [ "POST" ])
def home ():
if request.method == "POST" :
username = request.form[ "username" ]
password = request.form[ "password" ]
isLoggedIn = dbHandler.retrieveUsers(username, password)
if isLoggedIn:
dbHandler.listFeedback()
# User is "authenticated" but NO SESSION IS CREATED
return render_template( "/success.html" , value = username, state = isLoggedIn)
else :
return render_template( "/index.html" )
Notice that after successful authentication, the application simply renders a template. There’s no session cookie, no token, no way to remember the user on subsequent requests.
No Logout Functionality
There is no logout endpoint in main.py. Users cannot explicitly end their session because there is no session to end:
# No logout route exists!
# Expected but missing:
# @app.route("/logout")
# def logout():
# session.clear()
# return redirect("/")
No Authentication Required for Protected Pages
The /success.html endpoint accepts GET requests without any authentication:
@app.route ( "/success.html" , methods = [ "POST" , "GET" , "PUT" , "PATCH" , "DELETE" ])
def addFeedback ():
if request.method == "POST" :
feedback = request.form[ "feedback" ]
dbHandler.insertFeedback(feedback)
dbHandler.listFeedback()
return render_template( "/success.html" , state = True , value = "Back" )
else :
# Anyone can GET this page without logging in!
dbHandler.listFeedback()
return render_template( "/success.html" , state = True , value = "Back" )
Common Session Management Vulnerabilities
No Session Tracking
No Session Invalidation
Exposed Session Data
Predictable Session IDs
Missing Session Mechanism Problem: Application doesn’t create or maintain sessions after authentication.Impact:
Users can’t stay logged in
Every request requires re-authentication
No way to track user state across requests
Protected resources are not actually protected
Found in: main.py:46-67Missing Logout Functionality Problem: No logout endpoint exists, and there are no sessions to invalidate.Impact:
Users cannot securely end their session
If sessions existed, they would persist indefinitely
No session timeout mechanism
Shared computers remain “logged in”
Found in: Entire main.py file - no logout routeNo Session Security Controls Problem: Application doesn’t implement any session security measures.Missing protections:
No HttpOnly cookies
No Secure flag for HTTPS
No SameSite protection
No CSRF tokens
No session regeneration after login
Impact: If sessions were implemented without these protections, they would be vulnerable to XSS, session fixation, and CSRF attacks.Session ID Weakness Problem: If this application did use sessions, they would likely be predictable or weak.Attack vectors:
Session ID prediction
Session ID brute forcing
Session fixation
Session hijacking via XSS
Proper approach: Use cryptographically secure random session IDs with high entropy.
Real-World Attack Scenarios
Direct Access to Protected Pages
Because there’s no session management, an attacker can directly navigate to “protected” pages: # No authentication required!
curl http://localhost:5000/success.html
The application will render the page and display all feedback without checking if the user is authenticated.
State Manipulation
Even if a user “logs in”, clicking any link or refreshing the page loses their authentication state: 1. User logs in successfully
2. User clicks a link or refreshes
3. User is no longer "logged in" (no session to maintain state)
4. User must log in again
No Access Control
Without sessions, there’s no way to implement proper access control: # Can't check if user is authenticated
# Can't check user roles or permissions
# Can't track user activity
# Can't implement per-user features
Implementing Secure Session Management
Option 1: Flask-Session (Server-Side)
Flask-Session provides secure, server-side session management:
Installation
Configuration
Login Route
Protected Routes
Logout Route
pip install Flask - Session
Option 2: Flask-Login (User Session Management)
Flask-Login provides user session management with more features:
Session Security Best Practices
1. Session Configuration Checklist
Generate strong session IDs - Use cryptographically secure random values
Set HttpOnly flag - Prevents JavaScript from accessing cookies
Set Secure flag - Ensures cookies only sent over HTTPS
Set SameSite attribute - Protects against CSRF attacks
Implement session timeout - Auto-logout after inactivity
Regenerate session ID - After login to prevent fixation
Clear sessions on logout - Properly invalidate sessions
2. Session Timeout Implementation
from datetime import datetime, timedelta
@app.before_request
def check_session_timeout ():
if 'logged_in' in session:
last_activity = session.get( 'last_activity' )
if last_activity:
last_activity = datetime.fromisoformat(last_activity)
if datetime.now() - last_activity > timedelta( minutes = 30 ):
session.clear()
return redirect(url_for( 'home' , msg = 'Session expired' ))
session[ 'last_activity' ] = datetime.now().isoformat()
3. Concurrent Session Management
import uuid
@app.route ( "/" , methods = [ "POST" ])
def home ():
username = request.form[ "username" ]
password = request.form[ "password" ]
if dbHandler.retrieveUsers(username, password):
# Generate unique session identifier
session_id = str (uuid.uuid4())
# Store in database to track concurrent sessions
dbHandler.create_session(username, session_id)
session[ 'session_id' ] = session_id
session[ 'username' ] = username
return redirect( '/success.html' )
4. Session Monitoring and Logging
import logging
@app.before_request
def log_session_activity ():
if 'logged_in' in session:
logging.info( f "User { session.get( 'username' ) } accessed { request.path } from { request.remote_addr } " )
@app.route ( "/logout" )
def logout ():
username = session.get( 'username' , 'Unknown' )
logging.info( f "User { username } logged out from { request.remote_addr } " )
session.clear()
return redirect( '/' )
Testing Session Management
Test Session Creation
Verify that sessions are created upon login: import requests
session = requests.Session()
response = session.post( 'http://localhost:5000/' ,
data = { 'username' : 'testuser' , 'password' : 'password' })
# Check if session cookie is set
print (session.cookies)
Test Session Persistence
Verify that authenticated state persists across requests: # After login, try accessing protected page
response = session.get( 'http://localhost:5000/success.html' )
assert response.status_code == 200
Test Session Invalidation
Verify that logout properly invalidates sessions: # Logout
session.get( 'http://localhost:5000/logout' )
# Try accessing protected page
response = session.get( 'http://localhost:5000/success.html' )
assert response.status_code == 302 # Redirected to login
Test Session Timeout
Verify that sessions expire after inactivity: import time
# Login
session.post( 'http://localhost:5000/' , data = { 'username' : 'test' , 'password' : 'test' })
# Wait for timeout period
time.sleep( 1800 ) # 30 minutes
# Try accessing protected page
response = session.get( 'http://localhost:5000/success.html' )
assert 'Session expired' in response.text
References