diff options
| author | Michael Save <savetheinternet@tinyboard.org> | 2012-04-12 17:20:49 +1000 |
|---|---|---|
| committer | Michael Save <savetheinternet@tinyboard.org> | 2012-04-12 17:20:49 +1000 |
| commit | dd0f421015059247464efd5f6d2735c5ee08a400 (patch) | |
| tree | f308a18e31d974ba71dba90df0b0be5d8fbb7302 /inc/anti-bot.php | |
| parent | 96ffd9eb3b9515dc68eb685f8cf4fa263f63cd4b (diff) | |
better anti-bot check
Diffstat (limited to 'inc/anti-bot.php')
| -rw-r--r-- | inc/anti-bot.php | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/inc/anti-bot.php b/inc/anti-bot.php new file mode 100644 index 00000000..e8c26113 --- /dev/null +++ b/inc/anti-bot.php @@ -0,0 +1,236 @@ +<?php + +/* + * Copyright (c) 2010-2012 Tinyboard Development Group + */ + +if(realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { + // You cannot request this file directly. + exit; +} + +$hidden_inputs_twig = array(); + +class AntiBot { + public $inputs = array(), $index = 0; + private $salt; + + public static function randomString($length, $uppercase = false, $special_chars = false) { + $chars = 'abcdefghijklmnopqrstuvwxyz0123456789'; + if($uppercase) + $chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + if($special_chars) + $chars .= ' ~!@#$%^&*()_+,./;\'[]\\{}|:"<>?=-` '; + + $chars = str_split($chars); + + $ch = array(); + + // fill up $ch until we reach $length + while(count($ch) < $length) { + $n = $length - count($ch); + $keys = array_rand($chars, $n > count($chars) ? count($chars) : $n); + if($n == 1) { + $ch[] = $chars[$keys]; + break; + } + shuffle($keys); + foreach($keys as $key) + $ch[] = $chars[$key]; + } + + $chars = $ch; + + return implode('', $chars); + } + + public static function make_confusing($string) { + $chars = str_split($string); + + foreach($chars as &$c) { + if(rand(0, 2) != 0) + continue; + $c = mb_encode_numericentity($c, array(0, 0xffff, 0, 0xffff), 'UTF-8'); + } + + return implode('', $chars); + } + + public function __construct(array $salt = array()) { + global $config; + + if(!empty($salt)) { + // create a salted hash of the "extra salt" + $this->salt = implode(':', $salt); + } else { + $this->salt = ''; + } + + shuffle($config['spam']['hidden_input_names']); + + $input_count = rand($config['spam']['hidden_inputs_min'], $config['spam']['hidden_inputs_max']); + $hidden_input_names_x = 0; + + for($x = 0; $x < $input_count ; $x++) { + if($hidden_input_names_x === false || rand(0, 2) == 0) { + // Use an obscure name + $name = $this->randomString(rand(10, 40)); + } else { + // Use a pre-defined confusing name + $name = $config['spam']['hidden_input_names'][$hidden_input_names_x++]; + if($hidden_input_names_x >= count($config['spam']['hidden_input_names'])) + $hidden_input_names_x = false; + } + + if(rand(0, 2) == 0) { + // Value must be null + $this->inputs[$name] = ''; + } elseif(rand(0, 4) == 0) { + // Numeric value + $this->inputs[$name] = (string)rand(0, 100); + } else { + // Obscure value + $this->inputs[$name] = $this->randomString(rand(5, 100)); + } + } + } + + public function html($count = false) { + $elements = array( + '<input type="hidden" name="%name%" value="%value%">', + '<input type="hidden" value="%value%" name="%name%">', + '<input style="display:none" type="text" name="%name%" value="%value%">', + '<input style="display:none" type="text" value="%value%" name="%name%">', + '<span style="display:none"><input type="text" name="%name%" value="%value%"></span>', + '<div style="display:none"><input type="text" name="%name%" value="%value%"></div>', + '<div style="display:none"><input type="text" name="%name%" value="%value%"></div>', + '<textarea style="display:none" name="%name%">%value%</textarea>', + '<textarea name="%name%" style="display:none">%value%</textarea>' + ); + + $html = ''; + + if($count == 0) { + // all elements + $inputs = array_slice($this->inputs, $this->index); + } else { + $inputs = array_slice($this->inputs, $this->index, $count); + } + $this->index += count($inputs); + + foreach($inputs as $name => $value) { + $element = false; + while(!$element) { + $element = $elements[array_rand($elements)]; + if(strpos($element, 'textarea') !== false && $value == '') { + // There have been some issues with mobile web browsers and empty <textarea>'s. + $element = false; + } + } + + $element = str_replace('%name%', utf8tohtml($name), $element); + + if(rand(0, 2) == 0) + $value = $this->make_confusing($value); + else + $value = utf8tohtml($value); + + $element = str_replace('%value%', $value, $element); + + $html .= $element; + } + + return $html; + } + + public function hash() { + global $config; + + // This is the tricky part: create a hash to validate it after + // First, sort the keys in alphabetical order (A-Z) + $inputs = $this->inputs; + ksort($inputs); + + $hash = ''; + // Iterate through each input + foreach($inputs as $name => $value) { + $hash .= $name . '=' . $value; + } + // Add a salt to the hash + $hash .= $config['cookies']['salt']; + + // Use SHA1 for the hash + return sha1($hash . $this->salt); + } +};; + + +function hiddenInputs(array $salt, $print_the_rest = false) { + global $hidden_inputs_twig; + + $salt_str = implode(':', $salt); + + if(!isset($hidden_inputs_twig[$salt_str])) + $hidden_inputs_twig[$salt_str] = new AntiBot($salt); + + if($print_the_rest) + return $hidden_inputs_twig[$salt_str]->html(0); + else + return $hidden_inputs_twig[$salt_str]->html(rand(1, 5)); +} + +function hiddenInputsHash(array $salt) { + global $hidden_inputs_twig; + + $salt_str = implode(':', $salt); + + if(!isset($hidden_inputs_twig[$salt_str])) + $hidden_inputs_twig[$salt_str] = new AntiBot($salt); + + return $hidden_inputs_twig[$salt_str]->hash(); +} + +function checkSpam(array $extra_salt = array()) { + global $config; + + if(!isset($_POST['hash'])) + return true; + + $hash = $_POST['hash']; + + if(!empty($extra_salt)) { + // create a salted hash of the "extra salt" + $extra_salt = implode(':', $extra_salt); + } else { + $extra_salt = ''; + } + + // Reconsturct the $inputs array + $inputs = array(); + + foreach($_POST as $name => $value) { + if(in_array($name, $config['spam']['valid_inputs'])) + continue; + + $inputs[$name] = $value; + } + + // Sort the inputs in alphabetical order (A-Z) + ksort($inputs); + + $_hash = ''; + + // Iterate through each input + foreach($inputs as $name => $value) { + $_hash .= $name . '=' . $value; + } + + // Add a salt to the hash + $_hash .= $config['cookies']['salt']; + + // Use SHA1 for the hash + $_hash = sha1($_hash . $extra_salt); + + return $hash != $_hash; +} + |
