表单加入token,防止机器注入垃圾信息

网页表单如果不加入一些防范措施很容易被别人用程序注入一些垃圾信息,如何防范呢?在表单中加入隐藏的token或许是个选择。

<?php

class Security {

    public $charset = 'UTF-8';

    protected $hash;
    protected $token_name = 'token';

    protected $protection = true;

    public function __construct() {
        
        if ($this->protection) {
            $this->set_hash();// Set hash
        }
    }

    public function verify() {

        if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') {
            return $this->set_session();
        }
        
        if ( ! isset($_POST[$this->token_name]) OR $_POST[$this->token_name] !== $_SESSION[$this->token_name]) {
            return false;
        }
        unset($_POST[$this->token_name]);
        unset($_SESSION[$this->token_name]);
        $this->hash = NULL;

        $this->set_hash();
        $this->set_session();

        return true;
    }

    public function set_session(){

        if (!session_id()) session_start();

        $_SESSION[$this->token_name] = trim($this->hash);
        
        return true;
    }

    public function gethash() {
        return $this->hash;
    }
    public function gettoken_name() {
        return $this->token_name;
    }
    protected function set_hash()    {

        $rand = $this->get_random_bytes(16);
        $this->hash = ($rand === FALSE)
                ? md5(uniqid(mt_rand(), TRUE))
                : bin2hex($rand);
        
        return $this->hash;
    }
    public function get_random_bytes($length) {
        if (empty($length) OR ! ctype_digit((string) $length)) {
            return FALSE;
        }

        if (function_exists('random_bytes')) {
            try {
                return random_bytes((int) $length);
            }catch (Exception $e) {
                return FALSE;
            }
        }
        if (defined('MCRYPT_DEV_URANDOM') && ($output = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)) !== FALSE)
        {
            return $output;
        }

        if (is_readable('/dev/urandom') && ($fp = fopen('/dev/urandom', 'rb')) !== FALSE)
        {
            is_php('5.4') && stream_set_chunk_size($fp, $length);
            $output = fread($fp, $length);
            fclose($fp);
            if ($output !== FALSE)
            {
                return $output;
            }
        }
        if (function_exists('openssl_random_pseudo_bytes'))
        {
            return openssl_random_pseudo_bytes($length);
        }

        return FALSE;
    }
}

客户端每次请求有表单的页面,服务端都会重新生成一个hash。一份保存在网页表单中,另一份保存在服务器后台。客户端提交后后端进行检验,失败则不保存在数据库中。

    <form  action="" method="post" >
            <input type="hidden" name="$token" value="$token_hash">
            <input type="text" name="username" value="">
            <input type="text" name="email" value="">
            <input type="submit" value="立即提交" />
    </form>
//服务端
$security = new Security();
if(!$security->verify()){
      //验证失败             
 }

当然,token值保存在服务端会占用一定的资源。访问量很大的网站,尤为严重,这时就不适宜这种简单的验证方法了。

后台对留言用户的IP进行人工拉黑处理,结合上面的方法使用具有一定适用场景。

posted on 2017-06-29 16:33  D&L  阅读(5110)  评论(0编辑  收藏  举报