SSJX.CO.UK
Browser Games | Cybiko | Amiga | Applications | Windows Games | Python | Guides | Site Map

Secure Programming - User Input

This guide will give you tips and ideas on how to make your programs more secure. The focus of this guide will be validating user input to prevent unexpected and unwanted program behaviour.

Whenever your program gets input from the user, there is a potential security risk. User input can be anything from a name typed into a form to a search query passed to a web page.

Either intentionally or unintentially, incorrect input can cause your program to crash or in a worse case allow the user to see or do something they should not be able to. There is a lot of overlap in the following but these are the problems we will be looking to solve:

Invalid data

This can include something as simple as getting some text instead of a number.

$age="twenty"
$born_in_year=2018-int($age);

Buffer Overflows

Basically you set aside some space (buffer) but what you put in there is too big and overwrites the space next to it. This can cause program crashes or major problems such as priviledged access to sensitive data.

void main()
{
	char pass[5];
	char usertext[]="letmein";
	
	// usertext is longer than pass can hold so may overwrite other variables
	strcpy(pass,usertext);	
}

Path Traversal / Code Injection

This is more common with websites that take a filename as an input. By the site getting invalid input, it may lead to the user getting access to areas they should not be able too or even inserting malicious code into your site.

How the page should work, passing an image filename:
http://www.mysite.com/showpic.php?pic=pic1.jpg

How the page could be compromised, trying to jump to an admin area:
http://www.mysite.com/showpic.php?pic=../admin/useradmin.php

Encoded scripting can sometimes appear like the following:
http://www.mysite.com/showpic.php?pic=#64#65#66#64#65#66#64#65#66#64#65#66#64#65#66#64#65#66

Ideally, folder permissions should block the above from doing any damage but it is always best to stop these attempts as soon as possible.

Potential Solutions

There are a few very simple solutions that can help counter the above problems.

Character Checks

If we know what we data we are expecting, we can check that that is what we get. For example:

It is better to check for characters to allow rather than characters to reject. Checking for characters to reject risks missing a character.

The following example is in C++, the same method can apply to any language.

bool isvalid(const string input)
{
    bool found;
    const string valid="0123456789";
    for(char c:input)
    {
        found=false;
        for (char v:valid)
        {
            if (c==v){found=true;break;}
        }
        if (found==false)
        {
            cout<<input<<" is NOT a number"<<endl;
            return false;
        }
    }
    cout<<input<<" is a number"<<endl;
    return true;
}

int main()
{
    isvalid("0123");	// True
    isvalid("a0123");	// False (letter)
    isvalid("12.3");	// False (dot)
    isvalid("-123");	// False (minus)
}

By changing the valid characters (red line), we can change what is allowed:

// Lowercase text only
const string valid="abcdefghijklmnopqrstuvwxyz"; 

// Numbers, brackets and a space. 
// Note that this would allow "(00) (11) (22)" which is still not a valid telephone number!
const string valid="0123456789() ";

Many languages may have dedicated functions for checking the contents of a string, it is usually better to use these as they should be much quicker. PHP has a uesful one - 'cdigit_type', this checks that the string passed only contains numbers.

The following lines are in PHP

$user_input="1234";
ctype_digit($user_input);	// Will return true

$user_input="-1234";
ctype_digit($user_input);	// Will return false (minus sign)

$user_input="abc";
ctype_digit($user_input);	// Will return false (letters)

$user_input="12.34";
ctype_digit($user_input);	// Will return false (dot)

// Better version of the example at the start
$age="twenty";
if (ctype_digit($age)==true)
{
	$born_in_year=2018-int($age);
}
else
{
	// Invalid user input so fail gracefully.
}

Length Checks

The path traversal example shown above is a very simple example, sometimes you will find attempts to pass entire programs via the url with the aim of having these run by your server or by users going to your site.

The above character check will catch these attempts but it may be comparatively slow on very long strings. Before we run a character check, the simplest method to filter out a lot of these is a basic length check! If you get a name passed to your program and it is over 200 characters long, there is a good chance it is an attempt to break your program.

Getting the length of a string is usually very simple in any language. The PHP version is:

$user_input="..\..\..\..\admin.php";
if (strlen($user_input)<10)
{
	// Now we do a character check to make sure it really is okay, aborting if it is not.
}
else
{
	// Invalid user input so fail gracefully.
}

At a lower level, a length check can prevent buffer overflows by checking if your source fits into your destination.

void main()
{
	char pass[5];
	char usertext[]="letmein";	// 7 letters + Null so is 8 characters long
	
	// usertext is longer than pass can hold so this will return false
	if (sizeof(usertext)<=sizeof(pass))
	{
		strcpy(pass,usertext);
	}	
	else
	{
		// Does not fit so fail gracefully.	
	}
}

Summary

Doing these simple checks will reduce the chance of your program failing due to invalid data. This will make your program more secure, less likely to crash and help improve the overall user experience. So the condensed version of this page would be:

Last updated 12/08/2018

Play-Asia.com - Buy Games & Codes for PS4, PS3, Xbox 360, Xbox One, Wii U and PC / Mac.
Support this site : Visit Play-Asia for games and accessories for new and classic games consoles!