0

Teachers have access to a list of their Students classes. On this page (one page per Student) the Teachers can mark a checkbox as completed if the Student completes that class. This is done with ajax. I'm passing the current Students id by making it a value on the checkbox. This is not good as a malicious Teacher could inspect the page and change the Students id in the checkbox element (so they could be on Student 111's page and change the field in the checkbox to 112 and mark that other Students class as complete.

How can I prevent them from doing this? I know I can get current users data in POST or using a token, but the Student whose checkbox is being changed isn't the current user, current user is a Teacher and he is making changes to one of his Students. The url is something like this: /website/teacher/student111/classes/.

def post_form_api(request):
    data = {}

    if request.method == "POST":
        class_id = request.POST.get("class_id")
        student_id = request.POST.get("student_id")

        student_class_data_entry = get_object_or_404(StudentClassData, student_id=student_id, class_id=class_id)

        form = StudentClassDataForm(request.POST, instance=student_class_data_entry)
        
        [.. other logic .]

        if form.is_valid():
            form.save()
            data = {'result' : True}

        if request.is_ajax():
            return JsonResponse(data)
        else:
            return HttpResponseBadRequest()

(value says which of the Students classes has been changed)

<form>
    {% csrf_token %}
    <td class='class_complete' student_id='{{ student.student.id }}' name='completed' value='{{ class.id }}'>{{ item.completed }}</td>
</form>
$(".class_complete").click(function(e){
    var csrfToken = $("input[name='csrfmiddlewaretoken']");
    class_id = $(this).attr('value');
    student_id = $(this).attr('student_id');

    var checked = $('#'+e.target.id).is(":checked");

    $.ajax({ url: "/api/post_form/",
        type: "POST",
        dataType: "json",
        data: {'completed':checked, 'student_id':student_id, 'class_id':class_id, 'csrfmiddlewaretoken':csrfToken.val()},
        cache: false
    }).done(function(data) {
        if (data.result === true){
        }
        else {
        }
    });
});

Thank you.

horse
  • 479
  • 7
  • 25
  • If you actually meant the inspect (ctrl-shift-i) function, [this](https://stackoverflow.com/a/28690644) may help you. – crimsonpython24 Jul 21 '20 at 00:58
  • I appreciate your help, though I will try to find another way to pass the data rather than preventing the user from inspecting the page. Thanks again – horse Jul 21 '20 at 01:29

1 Answers1

0

Lots of ways to do this. One would be to make the form field a hash of a 'secret_key', 'student_name', and 'student_id'. Then it would appear as something opaque, like:

<td class='class_complete' user_hash='wkfjr8fjsf8je8jfkokjl' name='completed' value='1235'>completed</td>

On the backend, you could decrypt the hash and make sure the student_id matched that for the 'student_name'

GAEfan
  • 11,244
  • 2
  • 17
  • 33
  • Thank you. This sounds like what I'm after. I've had a Google and there doesn't seem to be a clear-cut way to do this with Django. It's going to take some research. Before I begin do you mind telling me if I should look into hashing the ```student_id``` in the database, or hashing it in my views.py and comparing it to my unhashed DB ```student_id```. Thank you. – horse Jul 21 '20 at 01:51
  • 1
    You can just hash it in the view. It's not so sensitive (like a password) where it should be encrypted in the db. – GAEfan Jul 21 '20 at 02:02