Question

I need to restrict POST request from specific domain. As far I know, HTTP_REFERER checking cannot be a good solution because it can be spoofed. So what can be the good solution when two different websites from different technology and web servers will work together?

Was it helpful?

Solution

Heres a method you could try, by adding a hidden field within your form that is session values that are set server side. This way if the form has not originated from your server the session would not have been set and the values would not match.

Example:

<?php 
session_start();

if($_SERVER['REQUEST_METHOD']=='POST'){
    if(isset($_SESSION['security']) && 
       isset($_SESSION['security_key']) && 
       !empty($_POST[$_SESSION['security_key']]) && 
       $_POST[$_SESSION['security_key']] == $_SESSION['security'])
    {
        /* forms post is from domain as session would 
           not have been started and security would not have been set */
        echo 'good';
    }else{
        /* forms post is not from domain */
        echo 'bad';
    }
    $_SESSION['security_key'] = sha1(microtime(true)+1);
    $_SESSION['security'] = sha1(microtime(true));
}else{
    $_SESSION['security_key'] = sha1(microtime(true)+1);
    $_SESSION['security'] = sha1(microtime(true));
}
?>

<form method="POST" action="">
  <input type="hidden" name="<?=$_SESSION['security_key'];?>" value="<?=$_SESSION['security'];?>"/>
  <p><input type="text" name="Text" size="20"><input type="submit" value="Submit"></p>
</form>

Alternatively you could use encryption instead of hashing, that way you could check the values:

<?php 
session_start();
define('SECURE_KEY',$_SERVER['SERVER_NAME']);

if($_SERVER['REQUEST_METHOD']=='POST'){
    if(isset($_SESSION['security_key']) && isset($_SESSION['security'])){
        //Decrypt
        list($servername,$userip) = explode('X',decrypt(base64_decode($_SESSION['security'])));

        //Check the decrypted values
        if($servername == $_SERVER['SERVER_NAME'] && $userip == $_SERVER['REMOTE_ADDR']){
            /* forms post is from domain as session would
            not have been started and security would not have been set */
            echo 'good';
        }else{
            echo 'bad';
        }

    }else{
        /* forms post is not from domain */
        echo 'bad';
    }

    $_SESSION['security_key'] = sha1(microtime(true));
    $_SESSION['security'] = base64_encode(encrypt($_SERVER['SERVER_NAME'].'X'.$_SERVER['REMOTE_ADDR']));
}else{
    $_SESSION['security_key'] = sha1(microtime(true));
    $_SESSION['security'] = base64_encode(encrypt($_SERVER['SERVER_NAME'].'X'.$_SERVER['REMOTE_ADDR']));
}

function encrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') {
    // hash
    $key = hash('sha256', $key);
    // create iv - encrypt method AES-256-CBC expects 16 bytes
    $iv = substr(hash('sha256', $secret), 0, 16);
    // encrypt
    $output = openssl_encrypt($string, $method, $key, 0, $iv);
    // encode
    return base64_encode($output);
}

function decrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') {
    // hash
    $key = hash('sha256', $key);
    // create iv - encrypt method AES-256-CBC expects 16 bytes
    $iv = substr(hash('sha256', $secret), 0, 16);
    // decode
    $string = base64_decode($string);
    // decrypt
    return openssl_decrypt($string, $method, $key, 0, $iv);
}
?>

<form method="POST" action="">
  <input type="hidden" name="<?=$_SESSION['security_key'];?>" value="<?=$_SESSION['security'];?>"/>
  <p><input type="text" name="Text" size="20"><input type="submit" value="Submit"></p>
</form>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top