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") { } elseif ($action == "UpdateAccount") {
# user is submitting their modifications to an existing account # user is submitting their modifications to an existing account
# #
if (check_token()) {
process_account_form($atype, "edit", "UpdateAccount", process_account_form($atype, "edit", "UpdateAccount",
in_request("U"), in_request("T"), in_request("S"), in_request("U"), in_request("T"), in_request("S"),
in_request("E"), in_request("P"), in_request("C"), in_request("E"), in_request("P"), in_request("C"),
in_request("R"), in_request("L"), in_request("I"), in_request("R"), in_request("L"), in_request("I"),
in_request("ID")); in_request("ID"));
}
} else { } else {

View file

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

View file

@ -36,19 +36,20 @@ if (isset($_POST['IDs'])) {
# Determine what action to do # Determine what action to do
$output = ""; $output = "";
if (current_action("do_Flag")) { if (check_token()) {
if (current_action("do_Flag")) {
$output = pkg_flag($atype, $ids, true); $output = pkg_flag($atype, $ids, true);
} elseif (current_action("do_UnFlag")) { } elseif (current_action("do_UnFlag")) {
$output = pkg_flag($atype, $ids, False); $output = pkg_flag($atype, $ids, False);
} elseif (current_action("do_Adopt")) { } elseif (current_action("do_Adopt")) {
$output = pkg_adopt($atype, $ids, true); $output = pkg_adopt($atype, $ids, true);
} elseif (current_action("do_Disown")) { } elseif (current_action("do_Disown")) {
$output = pkg_adopt($atype, $ids, False); $output = pkg_adopt($atype, $ids, False);
} elseif (current_action("do_Vote")) { } elseif (current_action("do_Vote")) {
$output = pkg_vote($atype, $ids, true); $output = pkg_vote($atype, $ids, true);
} elseif (current_action("do_UnVote")) { } elseif (current_action("do_UnVote")) {
$output = pkg_vote($atype, $ids, False); $output = pkg_vote($atype, $ids, False);
} elseif (current_action("do_Delete")) { } elseif (current_action("do_Delete")) {
if (isset($_POST['confirm_Delete'])) { if (isset($_POST['confirm_Delete'])) {
if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) {
$output = pkg_delete($atype, $ids, NULL); $output = pkg_delete($atype, $ids, NULL);
@ -68,14 +69,15 @@ if (current_action("do_Flag")) {
else { else {
$output = __("The selected packages have not been deleted, check the confirmation checkbox."); $output = __("The selected packages have not been deleted, check the confirmation checkbox.");
} }
} elseif (current_action("do_Notify")) { } elseif (current_action("do_Notify")) {
$output = pkg_notify($atype, $ids); $output = pkg_notify($atype, $ids);
} elseif (current_action("do_UnNotify")) { } elseif (current_action("do_UnNotify")) {
$output = pkg_notify($atype, $ids, False); $output = pkg_notify($atype, $ids, False);
} elseif (current_action("do_DeleteComment")) { } elseif (current_action("do_DeleteComment")) {
$output = pkg_delete_comment($atype); $output = pkg_delete_comment($atype);
} elseif (current_action("do_ChangeCategory")) { } elseif (current_action("do_ChangeCategory")) {
$output = pkg_change_category($atype); $output = pkg_change_category($atype);
}
} }
html_header($title); html_header($title);

View file

@ -27,10 +27,17 @@ if ($uid):
if (isset($_REQUEST['pkgsubmit'])) { 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 # Before processing, make sure we even have a file
if (!$error) {
if ($_FILES['pfile']['size'] == 0){ if ($_FILES['pfile']['size'] == 0){
$error = __("Error - No file uploaded"); $error = __("Error - No file uploaded");
} }
}
# Check whether the file is gzip'ed # Check whether the file is gzip'ed
if (!$error) { if (!$error) {
@ -448,7 +455,8 @@ html_header("Submit");
?> ?>
<form action='pkgsubmit.php' method='post' enctype='multipart/form-data'> <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'> <table border='0' cellspacing='5'>
<tr> <tr>
<td class='f4' align='right'><?php print __("Package Category"); ?>:</td> <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 ($canvote == 1) {
if (isset($_POST['doVote'])) { if (isset($_POST['doVote']) && check_token()) {
if (isset($_POST['voteYes'])) { if (isset($_POST['voteYes'])) {
$myvote = "Yes"; $myvote = "Yes";
} else if (isset($_POST['voteNo'])) { } 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"; print "<input type='hidden' name='Action' value='".$A."' />\n";
if ($UID) { if ($UID) {
print "<input type='hidden' name='ID' value='".$UID."' />\n"; print "<input type='hidden' name='ID' value='".$UID."' />\n";
print "<input type='hidden' name='token' value='".htmlspecialchars($_COOKIE['AURSID'])."' />\n";
} }
print "</fieldset>"; print "</fieldset>";
print "<table border='0' cellpadding='0' cellspacing='0' width='80%' style=\"margin:0 auto;\">\n"; 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; 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 # verify that an email address looks like it is legitimate
# #
function valid_email($addy) { function valid_email($addy) {

View file

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

View file

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

View file

@ -15,6 +15,7 @@ while (list($indx, $carr) = each($comments)) { ?>
$durl.= '<fieldset style="display:inline;">'; $durl.= '<fieldset style="display:inline;">';
$durl.= '<input type="hidden" name="action" value="do_DeleteComment" />'; $durl.= '<input type="hidden" name="action" value="do_DeleteComment" />';
$durl.= '<input type="hidden" name="comment_id" value="'.$carr['ID'].'" />'; $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.= '<input type="image" src="images/x.png" ';
$durl.= ' alt="'.__("Delete comment").'" name="submit" value="1" '; $durl.= ' alt="'.__("Delete comment").'" name="submit" value="1" ';
$durl.= ' />&nbsp;'; $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 = "<form method='post' action='packages.php?ID=".$pkgid."'>\n";
$edit_cat.= "<p>"; $edit_cat.= "<p>";
$edit_cat.= "<input type='hidden' name='action' value='do_ChangeCategory' />"; $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.= "<span class='f3'>" . __("Category") . ":</span> ";
$edit_cat.= "<select name='category_id'>\n"; $edit_cat.= "<select name='category_id'>\n";
foreach ($catarr as $cid => $catname) { 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='text' id='merge_Into' name='merge_Into' />
<input type='checkbox' name='confirm_Delete' value='1' /> <?php print __("Confirm") ?> <input type='checkbox' name='confirm_Delete' value='1' /> <?php print __("Confirm") ?>
<?php endif; ?> <?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") ?>' /> <input type='submit' class='button' style='width: 80px' value='<?php print __("Go") ?>' />
</div> </div>
<?php endif; # if ($SID) ?> <?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='voteNo' value='<?php print __("No") ?>' />
<input type='submit' class='button' name='voteAbstain' value='<?php print __("Abstain") ?>' /> <input type='submit' class='button' name='voteAbstain' value='<?php print __("Abstain") ?>' />
<input type='hidden' name='doVote' value='1' /> <input type='hidden' name='doVote' value='1' />
<input type='hidden' name='token' value='<?php print htmlspecialchars($_COOKIE['AURSID']) ?>' />
</fieldset> </fieldset>
</form> </form>
<?php } else { ?> <?php } else { ?>