18.2.1. ProblemYou want to be sure that a form submission is valid and intentional. 18.2.2. SolutionAdd a hidden form field with a one-time token, and store this token in the user's session: <?php session_start(); $_SESSION['token'] = md5(uniqid(mt_rand(), true)); ?> <form action="buy.php" method="POST"> <input type="hidden" name="token" value="<?php echo $_SESSION['token']; ?>" /> <p>Stock Symbol: <input type="text" name="symbol" /></p> <p>Quantity: <input type="text" name="quantity" /></p> <p><input type="submit" value="Buy Stocks" /></p> </form> When you receive a request that represents a form submission, check the tokens to be sure they match: <?php session_start(); if ($_POST['token'] != $_SESSION['token'] || !isset($_SESSION['token'])) { /* Prompt user for password. */ } else { /* Continue. */ } ?> 18.2.3. DiscussionThis technique protects against a group of attacks known as cross-site request forgeries (CSRF). These attacks all cause a victim to send requests to a target site without the victim's knowledge. Typically, the victim has an established level of privilege with the target site, so these attacks allow an attacker to perform actions that the attacker cannot otherwise perform. Adding a token to your forms in this way does not prevent a user from forging his own request from himself, but this is not something you can prevent, nor is it something to be concerned with. If you filter input as discussed in Recipe 18.3, you force requests to abide by your rules. The technique shown in this recipe helps to make sure the request is intentional. |