Implement token system to fix CSRF vulnerabilities

Specially crafted pages can force authenticated users to unknowingly perform
actions on the AUR website despite being on an attacker's website. This
cross-site request forgery (CSRF) vulnerability applies to all POST data on
the AUR.

Implement a token system using a double submit cookie. Have a hidden form
value on every page containing POST forms. Use the newly added check_token() to
verify the token sent via POST matches the "AURSID" cookie value. Random
nature of the token limits potential for CSRF.

Signed-off-by: canyonknight <canyonknight@gmail.com>
Signed-off-by: Lukas Fleischer <archlinux@cryptocrack.de>
This commit is contained in:
canyonknight 2012-06-23 14:40:11 -04:00 committed by Lukas Fleischer
parent bfb25807c4
commit 2c93f0a98f
13 changed files with 82 additions and 46 deletions

View file

@ -88,11 +88,13 @@ if (isset($_COOKIE["AURSID"])) {
} elseif ($action == "UpdateAccount") {
# user is submitting their modifications to an existing account
#
process_account_form($atype, "edit", "UpdateAccount",
in_request("U"), in_request("T"), in_request("S"),
in_request("E"), in_request("P"), in_request("C"),
in_request("R"), in_request("L"), in_request("I"),
in_request("ID"));
if (check_token()) {
process_account_form($atype, "edit", "UpdateAccount",
in_request("U"), in_request("T"), in_request("S"),
in_request("E"), in_request("P"), in_request("C"),
in_request("R"), in_request("L"), in_request("I"),
in_request("ID"));
}
} else {

View file

@ -16,7 +16,11 @@ if (isset($_COOKIE["AURSID"])) {
if ($atype == "Trusted User" OR $atype == "Developer") {
$dbh = db_connect();
if (!empty($_POST['addVote'])) {
if (!empty($_POST['addVote']) && !check_token()) {
$error = __("Invalid token for user action.");
}
if (!empty($_POST['addVote']) && check_token()) {
$error = "";
if (!empty($_POST['user'])) {
@ -99,6 +103,7 @@ if ($atype == "Trusted User" OR $atype == "Developer") {
<b><?php print __('Proposal') ?></b><br />
<textarea name='agenda' rows='25' cols='80'><?php if (!empty($_POST['agenda'])) { print htmlentities($_POST['agenda']); } ?></textarea><br />
<input type='hidden' name='addVote' value='1' />
<input type='hidden' name='token' value='<?php print htmlspecialchars($_COOKIE['AURSID']) ?>' />
<input type='submit' class='button' value='<?php print __('Submit'); ?>' />
</p>
</form>

View file

@ -36,46 +36,48 @@ if (isset($_POST['IDs'])) {
# Determine what action to do
$output = "";
if (current_action("do_Flag")) {
$output = pkg_flag($atype, $ids, true);
} elseif (current_action("do_UnFlag")) {
$output = pkg_flag($atype, $ids, False);
} elseif (current_action("do_Adopt")) {
$output = pkg_adopt($atype, $ids, true);
} elseif (current_action("do_Disown")) {
$output = pkg_adopt($atype, $ids, False);
} elseif (current_action("do_Vote")) {
$output = pkg_vote($atype, $ids, true);
} elseif (current_action("do_UnVote")) {
$output = pkg_vote($atype, $ids, False);
} elseif (current_action("do_Delete")) {
if (isset($_POST['confirm_Delete'])) {
if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) {
$output = pkg_delete($atype, $ids, NULL);
unset($_GET['ID']);
}
else {
$mergepkgid = pkgid_from_name($_POST['merge_Into']);
if ($mergepkgid) {
$output = pkg_delete($atype, $ids, $mergepkgid);
if (check_token()) {
if (current_action("do_Flag")) {
$output = pkg_flag($atype, $ids, true);
} elseif (current_action("do_UnFlag")) {
$output = pkg_flag($atype, $ids, False);
} elseif (current_action("do_Adopt")) {
$output = pkg_adopt($atype, $ids, true);
} elseif (current_action("do_Disown")) {
$output = pkg_adopt($atype, $ids, False);
} elseif (current_action("do_Vote")) {
$output = pkg_vote($atype, $ids, true);
} elseif (current_action("do_UnVote")) {
$output = pkg_vote($atype, $ids, False);
} elseif (current_action("do_Delete")) {
if (isset($_POST['confirm_Delete'])) {
if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) {
$output = pkg_delete($atype, $ids, NULL);
unset($_GET['ID']);
}
else {
$output = __("Cannot find package to merge votes and comments into.");
$mergepkgid = pkgid_from_name($_POST['merge_Into']);
if ($mergepkgid) {
$output = pkg_delete($atype, $ids, $mergepkgid);
unset($_GET['ID']);
}
else {
$output = __("Cannot find package to merge votes and comments into.");
}
}
}
else {
$output = __("The selected packages have not been deleted, check the confirmation checkbox.");
}
} elseif (current_action("do_Notify")) {
$output = pkg_notify($atype, $ids);
} elseif (current_action("do_UnNotify")) {
$output = pkg_notify($atype, $ids, False);
} elseif (current_action("do_DeleteComment")) {
$output = pkg_delete_comment($atype);
} elseif (current_action("do_ChangeCategory")) {
$output = pkg_change_category($atype);
}
else {
$output = __("The selected packages have not been deleted, check the confirmation checkbox.");
}
} elseif (current_action("do_Notify")) {
$output = pkg_notify($atype, $ids);
} elseif (current_action("do_UnNotify")) {
$output = pkg_notify($atype, $ids, False);
} elseif (current_action("do_DeleteComment")) {
$output = pkg_delete_comment($atype);
} elseif (current_action("do_ChangeCategory")) {
$output = pkg_change_category($atype);
}
html_header($title);

View file

@ -27,9 +27,16 @@ if ($uid):
if (isset($_REQUEST['pkgsubmit'])) {
# Make sure authenticated user submitted the package themselves
if (!check_token()) {
$error = __("Invalid token for user action.");
}
# Before processing, make sure we even have a file
if ($_FILES['pfile']['size'] == 0){
$error = __("Error - No file uploaded");
if (!$error) {
if ($_FILES['pfile']['size'] == 0){
$error = __("Error - No file uploaded");
}
}
# Check whether the file is gzip'ed
@ -448,7 +455,8 @@ html_header("Submit");
?>
<form action='pkgsubmit.php' method='post' enctype='multipart/form-data'>
<div> <input type='hidden' name='pkgsubmit' value='1' /> </div>
<div> <input type='hidden' name='pkgsubmit' value='1' />
<input type='hidden' name='token' value='<?php print htmlspecialchars($_COOKIE['AURSID']) ?>' /> </div>
<table border='0' cellspacing='5'>
<tr>
<td class='f4' align='right'><?php print __("Package Category"); ?>:</td>

View file

@ -72,7 +72,7 @@ if ($atype == "Trusted User" OR $atype == "Developer") {
}
if ($canvote == 1) {
if (isset($_POST['doVote'])) {
if (isset($_POST['doVote']) && check_token()) {
if (isset($_POST['voteYes'])) {
$myvote = "Yes";
} else if (isset($_POST['voteNo'])) {

View file

@ -33,6 +33,7 @@ function display_account_form($UTYPE,$A,$U="",$T="",$S="",
print "<input type='hidden' name='Action' value='".$A."' />\n";
if ($UID) {
print "<input type='hidden' name='ID' value='".$UID."' />\n";
print "<input type='hidden' name='token' value='".htmlspecialchars($_COOKIE['AURSID'])."' />\n";
}
print "</fieldset>";
print "<table border='0' cellpadding='0' cellspacing='0' width='80%' style=\"margin:0 auto;\">\n";

View file

@ -77,6 +77,16 @@ function check_sid($dbh=NULL) {
return;
}
# Verify the supplied token matches the expected token for POST forms
#
function check_token() {
if (isset($_POST['token'])) {
return ($_POST['token'] == $_COOKIE['AURSID']);
} else {
return false;
}
}
# verify that an email address looks like it is legitimate
#
function valid_email($addy) {

View file

@ -3,6 +3,7 @@
<fieldset>
<input type='hidden' name='IDs[<?php echo $row['ID'] ?>]' value='1' />
<input type='hidden' name='ID' value="<?php echo $row['ID'] ?>" />
<input type='hidden' name='token' value="<?php echo htmlspecialchars($_COOKIE['AURSID']) ?>" />
<?php
# Voting Button
#

View file

@ -1,6 +1,6 @@
<?php
# Add a comment to this package
if (isset($_REQUEST['comment'])) {
if (isset($_REQUEST['comment']) && check_token()) {
# Insert the comment
$dbh = db_connect();
@ -53,13 +53,14 @@ if (isset($_REQUEST['comment'])) {
<form action='<?php echo $_SERVER['REQUEST_URI'] ?>' method='post'>
<div style="padding: 1%">
<?php
if (isset($_REQUEST['comment'])) {
if (isset($_REQUEST['comment']) && check_token()) {
echo '<b>' . __('Comment has been added.') . '</b>';
}
?>
<input type='hidden' name='ID' value="<?php echo intval($_REQUEST['ID']) ?>" />
<?php echo __('Enter your comment below.') ?><br />
<textarea name='comment' cols='80' rows='10' style="width: 100%"></textarea><br />
<input type='hidden' name='token' value='<?php echo htmlspecialchars($_COOKIE['AURSID']) ?>' />
<input type='submit' value="<?php echo __("Submit") ?>" />
<input type='reset' value="<?php echo __("Reset") ?>" />
</div>

View file

@ -15,6 +15,7 @@ while (list($indx, $carr) = each($comments)) { ?>
$durl.= '<fieldset style="display:inline;">';
$durl.= '<input type="hidden" name="action" value="do_DeleteComment" />';
$durl.= '<input type="hidden" name="comment_id" value="'.$carr['ID'].'" />';
$durl.= '<input type="hidden" name="token" value="'.htmlspecialchars($_COOKIE['AURSID']).'" />';
$durl.= '<input type="image" src="images/x.png" ';
$durl.= ' alt="'.__("Delete comment").'" name="submit" value="1" ';
$durl.= ' />&nbsp;';

View file

@ -10,6 +10,9 @@ if ($uid == $row["MaintainerUID"] or
$edit_cat = "<form method='post' action='packages.php?ID=".$pkgid."'>\n";
$edit_cat.= "<p>";
$edit_cat.= "<input type='hidden' name='action' value='do_ChangeCategory' />";
if ($SID) {
$edit_cat.= "<input type='hidden' name='token' value='".htmlspecialchars($_COOKIE['AURSID'])."' />";
}
$edit_cat.= "<span class='f3'>" . __("Category") . ":</span> ";
$edit_cat.= "<select name='category_id'>\n";
foreach ($catarr as $cid => $catname) {

View file

@ -114,6 +114,7 @@ for ($i = 0; $row = mysql_fetch_assoc($result); $i++) {
<input type='text' id='merge_Into' name='merge_Into' />
<input type='checkbox' name='confirm_Delete' value='1' /> <?php print __("Confirm") ?>
<?php endif; ?>
<input type='hidden' name='token' value='<?php print htmlspecialchars($_COOKIE['AURSID']) ?>' />
<input type='submit' class='button' style='width: 80px' value='<?php print __("Go") ?>' />
</div>
<?php endif; # if ($SID) ?>

View file

@ -70,6 +70,7 @@ if (!$isrunning) { ?>
<input type='submit' class='button' name='voteNo' value='<?php print __("No") ?>' />
<input type='submit' class='button' name='voteAbstain' value='<?php print __("Abstain") ?>' />
<input type='hidden' name='doVote' value='1' />
<input type='hidden' name='token' value='<?php print htmlspecialchars($_COOKIE['AURSID']) ?>' />
</fieldset>
</form>
<?php } else { ?>