Cross-Site Request Forgery (CSRF) applications are a form of malicious exploitation where unauthorized orders are made on behalf of a certified user.

CodeIgniter 4 provides protection from CSRF attacks. However, it is not automatically enabled in the same way as CodeIgniter 3.

The token is made for each user and is managed by CodeIgniter to verify the user's request.

In this tutorial, I will show you how to enable CSRF protection and send the AJAX application and CSRF token to the CodeIgniter 4 project.

Contents

  1. Database configuration
  2. Enable CSRF
  3. Create Table
  4. Model
  5. Route
  6. Controller
  7. View
  8. Run
  9. Conclusion

1. Database configuration

  • Open the .env file found at the root of the project.

NOTE - If a dot (.) Is not added at first then rename the file to .env.

  • Remove # from the beginning of the database.default.hostname, database.default.database, database.default.username, database.default.password, and database.default.DBDriver.
  • Review the suspension and save it.
database.default.hostname = 127.0.0.1
database.default.database = testdb
database.default.username = root
database.default.password = 
database.default.DBDriver = MySQLi


2. Enable CSRF

  • Reopen the .env file.
  • Remove # from the beginning of the app.CSRFProtection, app.CSRFTokenName, app.CSRFCookieName, app.CSRFExpire, and app.CSRFRegenerate.
  • I am updating the app.CSRFTokenName value with 'csrf_hash_name'. With this word read the CSRF hash. You can update it at any other value.
  • If you do not want to renew the CSRF hash after each AJAX application then set the app.CSRFRegenerate = false.
app.CSRFProtection = true
app.CSRFTokenName = 'csrf_hash_name'
app.CSRFCookieName = 'csrf_cookie_name'
app.CSRFExpire = 7200
app.CSRFRegenerate = true
# app.CSRFExcludeURIs = []
  • Open the app/Config/Filters.php file.
  • Disable 'csrf' to 'before' if noted.
// Always applied before every request
public $globals = [
    'before' => [
       //'honeypot'
       'csrf',
    ],
    'after' => [
       'toolbar',
       //'honeypot'
    ],
];


3. Create Table

  • Create a new table users using migration.
php spark migrate:create create_users_table
  • Now, navigate to the app/Database/Migration/ folder from the root of the project.
  • Find the PHP file ending in create_users_table and open it.
  • Describe the structure of the table in an up().
  • Using the down() method, remove the users table that calls for migration adjustment.
<?php namespace AppDatabaseMigrations;

use CodeIgniterDatabaseMigration;

class CreateUsersTable extends Migration
{
    public function up() {
       $this->forge->addField([
          'id' => [
             'type' => 'INT',
             'constraint' => 5,
             'unsigned' => true,
             'auto_increment' => true,
          ],
          'name' => [ 
             'type' => 'VARCHAR',
             'constraint' => '100',
          ],
          'username' => [
             'type' => 'VARCHAR',
             'constraint' => '80',
          ],
          'gender' => [
             'type' => 'VARCHAR',
             'constraint' => '10',
          ],
          'email' => [
             'type' => 'VARCHAR',
             'constraint' => '80',
          ],

       ]);
       $this->forge->addKey('id', true);
       $this->forge->createTable('users');
    }

    //--------------------------------------------------------------------

    public function down() {
       $this->forge->dropTable('users');
    }
}
  • Run the migration –
php spark migrate

4. Model

  • Create a Users.php file in the app/Models/ folder.
  • Open the file.
  • Specify the table name "users" for a variety of $table, key "id" in $primaryKey, Return type "array" to $ReturnType .
  • In $allowedFields Array specify field names - ['name', 'username', 'gender', 'email'] that can be set during installation and renewal.

Completed Code

<?php 
namespace AppModels;

use CodeIgniterModel;

class Users extends Model
{
    protected $table = 'subjects'; 
    protected $primaryKey = 'id';

    protected $returnType = 'array';

    protected $allowedFields = ['name', 'username','gender','email'];
    protected $useTimestamps = false;

    protected $validationRules = [];
    protected $validationMessages = [];
    protected $skipValidation = false;

}


5. Route

  • Open the app/Config/Routes.php file.
  • Define 2 -

                     / - Show users a view.

                     users/user details - Used to send AJAX request.

Completed Code

$routes->get('/', 'UsersController::index');
$routes->post('users/userDetails', 'UsersController::userDetails');


6. Controller

  • Create a UsersController.php file in the app/Controllers/ folder.
  • Open the file.
  • Import Users Model.
  • Create 2 ways -

          index () - Download all records in the users table and provide $data['users'] data. Upload users to view and transfer $data Array.

          userDetails () - This method is used to manage AJAX application. This way retrieve user data in  JSON format with username.

Read POST values ​​and provide $postData flexibility. Create a $data Array to save feedback. Assign a new CSRF token to $data['token'].

Explain confirmation. If the POST value is invalid give 0 to $data ['success'] and error message to $data['error'].

If the value is valid give 1 to $data['success'] and download the record with the username to the users table. Provide downloaded record to $data['user'].

Restore $data Array in JSON format.

Completed Code

<?php namespace AppControllers;

use AppModelsUsers;

class UsersController extends BaseController
{

   public function index(){
      $users = new Users();

      ## Fetch all records
      $data['users'] = $users->findAll();

      return view('users',$data);
   }

   public function userDetails(){

      $request = service('request');
      $postData = $request->getPost();

      $data = array();

      // Read new token and assign in $data['token']
      $data['token'] = csrf_hash();

      ## Validation
      $validation = ConfigServices::validation();

      $input = $validation->setRules([
        'username' => 'required|min_length[3]'
      ]);

      if ($validation->withRequest($this->request)->run() == FALSE){

         $data['success'] = 0;
         $data['error'] = $validation->getError('username');// Error response

      }else{

         $data['success'] = 1;
         
         // Fetch record
         $users = new Users();
         $user = $users->select('*')
                ->where('username',$postData['username'])
                ->findAll();

         $data['user'] = $user;

      }

      return $this->response->setJSON($data);

   }

}


7. View

Create a users.php file in the app/Views/.

Create a hidden object to save the name of the CSRF tokens specified in the .env file in the name attribute and save the CSRF hash at attribute value.

<input type="hidden" class="txt_csrfname" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />

Enter usernames in <select id = 'sel_user'> by opening $users. Keep $user['username'] in the value attribute.

Displaying selected user information created objects.

Script –

Describe the change event in #sel_user.

Read the CSRF Token name and hash from a hidden field and share csrfName with csrfHash.

Assign a number of selected options to the username variation.

Send AJAX POST request to "<? = Site_url ('users / userDetails')?>". Transfer username and CSRF hash as data - {username: username, [csrfName]: csrfHash} as data.

Here, the hash will pass as - [csrfName]: csrfHash.

Set the dataType: 'json'. In a repetition call give response.token to '.txt_csrfname'. Unpack items .

If the response.success == 1 then open the response.user to read user data. Update text value with user data.

If the response.success is not equal to 0 then alert response.error.


8. Run

  • Navigate to the project, and
  • Execute “php spark serve” command.
  • Run http://localhost:8080 in the web browser.


9. Conclusion

CSRF token is not required to send with AJAX GET request. If you have enabled the CSRF token to be renewed you will need to renew the token after each request as I did in the example.

Set the app.CSRFRegenerate = false if you want to use the same token on all AJAX calls.

You can view this tutorial to find out how to submit an AJAX application and CSRF token to CodeIgniter 3.