diff --git a/README.md b/README.md index 1fa81b4..eb8c737 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,6 @@ The point is to demonstrate common cyber security problems and their fixes. ## Description of vulnerabilities -> **_NOTE:_** More detailed description of problems coming soon. - I am using the 2021 OWASP Top Ten list. LINK: https://github.com/VSinerva/csb-project-1 @@ -46,7 +44,16 @@ If users already exist with weakly hashed passwords, a more complicated migratio FLAW 3: > ADD EXACT SOURCE LINK -SQL Injection (Unsanitized SQL query for search) +(Injection) The application has a classic SQL injection vunlerability in its search function. +This is cause by taking the user input (search text) and placing it directly in the SQL query with a Python f-string. +As an example, the "Search text" shown below will give any user a full listing of all usernames and their hashed passwords. +`' AND 0=1 UNION SELECT date_joined, username || ":" || password as user, id FROM auth_user; --` +Especially with flaws 2 and 4 present, this will quickly lead to a lot of compromised accounts. + +The fix to this issue is to properly escape/sanitize the user input e.g. by escaping control characters. +This is difficult to do perfectly, so best practice is to use a well-known library or something similar for this. +Luckily, Django has existing functionality for doing what we wanted to do, which will fix this issue. +The commented out code implements this fixed version. FLAW 4: diff --git a/notes/views.py b/notes/views.py index 99e537e..19e1904 100644 --- a/notes/views.py +++ b/notes/views.py @@ -5,7 +5,6 @@ from django.contrib.auth.validators import UnicodeUsernameValidator from django.contrib.auth import authenticate, login, logout from django.contrib.auth.password_validation import validate_password from django.shortcuts import render, redirect -from django.views.decorators.csrf import csrf_exempt from django.db import connection from django.core.exceptions import ValidationError @@ -52,9 +51,16 @@ def search(request): user = request.user keyword = request.GET.get('keyword') - notes = Note.objects.filter(owner=user, body__icontains=keyword) - notes_list = [ { 'time' : note.time, 'body' : note.body, 'id' : note.id } for note in notes ] - notes_list.sort(key=lambda note: note['time']) +# FLAW 3: +# Using the commented out version of the code uses Django's built in methods +# This makes sure the inputs are properly sanitized +# notes = Note.objects.filter(owner=user, body__icontains=keyword) +# notes_list = [ { 'time' : note.time, 'body' : note.body, 'id' : note.id } for note in notes ] +# notes_list.sort(key=lambda note: note['time']) + query = f"SELECT time, body, id FROM notes_note WHERE body LIKE '%{keyword}%' ORDER BY time;" + with connection.cursor() as cursor: + notes = cursor.execute(query).fetchall() + notes_list = [ { 'time' : note[0], 'body' : note[1], 'id' : note[2] } for note in notes ] return render(request, 'search.html', { 'notes' : notes_list, 'keyword' : keyword})