3
\$\begingroup\$

I have the following code which is supposed to insert a row into a DB table "clicks" (consisting of 1 Primary AI column "id" and another column "user" which contains the user's session ID) upon clicking the Like button. For each user assuming they have a session ID set from a login I would like to return to them their most recently inserted ID from the table. So the first time the button is clicked it will return 1 etc. I would like this to be accessible to multiple users through a login system.

Is this vulnerable to Cross-site request forgery and if so, how can I alter the code to defend against it?

index.php:

<?php
include 'init.php';
include 'connect.php';
?>
<!doctype html>
<html>
<body>
    <?php       
    $userid = $_SESSION['user_id'];
   echo '<a class="like" href="#" onclick="like_add(', $userid,   
  ');">Like</a>';
    ?>
    <script type ="text/javascript" src="jquery-1.11.1.min.js"></script>
    <script type ="text/javascript" src="like.js"></script>      
</body>
</html>

connect.php

<?php  
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "DB";
$conn = new mysqli($servername, $username, $password, $dbname);

if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
?>

init.php

<?php
session_start();
$_SESSION['user_id']='1';
$userid = $_SESSION['user_id'];
include 'connect.php';
include 'like.php';
?>

like.js

function like_add(userid) {
$.post('like_add.php', {userid:userid}, function(data) {
   if (data == 'success'){
    add_like($userid);
   } else{
       alert(data);
   }
});
}

like.php

<?php
function add_like($userid){
include 'connect.php';

$stmt = $conn->prepare("INSERT INTO clicks (user) VALUES (?)");
$stmt->bind_param("s", $userid);

$stmt->execute();
$stmt = $conn->prepare("SELECT max(id) FROM clicks WHERE user=?");
$stmt->bind_param("s", $userid);
$stmt->execute();
$stmt->bind_result($click);
$stmt->fetch();
echo $click;
$stmt->close();
}
?>

like_add.php

<?php
include 'init.php';
if (isset($userid)) {
$userid = $userid;
add_like($userid);
}
?>
\$\endgroup\$
  • \$\begingroup\$ @Jamal thanks - any ideas? \$\endgroup\$ – Damien Rice May 19 '15 at 7:29
  • \$\begingroup\$ Jamal only corrects typos... \$\endgroup\$ – Pinoniq May 26 '15 at 16:34
  • \$\begingroup\$ Note that now your $user_id is ALWAYS 1. is this by design? ;) \$\endgroup\$ – Pinoniq May 26 '15 at 16:40
  • \$\begingroup\$ you're including connect.php 3 times. \$\endgroup\$ – Sebas May 26 '15 at 23:18
  • 1
    \$\begingroup\$ Also, it's not really CSRF but rather spoofing.. but if you send contextual information through javascript (userid), you should expect this information to be untrustable. I don't understand why you send that information accross post ajax request since you already have it in php into the $_SESSION array. \$\endgroup\$ – Sebas May 26 '15 at 23:22
2
\$\begingroup\$

Defending agains CSRF offens happens by creating a token that can only be used once by the client that requested it. For proper protection, that token should ofcourse be linked to a form.

A simple one could be to add a md5 hash or similar to all your forms, store that hash somewhere. And then when the user submits, check or the hash is valid. Depending on the requirements, you can also add a Time to live to the hash (e.g. did it take more then 30minutes to submit the form?)

In your case, it is not a form, but a request being send to the server. Simply adding a token to that request (and validating it) would help you protect agains CSRF atacks.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.