Secure Coding: How to Account for Input Sanitization

On average, a website leverages around 18-20 different plugins in its structure. These plugins enhance the website’s functionality and in some instances extend the applications core capabilities.

It’s great for website owners because they can pick and choose from different plugins and check which ones better fit their personal blog or businesses. On the other hand, the availability of such resources can put your website at risk without you even knowing about it.

In this post I’m going to describe:

  • How good code doesn’t always mean secure code.
  • How to dive into input validation.
  • Recommendations on how to prevent such issues from happening.

During a routine cleanup investigation, we found a WordPress Plugin containing good code while also introducing features that could potentially put a website at risk. To the untrained eye, this would likely go unnoticed. The general rule of thumb in security, and development, is never trust data being inputted into your application.

Here is the sample code I came across:

 <?php
 $lic = $_POST['lic'];
 $act = $_POST['act'];
 $apth = trim(base64_decode($_POST['apath']));
 // create License
 if( $act == 1 ) {
 if ( !file_exists( $apth ) ) {
 $config = "”;

if (($fp = fopen( $apth, “w”))) {
 fputs( $fp, $config, strlen( $config ) );
 fclose( $fp );
 }
 }
 echo ‘successfully’;
 // Remove license
 } else {
 unlink( $apth );
 echo ‘successfully’;
 }
 ?>

This is different than what we come across on the remediation side of the house. There is nothing that would resemble malware nor any encoding technique that attackers use when trying to obfuscate their intent.

When checking the code, we see that it is related to creating and removing a license file, which is a very common practice, used in paid premium plugins to validate their users. In this case, we believe the developers assumed that they would be the only ones to manage this particular file and they also did not expect anyone to take advantage of the lack of input validation.

Input Validation

In secure programming, we should always check the data our application receives regardless of the source.

Input validation is one of the most fundamental steps we take to prevent unexpected behavior. If the data being sent is not valid or it doesn’t match your criteria, your script shouldn’t allow it to go through, nor process it, therefore reducing the risks of unknown consequences.

I particularly like the whitelist strategy where the idea is to check only for a set of known good values, therefore having as much control as possible to everything that reaches your application.

There is also another strategy called blacklist where basically we reject a set of characters or strings. If we don’t expect our variable to receive double-quotes (”) for instance, we go ahead and add that into our known bad code list. The problem with this approach is that attackers have an infinite set of characters they can try to circumvent our security measures, such as: encoding, using different charsets, escaping, and much more.

Demonstration of How To Apply

Using the code above as an example, we have lots of options to turn it into a secure solution. I would start one step before writing the code itself, checking the logic.

  • Who is allowed to write the license file?
  • Do I want to leave those variables in the open?
  • How do I differentiate a paid customer from a non-paid?

With those thoughts in mind, here are a few suggestions.

Using The Web Server To Our Advantage – Controlling File Access Via .htaccess

Even though our code may be vulnerable, we can easily create an .htaccess file to control access to that resource and allow only our range of IP addresses.

E.G.:

<Files my-vulnerable-script.php>
Order Deny,Allow
Deny from All
Allow from MY-COMPANY-IP
</Files>

Controlling Access Via Our Application

Although not the best method, we can specify only a set of IP addresses who can access the resource.

E.G. (1):

<?php
 $remote_addr = $_SERVER[‘REMOTE_ADDR’];
 $valid_ips = array(“my-ip”, “my-company-ip”);

if(!in_array($remote_addr, $valid_ips))
 {
 die();
 }
>// Proceed with your code
 …
 ?>

E.G. (2):

Either $act or $lic variables could have been previously set on the user end, and we also keep a list on the server for comparison, so instead of checking if $act == 1, we check that against our list…

 <?php
 …
 $act = “static_value”; // or $lic = “static_value”;
 $valid_acounts = array fetched from server

if(!in_array($act, $valid_accounts))
 {
 die();
 }
 // Proceed

…
 ?>

Or, whitelisting the user’s input in the $lic variable to allow only alphanumeric characters in that field and avoid escaping from the context we want to:

 <?php
 …
 $_POST[‘lic’] = preg_replace(‘/[^a-zA-Z0-9]/’,”,$_POST[‘lic’]);
 …
 ?>

There are different techniques that can be implemented and it all depends on your environment and your needs. These are some of the things that the developer in this case could have taken, and something we’d recommend all developers consider.

Conclusion & Final Considerations

Input validation is our first line of defense to prevent uncontrolled data to get into our system and we should always plan for it.

A great resource would be to spend some time looking at the Open Web Application Security Project (OWASP) input validation cheat sheet, designed to help you think through the various scenarios.

Using this security measure in addition to other layers of security, such as a Web Application Firewall (WAF) can help us prevent attacks and unauthorized access to our system.

At Sucuri we have a WAF solution that prevents such attacks from reaching your website or its hosting environment.

2 comments
  1. In e.g. 2, you focus on preventing problems with $lic or $act, but if the example code is the entire code we’re considering, the only thing that is actually used in a context that might create a security risk is $apth. Shouldn’t we make sure the input for $apth isn’t a stream:, data: or external URL? And make sure a specific working directory is prepended? Even so, it seems little harm would come of a file with an empty string as its contents ($config), no matter where on the file system or in memory it is placed… The real problem is that this script could allow a user to delete any file from the file system (not just the license) by manipulating $apth.

    1. Yes, you’re absolutely right.
      $apth is a huge risk indeed and it should be either hardcoded or set based on controlled variables.

      There were so many issues that I completely forgot to write about it.

      Thanks for the comment! 🙂

Comments are closed.

You May Also Like