0

I'm trying to make a notification system for my essay review website here is the basic flow of what should happen:

flow

and here are my tables' structures(MySQL):

schema

The problem I'm having is that I can't figure out how to update the status in the relations table securely once a user accepts or declines a review request. I could set the values of the accept/decline buttons to the id of the relationship and use ajax to update the status of that relationship, but that doesn't seem secure as a user could just change the value with inspect element.

Here is an example of what I have:
request.php

<?php
//define global variables
$dbhost = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbdatabase = "test";
$conn = new mysqli($dbhost, $dbusername, $dbpassword, $dbdatabase);
?>
<a href="user43notifs.php">Click here to go to user 43's notifications</a><br><br>

<!--Example requests-->

<form action="request.inc.php" method="post">
  op_id: 43<br>
  reviewer_id: 42<br>
  essay_id: 34<br>
  <input type="hidden" name="op_id" value="43">
  <input type="hidden" name="reviewer_id" value="42">
  <input type="hidden" name="essay_id" value="34">
  <input type="submit" name="submit">
</form>
<form action="request.inc.php" method="post">
  op_id: 43<br>
  reviewer_id: 16<br>
  essay_id: 135<br>
  <input type="hidden" name="op_id" value="43">
  <input type="hidden" name="reviewer_id" value="16">
  <input type="hidden" name="essay_id" value="135">
  <input type="submit" name="submit">
</form>
<form action="request.inc.php" method="post">
  op_id: 78<br>
  reviewer_id: 12<br>
  essay_id: 25<br>
  <input type="hidden" name="op_id" value="78">
  <input type="hidden" name="reviewer_id" value="12">
  <input type="hidden" name="essay_id" value="25">
  <input type="submit" name="submit">
</form>

request.inc.php

<?php
//define global variables
$dbhost = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbdatabase = "test";
$conn = new mysqli($dbhost, $dbusername, $dbpassword, $dbdatabase);

$op = mysqli_real_escape_string($conn, $_POST['op_id']);
$reviewer = mysqli_real_escape_string($conn, $_POST['reviewer_id']);
$essay = mysqli_real_escape_string($conn, $_POST['essay_id']);

$sql = "INSERT INTO `reviewer_relations` (`reviewer_id`, `essay_id`, `status`)
VALUES ('$reviewer', '$essay', 0)";

$result=mysqli_query($conn, $sql);
if($result === TRUE){
  $title = mysqli_real_escape_string($conn, $reviewer." has requested to review your essay: essay#".$essay.".");
  $message = mysqli_real_escape_string($conn, '<button onclick="location.href=\'scripts/review_request.php?confirmation=accept\'" class="review-accept">Accept</button><button onclick="location.href=\'scripts/review_request.php?confirmation=decline\'" class="review-decline">Decline</button>');
  $sql = "INSERT INTO `notifications` (`user_id`, `title`, `message`)
  VALUES ('$op', '$title', '$message')";

  $result=mysqli_query($conn, $sql);

  if($result === TRUE){
    echo 'notification and relation insert success';
  }
  else{
    echo 'notification insert fail: '.mysqli_error($conn);
  }
}
else{
  echo 'relation insert fail: '.mysqli_error($conn);
}
?>

user43notifs.php

<?php
$dbhost = "localhost";
$dbusername = "root";
$dbpassword = "";
$dbdatabase = "test";
$conn = new mysqli($dbhost, $dbusername, $dbpassword, $dbdatabase);

$sql="SELECT *
FROM notifications
WHERE user_id = 43";
$result = mysqli_query($conn, $sql);
while($row = mysqli_fetch_assoc($result)){
  echo '**********************************************<br>';
  echo $row['title'].'<br>';
  echo $row['message'].'<br>';
}
?>

using these two table tables setup up with PHPMyAdmin:
reviewer_relations
reviewer_relations
notifications
enter image description here

I need a secure way to update the status column of the reviewer_relation that is represented by the notification when the user clicks on said notification's accept or decline button.

The problem is I can't figure out a way to associate the relationship id (or the reviewer_id and essay_id that describe the relationship) to it's notification without putting it directly into the notification's HTML where it's vulnerable to be changed.

I don't often ask questions, so any critique on how the question is titled, written, or stated is greatly appreciated. If any additional information is needed please ask. Thanks!

Alex Charters
  • 301
  • 2
  • 12
  • 6
    We are always glad to help and support new coders but ***you need to help yourself first. :-)*** After [**doing more research**](https://meta.stackoverflow.com/q/261592/1011527) if you have a problem **post what you've tried** with a **clear explanation of what isn't working** and provide [a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve). Read [How to Ask](http://stackoverflow.com/help/how-to-ask) a good question. Be sure to [take the tour](http://stackoverflow.com/tour) and read [this](https://meta.stackoverflow.com/q/347937/1011527). – Jay Blanchard Jul 23 '18 at 17:51
  • @JayBlanchard Thank you for the advice! I've read the material and updated the question. I'm sorry it's lacking in the "what I've tried" aspect but everything I can think of and looked up I know will not meet the requirements of what I need. – Alex Charters Jul 23 '18 at 20:48
  • Basically, you should have the AJAX API inspect the user's identity through session or token. And if you have the user identity in your API call resolver, it should be able to determine if the user can or cannot change a thing in a specific way. To put it simply, you'd know if the user has permission to the essay, and you'd know if the user may set the status to enable / disable. – Koala Yeung Jul 24 '18 at 04:41
  • If you're afraid that hacker might sniff the token / session, use HTTPS on your server. [Let's Encrypt](https://letsencrypt.org/) is free to use. – Koala Yeung Jul 24 '18 at 04:44
  • Thanks Koala, my problem is not trying to see whether or not a user has permission to edit, but how to securely update the status column when only the html of that notification is available to be used in the sql statement. I think I have a solution though. I'll post it as an answer in a bit. – Alex Charters Jul 24 '18 at 17:46

1 Answers1

0

I believe I've found a solution:
I've added a token column to the user-essay relations table so that each request can be identified with a unique, cryptographically secure token (See Scott's updated answer here for token generating code).
Then when the notification is inserted into the notification table I set the value of the accept button as the token. That way when the notifications page is loaded the token can be retrieved by using .val() and used with ajax to update the status of the appropriate request. So, while a user could change the value of the button the chances of them guessing the 100-character-long token of another request is astronomically small.
Please let me know if this is not as secure as I think it to be.

Alex Charters
  • 301
  • 2
  • 12