Firewall/WAF with PHP: Whitelist and blacklist with IP addresses for PHP scripts

Firewall/WAF with PHP: Whitelist and blacklist with IP addresses for PHP scripts

Today I would like to publish a short article with some examples how a firewall/WAF can be implemented with PHP.

I have created 4 examples including a whitelist, a blacklist, a blacklist with a text file as IP blocklist and an example for the implementation of a mini-WAF.

All code examples are designed to be inserted in the upper part of already existing scripts.

PHP Whitelist

The allowed IP addresses are in the array $waf – which of course can be extended.

If the IP address is not in the list, access is denied and the message “Blocked 1” is displayed, otherwise the script continues to run as planned. In this example “Hello World 1” will be output.

// PHPWAF START - WHITELIST EXAMPLE
$waf = array(
    '127.0.0.1',
    '1.1.1.1',);
$rip = isset($_SERVER['REMOTE_ADDR']) ? trim($_SERVER['REMOTE_ADDR']) : '';
echo $rip; //echo the IP for testing
if ((($key = array_search($rip, $waf)) == false)) {
    echo 'Blocked 1';
    exit();
}

echo 'Hello World 1'
// PHPWAF END - WHITELIST EXAMPLE

PHP Blacklist

In the next example, we reverse the process and the IPs in the $waf array become a blacklist. However, this can be error-prone – if Cloudflare is used, for example – which is why we ask for the will “CF_CONNECTING_IP” and “X_FORWARDED_FOR” in addition to the normally determined IP address and match them with our blacklist. This increases the hit rate significantly.

// PHPWAF START - BLACKLIST EXAMPLE
$waf = array(
    '0.0.0.0',
    '1.1.1.1',
  
);
$rip = ''; $cip = ''; $xip = '';
$rip = isset($_SERVER['REMOTE_ADDR']) ? trim($_SERVER['REMOTE_ADDR']) : '';
$cip = isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? trim($_SERVER['HTTP_CF_CONNECTING_IP']) : ''; //rec: dont use for whitelist
$xip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? trim($_SERVER['HTTP_X_FORWARDED_FOR']) : ''; //rec: dont use for whitelist
//echo $rip.$cip.$xip; //echo the IPs for testing
if ((($key = array_search($rip, $waf)) == true) || (($key = array_search($cip, $waf)) == true) || (($key = array_search($xip, $waf)) == true)) {
    echo 'Blocked 2';
    exit();
}

echo 'Hello World 2';
// PHPWAF END - BLACKLIST EXAMPLE

PHP blacklist with a blocklist

This example follows the blacklist example above. However, no array is used for the blacklist, but a text file with the name “blacklist.txt”. The IP addresses can be entered there line by line.

// PHPWAF START - BLACKLIST EXAMPLE WITH FILE
$waf = file('blacklist.txt', FILE_IGNORE_NEW_LINES);
$rip = ''; $cip = ''; $xip = '';
$rip = isset($_SERVER['REMOTE_ADDR']) ? trim($_SERVER['REMOTE_ADDR']) : '';
$cip = isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? trim($_SERVER['HTTP_CF_CONNECTING_IP']) : ''; //rec: dont use for whitelist
$xip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? trim($_SERVER['HTTP_X_FORWARDED_FOR']) : ''; //rec: dont use for whitelist
//echo $rip.$cip.$xip; //echo the IPs for testing
if ((($key = array_search($rip, $waf)) == true) || (($key = array_search($cip, $waf)) == true) || (($key = array_search($xip, $waf)) == true)) {
    echo 'Blocked 3';
    exit();
}

echo 'Hello World 3';
// PHPWAF END - BLACKLIST EXAMPLE WITH FILE

mini-WAF with PHP

This is just an example of an extremely simplified version of a WAF. In this example all values – which are passed to the PHP script via POST or GET – are searched for certain strings to prevent e.g. cross-site scripting and simple SQL injections. Of course, this is by no means sufficient or complete.

//PHPWAF - INPUT CHECKS START

$postdata = file_get_contents("php://input");
if($postdata) {
if ((strstr($postdata, 'exec '))||(strstr($postdata, 'SELECT *'))||(strstr($postdata, 'select *'))||(strstr($postdata, 'UNION SELECT'))||(strstr($postdata, 'union select'))||(strstr($postdata, 'EXEC '))||(strstr($postdata, '<script>'))||(strstr($postdata, '<SCRIPT>'))||(strstr($postdata, '<?php'))||(strstr($postdata, '<?'))||(strstr($postdata, '?>'))||(strstr($postdata, 'UNION DELETE'))||(strstr($postdata, 'union delete'))||(strstr($postdata, 'UNION UPDATE'))||(strstr($postdata, 'union update'))||(strstr($postdata, 'UNION TRUNCATE'))||(strstr($postdata, 'union truncate')))) { //str_contains for php8
    echo "blocked 4";
	exit;
}
}
$postdata = $_GET;
$postdata = implode(" ", $postdata);

if($postdata) {
if ((strstr($postdata, 'exec '))||(strstr($postdata, 'SELECT *'))||(strstr($postdata, 'select *'))||(strstr($postdata, 'UNION SELECT'))||(strstr($postdata, 'union select'))||(strstr($postdata, 'EXEC '))||(strstr($postdata, '<script>'))||(strstr($postdata, '<SCRIPT>'))||(strstr($postdata, '<?php'))||(strstr($postdata, '<?'))||(strstr($postdata, '?>'))||(strstr($postdata, 'UNION DELETE'))||(strstr($postdata, 'union delete'))||(strstr($postdata, 'UNION UPDATE'))||(strstr($postdata, 'union update'))||(strstr($postdata, 'UNION TRUNCATE'))||(strstr($postdata, 'union truncate')))) { //str_contains for php8
    echo "blocked 4";
	exit;
}
}
echo 'Hello World 4';
echo file_get_contents("php://input");

//PHPWAF - INPUT CHECKS END

Leave a Reply

Your email address will not be published. Required fields are marked *