Hi,
I was searching on Google and in the CI forum but I could not find any recent topics on the use of a honey pot.
So I added it. If anyone is interested here are the steps and code required.
Any feedback is welcome
- Martin
Step 1: Edit config.php
Edit your application config.php file, located at
./application/config.php. Add the following lines to it
PHP Code:
/*
|--------------------------------------------------------------------------
| ANTI SPAM HONEY POT
|--------------------------------------------------------------------------
| Enables the use of a invisible honey pot field.
|
| 'spam_protection' = TRUE => Use honey pot, FALSE => don't use honey pot
| 'spam_protection_name' = The name of the honey pot cookie
| 'honey_pot_expire' = The maximum time the token is valid for
*/
$config['spam_protection'] = TRUE;
$config['spam_protection_name'] = 'ci_honey_pot';
$config['honey_pot_expire'] = 3600;
Step 2: Create MY_Input.php
Create
MY_Input.php in your
./application/core directory and place the following code in it:
PHP Code:
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* My Input
*
* Extends CodeIgniters core Input with a honey pot anti-spam protection
* Added config items for use.
*
* @author Martin Langenberg
*/
class MY_Input extends CI_Input {
/**
* Enable Honey pot flag
*
* Enables a honey pot token name to be set.
* Set automatically based on config setting.
*
* @var bool
*/
protected $_enable_honey_pot = FALSE;
public function __construct() {
log_message('debug', "Class ".get_class($this)." Initialized.");
parent::__construct();
$this->_enable_honey_pot = (config_item('spam_protection') === TRUE);
$this->_resanitize_globals();
}
// --------------------------------------------------------------------
/**
* Resanitize Globals
*
* Internal method serving for the following purposes:
*
* - Sets the honey pot and validates on POST request
*
* @return void
*/
protected function _resanitize_globals()
{
// Honey pot protection check
if ($this->_enable_honey_pot === TRUE && ! is_cli())
{
$this->security->honey_pot_verify();
}
log_message('debug', 'Honey pot set and verified');
}
// --------------------------------------------------------------------
}
Step 3: Create MY_Security.php
Create
MY_Security.php in your
./application/core directory and place the following code in it:
PHP Code:
<?php if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* My Security
*
* Extends CodeIgniters core Security with a honey pot anti-spam protection
*
* @author Martin Langenberg
*/
class MY_Security extends CI_Security {
protected $_honey_pot_name; // The honey pot cookie name
protected $_honey_pot_token_name; // The hashed honey pot field name
protected $_honey_pot_expire; // The time the token remains valid for. Default is 1 hour
public function __construct() {
log_message('debug', "Class ".get_class($this)." Initialized.");
parent::__construct();
$this->_honey_pot_name = config_item('spam_protection_name');
$this->_honey_pot_expire = config_item('honey_pot_expire');
}
// --------------------------------------------------------------------
/**
* Honey pot Verify
*
* @return MY_Security
*/
public function honey_pot_verify()
{
// If it's not a POST request, set the honey pot and return
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') {
return $this->_spam_protection_set_honey_pot();
}
// It's a post, get the stored token name to use with the available $_POST data
$this->_honey_pot_token_name = $_COOKIE[$this->_honey_pot_name];
// Do the tokens exist in the _POST
if ( ! isset( $_POST[$this->_honey_pot_token_name] )
OR strlen($_POST[$this->_honey_pot_token_name]) > 0 ) // Is the honey pot empty?
{
// Log a clear error, but don't print clear honey pot errors to screen
log_message('error', 'The honey pot was invalid OR not empty!');
$this->csrf_show_error();
}
// We kill this since we're done and we don't want to polute the _POST array
unset($_POST[$this->_honey_pot_token_name]);
// Nothing should last forever
unset($_COOKIE[$this->_honey_pot_name]);
$this->_honey_pot_token_name = NULL;
$this->_spam_protection_set_honey_pot();
log_message('info', 'Honey pot verified');
return $this;
}
// --------------------------------------------------------------------
/**
* Set Honey pot name and value
*
* @return string
*/
protected function _spam_protection_set_honey_pot() {
if ($this->_honey_pot_token_name === NULL) {
// If the cookie exists we will use its value.
// We don't necessarily want to regenerate it with
// each page load since a page could contain embedded
// sub-pages causing this feature to fail
if (isset($_COOKIE[$this->_honey_pot_name]) && is_string($_COOKIE[$this->_honey_pot_name])
&& preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->_honey_pot_name]) === 1)
{
return $this->_honey_pot_token_name = $_COOKIE[$this->_honey_pot_name];
}
$rand = $this->get_random_bytes(16);
$this->_honey_pot_token_name = ($rand === FALSE)
? md5(uniqid(mt_rand(), TRUE))
: bin2hex($rand);
}
$this->honey_pot_set_cookie();
return $this->_honey_pot_token_name;
}
// --------------------------------------------------------------------
/**
* Honey pot Set Cookie
*
* @return CI_Security
*/
public function honey_pot_set_cookie() {
$expire = time() + $this->_honey_pot_expire;
$secure_cookie = (bool) config_item('cookie_secure');
setcookie(
$this->_honey_pot_name,
$this->_honey_pot_token_name,
$expire,
config_item('cookie_path'),
config_item('cookie_domain'),
$secure_cookie,
config_item('cookie_httponly')
);
log_message('info', 'Honey Pot cookie sent');
return $this;
}
// --------------------------------------------------------------------
/**
* return the set honey pot token name
* @return string
*/
public function get_honey_pot_token_name() {
return $this->_honey_pot_token_name;
}
// --------------------------------------------------------------------
}
Step 4: Create MY_form_helper.php
Create
MY_form_helper.php in your
./application/helpers directory and place the following code in it:
PHP Code:
<?php
/**
* Crossfire CMS
*
* @package Crossfire CMS
* @author Martin Langenberg
* @copyright Copyright (c) 2011 - 2015, Martin Langenberg
* @since Version 2.0
* @filesource
*/
/**
*
* This class replaces the CodeIgniter form_helper method form_open().
* It adds the use of a invisible honey pot field if required by the config.
* The hidden and invisible fields are wrapped in a invisible container.
*/
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CodeIgniter Form Helpers
*
* @package CodeIgniter
* @subpackage Helpers
* @category Helpers
* @author EllisLab Dev Team
* @link http://codeigniter.com/user_guide/helpers/form_helper.html
*/
// ------------------------------------------------------------------------
if ( ! function_exists('form_open'))
{
/**
* Form Declaration
*
* Creates the opening portion of the form.
*
* @param string the URI segments of the form destination
* @param array a key/value pair of attributes
* @param array a key/value pair hidden data
* @return string
*/
function form_open($action = '', $attributes = array(), $hidden = array())
{
$CI =& get_instance();
// If no action is provided then set to the current url
if ( ! $action)
{
$action = $CI->config->site_url($CI->uri->uri_string());
}
// If an action is not a full URL then turn it into one
elseif (strpos($action, '://') === FALSE)
{
$action = $CI->config->site_url($action);
}
$attributes = _attributes_to_string($attributes);
if (stripos($attributes, 'method=') === FALSE)
{
$attributes .= ' method="post"';
}
if (stripos($attributes, 'accept-charset=') === FALSE)
{
$attributes .= ' accept-charset="'.strtolower(config_item('charset')).'"';
}
$form = '<form action="'.$action.'"'.$attributes.">\n";
// Add CSRF field if enabled, but leave it out for GET requests and requests to external websites
if ($CI->config->item('csrf_protection') === TRUE && strpos($action, $CI->config->base_url()) !== FALSE && ! stripos($form, 'method="get"'))
{
$hidden[$CI->security->get_csrf_token_name()] = $CI->security->get_csrf_hash();
}
// Add honey pot field if enabled, but leave it out for GET requests and requests to external websites
if ($CI->config->item('spam_protection') === TRUE && strpos($action, $CI->config->base_url()) !== FALSE && ! stripos($form, 'method="get"'))
{
$hidden[$CI->security->get_honey_pot_token_name()] = NULL;
}
// Make all hidden fields invisible
$form .= '<div class="hidden" style="display: none;">';
if (is_array($hidden))
{
foreach ($hidden as $name => $value)
{
$form .= '<input type="hidden" name="'.$name.'" value="'.html_escape($value).'" style="display:none;" />'."\n";
}
}
$form .= '</div>';
return $form;
}
}
And that is that. You can now have a honey pot field automatically added to a form