TheOnly92
TheOnly92

Reputation: 1763

Prevent Users from Performing an Action Twice

We have some problems with users performing a specific action twice, we have a mechanism to ensure that users can't do it but somehow it still happens. Here is how our current mechanism works:

  1. Client side: The button will be disabled after 1 click.
  2. Server side: We have a key hash in the URL which will be checked against the key stored in SESSIONS, once it matches, the key is deleted.
  3. Database side: Once the action is performed, there is a field to be flagged indicating the user has completed the action.

However, with all these measures, still there are users able to perform the action twice, are there any more safer methods?

Here is the partial code for the database side:

$db->beginTransaction();
// Get the user's datas
$user = $db->queryRow("SELECT flag FROM users WHERE userid = {$auth->getProperty('auth_user_id)}");
if ($user['flag'] != 0) {
    $db->rollback();
    // Return with error
    return false;
}
// Proceed with performing the action
// --- Action Here ---
// Double checking process, the user data is retrieved again
$user = $db->queryRow("SELECT flag FROM users WHERE userid = {$auth->getProperty('auth_user_id)}");
if ($user['flag'] != 0) {
    $db->rollback();
    // Return with error
    return false;
}
// --- The final inserting query ---
// Update the flag
$db->query("UPDATE users SET flag = 1 WHERE userid = {$auth->getProperty('auth_user_id)}");
$db->commit();
return true;

Upvotes: 2

Views: 383

Answers (3)

Kamil Szot
Kamil Szot

Reputation: 17817

Pseudocode follows:

<?

$act_id; // contains id of action to be executed

$h = uniqid('');

// this locks action (if it is unlocked) and marks it as being performed by me.
UPDATE actions SET executor = $h WHERE act_id = $act_id AND executor = ''; 

SELECT * FROM actions WHERE executor = $h;

//
// If above query resulted in some action execute it here
//

// if you want to allow for executing this exact action in the future mark it as not executed
UPDATE actions SET executor = '' WHERE act_id = $act_id; 

Important things:

  • First query should be update claiming the action for me if it is yet unclaimed.
  • Second should be query grabbing action to execute but only if it was claimed by me.

Upvotes: 0

nik
nik

Reputation: 3678

Well the JS method and Hash method may be cheated by some notorious guy, but 3rd method seems to be very good in order to protect the redundancy. There must be some programming flaw to get passed this.

Why don't u just check the flag field on the page where you are inserting the values rather than where user performing the action (if you are doing it now)

Upvotes: 0

Sarfraz
Sarfraz

Reputation: 382706

It is good to see that you have taken all measures to defeat the bad guys. Speaking in terms of bad guys:

Finally:

I would recommend to you to check out the:

OWASP PHP Project

The OWASP PHP Project's goal (OWASP PHP Project Roadmap) is to enable developers, systems administrators and application architects to build and deploy secure applications built using the PHP programming language.

Upvotes: 1

Related Questions