Why client side validation is not a good idea or: how i managed to save about 20 hours of studying
Table of contents
Hi, it's me again, this story begins one month ago: My automation teacher assigned me a quiz, made of 20 hours of lessons. I didn't have enough time to do that, since in these days i had to deal with the insane amount of tests and homeworks, and that takes time, so i ended up procrastinating until i realized that the deadline was close by 11 days
How i did?
After receiving the credentials, i logged up the website
and took the first questions
then, i inspected the html to see what's happening behind the scenes
every checkbox is composed by a value and calls a javascript function called "next()" so i digged up a bit to see what this function does
var tot_test = 0; //inizializate this variable that keeps track of the total score
function next(nr) //declaration of next function that accepts a string as input
{
if(document.getElementById('d'+nr+'-a').checked == true){ //get the checkbox with class 'd'+input value+a
tot_test += parseInt(document.getElementById('d'+nr+'-a').value); // get the value of this element and parse that value as integer if that value is "1" the variable is incremented else no
}
if(document.getElementById('d'+nr+'-b').checked == true){
tot_test += parseInt(document.getElementById('d'+nr+'-b').value);
}
if(document.getElementById('d'+nr+'-c').checked == true){
tot_test += parseInt(document.getElementById('d'+nr+'-c').value);
}
if(document.getElementById('d'+nr+'-d').checked == true){
tot_test += parseInt(document.getElementById('d'+nr+'-d').value);
}
//-----------------------------------------------
soglia_min = parseInt('8'); // here is the max amount of right answer i have to do in order to pass the test
nmax = parseInt('10'); // here is the number of questions
//-----------------------------------------------
for(i=1; i<=nmax; i++){
document.getElementById('d'+i).style.display = 'none';
if(document.getElementById('d-audio'+i)){
document.getElementById('d-audio'+i).pause();
}
}
nr_succ = parseInt(nr) + 1;
if(nr_succ == nmax+1)
{
if(tot_test == nmax || (soglia_min > 0 && tot_test >= soglia_min)){ // if i have 8 or more correct answers
document.getElementById('loader').style.display='block';
document.getElementById('form-s').submit(); // send the form to the backend
}else{
if(soglia_min > 0){
alert('Hai risposto correttamente solo a '+tot_test+' domande su '+nmax+'.\nPer proseguire devi rispondere correttamente ad almeno '+soglia_min+' domande. Riprova');
}else{
alert('Hai risposto correttamente solo a '+tot_test+' domande su '+nmax+'.\nPer proseguire devi rispondere correttamente a tutte le domande. Riprova'); // otherwise output the error message
}
tot_test = 0;
for(i=1; i<=nmax; i++){
document.getElementById('d'+i+'-a').checked = false;
document.getElementById('d'+i+'-b').checked = false;
document.getElementById('d'+i+'-c').checked = false;
document.getElementById('d'+i+'-d').checked = false; //reset the selections
}
document.getElementById('d1').style.display = 'block';
document.getElementById('d'+nmax).style.display = 'none'; // takes me back to the main screen
}
}
else
{
document.getElementById('d'+nr_succ).style.display = 'block'; //show me the correct answers
}
}
After that we know how this function works, we realize that would be pointless to override this function in order to accept less answers because the backend will reject the entire form so how we can do?
Wrong validation
We discovered that all the answers are in the same page hidden, so we can inspect the html page to determine what is the good answer if the value is equal to zero, the answer is not correct otherwise it is.
So i ended up creating a simple tool that iterates over all the forms element seeking all the input that are value="1", returning the text inside
<?php
function getValuesInsidePTags($html) {
$dom = new DOMDocument();
$dom->loadHTML($html);
$occurrences = array();
$inputElements = $dom->getElementsByTagName('input');
foreach ($inputElements as $input) {
$value = $input->getAttribute('value');
if ($value === '1') {
$pTag = $input->parentNode;
if ($pTag->nodeName === 'p') {
$occurrences[] = $pTag->nodeValue;
}
}
}
return $occurrences;
}
Conclusions
When you are making a quiz website avoid this approach, use server side validation instead. A backend dev is more expensive but at least you don't get fucked by a 16 y.o guy
Subscribe to my newsletter
Read articles from Neverquest directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by