Description
Role-based access control is implemented inconsistently across routes. While most routes check session['role'] before processing, the approach varies:
- Some routes use a helper-like pattern inline
- There are gaps where a user could potentially access another role's routes by guessing or manipulating URLs
- There is no centralized middleware or decorator for access control
Current Approach
# Inconsistent - different patterns used across routes
# Pattern 1: Inline check at start
if 'userid' not in session or session['role'] != 'teacher':
return redirect(url_for('login'))
# Pattern 2: Redirect to role-specific dashboard
if session['role'] == 'admin':
return redirect(url_for('admin_dashboard'))
# Pattern 3: No explicit check (relying on session presence)
Potential Gaps
- Routes like
export_quizzes check for admin but redirect behavior could be exploited
- Some teacher routes may not properly validate that the teacher owns the resource (e.g., a teacher could potentially view another teacher's quiz data via direct IDs)
- The
view_responses and list_responses routes serve both teachers and students but may not properly scope data
Recommended Enhancement
-
Create a centralized access control decorator:
from functools import wraps
def login_required(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'userid' not in session:
flash('Please log in first.', 'warning')
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
def role_required(*roles):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'userid' not in session:
return redirect(url_for('login'))
if session['role'] not in roles:
flash('You do not have permission to access this page.', 'danger')
return redirect(url_for('login'))
return f(*args, **kwargs)
return decorated_function
return decorator
-
Apply decorators to routes:
@app.route('/teacher_dashboard')
@login_required
@role_required('teacher')
def teacher_dashboard():
...
-
Add resource ownership validation:
# Verify teacher owns the quiz before allowing modifications
cur.execute("SELECT createdby FROM quizzes WHERE quizid = %s", (quiz_id,))
if cur.fetchone()[0] != session['userid']:
flash('You do not have permission to modify this quiz.', 'danger')
return redirect(url_for('teacher_dashboard'))
Description
Role-based access control is implemented inconsistently across routes. While most routes check
session['role']before processing, the approach varies:Current Approach
Potential Gaps
export_quizzescheck for admin but redirect behavior could be exploitedview_responsesandlist_responsesroutes serve both teachers and students but may not properly scope dataRecommended Enhancement
Create a centralized access control decorator:
Apply decorators to routes:
Add resource ownership validation: