Welcome Guest, Not a member yet? Register   Sign In
Anti spam honey pot
#1

(This post was last modified: 06-20-2017, 05:01 AM by Martin7483.)

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 Smile

- 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]) > // 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
Reply
#2

Sorry what exactly is a honey pot?
Practical guide to IgnitedCMS - Book coming soon, www.ignitedcms.com
Reply
#3

(10-01-2015, 10:52 AM)iamthwee Wrote: Sorry what exactly is a honey pot?

A honey pot is an invisible form field that is required to be empty when the form is posted.
As bots fill in all available fields the form will be invalid and thus the posting of the form is made harder for bots.
Reply
#4

Hey Martin,

thanks for sharing the codes.
I'm wonder you never mentioned about calling the helper anywhere. i didn't find any line of the code to call the helper as well !

Also im eager to know how am i able to test this functionality?

Please advice me.
Thanks
Reply
#5

This solution seems bloated. If you really want to have a so called "honeypot field" in your form, all you have to do is add it, then in your form validation add a callback that checks it for any value. If the value is there then die(), redirect(), log_something(), whatever();
Reply
#6

(This post was last modified: 12-19-2015, 11:28 PM by Martin7483.)

(12-19-2015, 10:06 PM)skunkbad Wrote: This solution seems bloated. If you really want to have a so called "honeypot field" in your form, all you have to do is add it, then in your form validation add a callback that checks it for any value. If the value is there then die(), redirect(), log_something(), whatever();

Then you would always need to add it manually and remember too use a callback or custom rule. My approach enables this with a simple true / false setting just like csrf protection. Field is auto added and validated so no chance you would forget a step. If you think this is bloated you probebly think the csrf approach is bloated?
Reply
#7

I like your approach, thanks for sharing.

@ardavan there is no need to make an extra call to the helper. It override the default form helper found in CodeIgniter. Normaly when you use the helper function form_open() CodeIgniter generates an opening html form tag and add some hidden fields to it containing the CSRF values. This addon also adds a honeypot field to it.
Reply
#8

Interesting stuff. But why does it need a unique token? Am I wrong or is the same token used for all visitors?
CodeIgniter 4 tutorials (EN/FR) - https://includebeer.com
/*** NO support in private message - Use the forum! ***/
Reply
#9

(12-20-2015, 04:25 PM)includebeer Wrote: Interesting stuff. But why does it need a unique token? Am I wrong or is the same token used for all visitors?

First, you don't need a unique token. It is just an extra level of protection. If the form is recorded and a bot figures out that it should remain empty, it will fail because the recorded field is then invalid

Second, I missed that this way of generating and storing the token wouldn't work. So I have changed it so it now also uses a cookie just like CSRF uses a cookie. I have updaqted the original post with the new code.
Reply
#10

Hey @Martin7483,

i copy and paste your honey pot code to my project.
Now How can i test whether its working on my project or not?

Thanks in advance
Reply




Theme © iAndrew 2016 - Forum software by © MyBB