Plugin Directory

Changeset 2717317


Ignore:
Timestamp:
05/02/2022 10:08:25 PM (4 years ago)
Author:
era404
Message:

Added wp_nonce_url and check_admin_referer to admin delete record feature to defend against CSRF, as suggested by Hassan Khan Yusufzai (thank you);

Location:
stafflist/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • stafflist/trunk/readme.txt

    r2717270 r2717317  
    44Tags: staff, directory, faculty, personnel, phonebook, rubrik
    55Requires at least: 3.2.1
    6 Tested up to: 5.7.2
     6Tested up to: 5.9.3
    77Requires PHP: 5.6
    88Stable tag: trunk
     
    103103
    104104== Changelog ==
     105= 3.1.6 =
     106* Added wp_nonce_url and check_admin_referer to admin delete record feature to defend against CSRF, as suggested by Hassan Khan Yusufzai (thank you);
     107
    105108= 3.1.5 =
    106 * Fixed a vulnerability in admin search discoverd by HYusufzai (thank you);
     109* Fixed a vulnerability in admin search discoverd by Hassan Khan Yusufzai (thank you);
    107110
    108111= 3.1.2 =
  • stafflist/trunk/stafflist.php

    r2717270 r2717317  
    44Plugin URI: http://wordpress.org/plugins/stafflist/
    55Description: A super simplified staff directory tool
    6 Version: 3.1.5
     6Version: 3.1.6
    77Author: era404
    88Author URI: http://www.era404.com
     
    138138*     Build Admin Page
    139139***********************************************************************************/
    140 function stafflist_plugin_options() {
     140function stafflist_plugin_options(){
    141141    if ( !current_user_can( 'edit_stafflist' ) )  {
    142142        wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
     
    191191    //handle deleting records
    192192    $cr = 0;
    193     if(isset($_GET['remove'])) {
    194         $q = "SELECT count(id) FROM $staffdb WHERE id=%s";
    195             $cr = $wpdb->get_var($wpdb->prepare($q, (int) $_GET['remove']) );
    196         $q = "DELETE FROM $staffdb WHERE id=%s";
    197             $wpdb->query($wpdb->prepare( $q, (int) $_GET['remove']) );
     193    if(isset($_GET['remove']) && is_numeric($_GET['remove'])){
     194        if(check_admin_referer()){
     195            $q = "SELECT count(id) FROM $staffdb WHERE id=%s";
     196            $r = (int) trim($_GET['remove']);
     197            $cr = $wpdb->get_var($wpdb->prepare($q,$r));
     198            if($wpdb->get_var($wpdb->prepare($q,$r)==1)){
     199                $q = "DELETE FROM $staffdb WHERE id=%s";
     200                $wpdb->query($wpdb->prepare($q,$r));
     201            }
     202        }
    198203    }
    199204
    200205    //handle sorting
    201     $s = $_GET['s'] = (!isset($_GET['s']) ? $cols[0]['id'] : $_GET['s']);
    202     $dir = strstr($s,"-")?"ASC":"DESC"; $default = false; $sort = false;
    203     //front-end sorting
    204     foreach($cols as $col){
    205         if(!$default) $default = $col['col'];
    206         if($col['id'] == str_replace("-","",$s)){ $sort = $col['col']; break; }
    207     }
    208     //back-end sorting
    209     if(!$sort && !is_numeric($s)){
    210         $sorts = array("last"=>"lastname","first"=>"firstname","dept"=>"department","email"=>"email");
    211         if(isset($sorts[ str_replace("-","",$s) ])) $sort = $sorts[ str_replace("-","",$s) ];
    212     }
    213     if(!$sort) $sort = $default;
    214    
     206    $sorts = array("last"=>"lastname","first"=>"firstname","dept"=>"department","email"=>"email");
     207    $s =    $_GET['s'] = (isset($_GET['s']) && in_array(trim($_GET['s']),array("last","first","dept","email","last-","first-","dept-","email-")) ? (string) trim($_GET['s']) : "last");
     208    $sort = $sorts[str_replace("-","",$s)];
     209    $dir =  (strstr($s,"-")?"DESC":"ASC");
     210
    215211    //handle search (use mb_strtolower, where available)
    216212    if(isset($_GET['search']) && (string) trim($_GET['search'])!=""){
    217213       
    218214        $w = (function_exists('mb_strtolower') ?
    219                 mb_strtolower(  $_GET['search'],'utf8') :
    220                 strtolower(     $_GET['search']));
     215                mb_strtolower(  sanitize_text_field($_GET['search']),'utf8') :
     216                strtolower(     sanitize_text_field($_GET['search'])));
    221217        $ws = '%'.$wpdb->esc_like($w).'%';
    222218        $where = "WHERE LOWER(lastname)     LIKE %s OR
     
    244240    $q =        "SELECT count(id) FROM $staffdb {$where}";
    245241    $sql =      $wpdb->prepare($q,$params);
    246     $count =    $wpdb->get_var(); //echo "COUNT: $count<br /><br />";
     242    $count =    $wpdb->get_var($sql);
    247243
    248244    //handle paging
    249245    $pg = array((int) $count, (int) $rows, (int) ceil($count/$rows));
    250     $p = $_GET['p'] = $pg[3] = (!isset($_GET['p']) || $_GET['p']<1 || $_GET['p']>$pg[2] ? 1 : $_GET['p']);
     246    $p = $_GET['p'] = $pg[3] = (!isset($_GET['p']) || !is_numeric($_GET['p']) || intval($_GET['p'])<2 || intval($_GET['p'])>$pg[2] ? 1 : intval($_GET['p']));
    251247    $pg[4] = (int) ($pg[1]*$pg[3])-$pg[1];
    252248    $pg[5] = (int) ($pg[4]+$pg[1])-1; if($pg[5]+1>$pg[0]) $pg[5]=($pg[0]-1);
     
    291287    echo "<div id='warning' class='orange' style='display:".($cr>0?"block":"none").";'>".(($cr>0)?"<strong>NOTE:</strong> [ $cr ] Staff Record removed.":"")."</div>";
    292288    echo "<input type='text' id='searchdirectory' name='searchdirectory' value='".esc_attr(stripslashes($w))."' placeholder='Search Directory' />";
    293    
    294     global $stafflisturl; $stafflisturl = STAFFLIST_URL . ($w ? "&search={$w}" : "");
     289
     290    global  $stafflisturl;
     291            $stafflisturl = STAFFLIST_URL . ($w ? "&search={$w}" : "") . ($s ? "&s={$s}" : "");
    295292    echo renderAdminPager($pg);
    296293   
     
    298295          <table id='stafflists' style='border:1px solid #E8E8E8;'>";
    299296    echo "<thead id='stafflisthead'><tr>
    300             <th><a href='{$stafflisturl}&s=last' title='Sort by Last Name A-Z' class='sort_a ".($_GET['s']=='last'?'selected':'')."'><span>Ascending</span></a> Last Name
    301                 <a href='{$stafflisturl}&s=last-' title='Sort by Last Name Z-A' class='sort_d ".($_GET['s']=='last-'?'selected':'')."'><span>Descending</span></a>
     297            <th><a href='{$stafflisturl}&s=last' title='Sort by Last Name A-Z' class='sort_a ".($s=='last'?'selected':'')."'><span>Ascending</span></a> Last Name
     298                <a href='{$stafflisturl}&s=last-' title='Sort by Last Name Z-A' class='sort_d ".($s=='last-'?'selected':'')."'><span>Descending</span></a>
    302299            </th><th>&nbsp;</th>
    303             <th><a href='{$stafflisturl}&s=first' title='Sort by First Name Ascending' class='sort_a ".($_GET['s']=='first'?'selected':'')."'><span>Ascending</span></a> First Name
    304                 <a href='{$stafflisturl}&s=first-' title='Sort by First Name Descending' class='sort_d ".($_GET['s']=='first-'?'selected':'')."'><span>Descending</span></a>
     300            <th><a href='{$stafflisturl}&s=first' title='Sort by First Name Ascending' class='sort_a ".($s=='first'?'selected':'')."'><span>Ascending</span></a> First Name
     301                <a href='{$stafflisturl}&s=first-' title='Sort by First Name Descending' class='sort_d ".($s=='first-'?'selected':'')."'><span>Descending</span></a>
    305302            </th><th>&nbsp;</th>
    306             <th><a href='{$stafflisturl}&s=dept' title='Sort by Department Ascending' class='sort_a ".($_GET['s']=='dept'?'selected':'')."'><span>Ascending</span></a> Department
    307                 <a href='{$stafflisturl}&s=dept-' title='Sort by Department Descending' class='sort_d ".($_GET['s']=='dept-'?'selected':'')."'><span>Descending</span></a>
     303            <th><a href='{$stafflisturl}&s=dept' title='Sort by Department Ascending' class='sort_a ".($s=='dept'?'selected':'')."'><span>Ascending</span></a> Department
     304                <a href='{$stafflisturl}&s=dept-' title='Sort by Department Descending' class='sort_d ".($s=='dept-'?'selected':'')."'><span>Descending</span></a>
    308305            </th><th>&nbsp;</th>
    309             <th><a href='{$stafflisturl}&s=email' title='Sort by Email Address Ascending' class='sort_a ".($_GET['s']=='email'?'selected':'')."'><span>Ascending</span></a> Email Address
    310                 <a href='{$stafflisturl}&s=email-' title='Sort by Email Address Descending' class='sort_d ".($_GET['s']=='email-'?'selected':'')."'><span>Descending</span></a>
     306            <th><a href='{$stafflisturl}&s=email' title='Sort by Email Address Ascending' class='sort_a ".($s=='email'?'selected':'')."'><span>Ascending</span></a> Email Address
     307                <a href='{$stafflisturl}&s=email-' title='Sort by Email Address Descending' class='sort_d ".($s=='email-'?'selected':'')."'><span>Descending</span></a>
    311308            </th><th>&nbsp;</th>
    312309            <th>Phone / Ext</th><th>&nbsp;</th>";
     
    315312   
    316313    $i=0;
    317     foreach($staff as $k=>$s){
    318         $del = "<a href='{$stafflisturl}&remove={$s['id']}&p={$p}&s={$_GET['s']}' class='remove'
     314    foreach($staff as $k=>$v){
     315        $del = "<a href='".wp_nonce_url("{$stafflisturl}&remove={$v['id']}&p={$p}&s={$s}")."' class='remove'
    319316                   onclick='javascript:if(!confirm(\"Are you sure you want to delete this staff record?\")) return false;'
    320317                   title='Permanently Delete This Staff Record' target='_self'
     
    322319        $i++;
    323320       
    324         echo "<tr class='row' id='staff_{$s['id']}'>
    325         <td><input type='text' id='lastname:{$s['id']}' value='".esc_attr($s['lastname'])."' autocomplete='Off' /></td><td></td>
    326         <td><input type='text' id='firstname:{$s['id']}' value='".esc_attr($s['firstname'])."' autocomplete='Off' /></td><td></td>
    327         <td><input type='text' id='department:{$s['id']}' value='".esc_attr($s['department'])."' autocomplete='Off' /></td><td></td>
    328         <td><input type='text' id='email:{$s['id']}' value='".esc_attr($s['email'])."' autocomplete='Off' /></td><td></td>
    329         <td><input type='text' id='phone:{$s['id']}' value='".esc_attr($s['phone'])."' autocomplete='Off' /></td><td></td>";
     321        echo "<tr class='row' id='staff_{$v['id']}'>
     322        <td><input type='text' id='lastname:{$v['id']}' value='".esc_attr($v['lastname'])."' autocomplete='Off' /></td><td></td>
     323        <td><input type='text' id='firstname:{$v['id']}' value='".esc_attr($v['firstname'])."' autocomplete='Off' /></td><td></td>
     324        <td><input type='text' id='department:{$v['id']}' value='".esc_attr($v['department'])."' autocomplete='Off' /></td><td></td>
     325        <td><input type='text' id='email:{$v['id']}' value='".esc_attr($v['email'])."' autocomplete='Off' /></td><td></td>
     326        <td><input type='text' id='phone:{$v['id']}' value='".esc_attr($v['phone'])."' autocomplete='Off' /></td><td></td>";
    330327        for($i = 1; $i <= $activeCols; $i++){
    331328            $col = $i+5;
    332329            $key = "col{$col}";
    333             echo "<td><input type='text' id='col{$col}:{$s['id']}' value='".esc_attr($s[$key])."' autocomplete='Off' /></td>";
     330            echo "<td><input type='text' id='col{$col}:{$v['id']}' value='".esc_attr($v[$key])."' autocomplete='Off' /></td>";
    334331            if($i < $activeCols) echo "<td></td>";
    335332        }
     
    526523    $cur = $pg[3];
    527524    $last = $pg[2];
    528     global $stafflisturl; //includes search
     525    global $stafflisturl; //includes search & sort
    529526
    530527    //one page or less?
    531528    if($pg[0]<1 || $last<2) return("");
    532529    //previous
    533     $html = ($cur > 1 ? "<p class='pager'><a href='{$stafflisturl}&p=".($cur-1)."&s={$_GET['s']}'>Previous </a></p>" : ""); //<
     530    $html = ($cur > 1 ? "<p class='pager'><a href='{$stafflisturl}&p=".($cur-1)."'>Previous </a></p>" : "");
    534531    //pages
    535532    if($cur<=3){
     
    550547    }
    551548    //next
    552     $html .= (($cur < $pg[2] && $pg[2] > 1) ? "<p class='pager'><a href='{$stafflisturl}&p=".($cur+1)."&s={$_GET['s']}'> Next</a></p>" : ""); //>
     549    $html .= (($cur < $pg[2] && $pg[2] > 1) ? "<p class='pager'><a href='{$stafflisturl}&p=".($cur+1)."'> Next</a></p>" : ""); //>
    553550    //page numbering
    554551    $html .= "<div class='pageNum'>Page: ".($pg[3])." ( ".($pg[4]+1)."-".($pg[5]+1)." of ".($pg[0])." )</div>";
     
    557554function renderAdminPage($style, $page){
    558555    global $stafflisturl; //includes search
    559     return("<p class='pager{$style}'>".(is_numeric($page)?"<a href='{$stafflisturl}&p={$page}&s={$_GET['s']}'>{$page}</a>":$page)."</p>");
     556    return("<p class='pager{$style}'>".(is_numeric($page)?"<a href='{$stafflisturl}&p={$page}'>{$page}</a>":$page)."</p>");
    560557}
    561558/***********************************************************************************
     
    580577        $limit = (empty($_POST) ? array("sort"=>$cols[0]['id'],"page"=>1,"search"=>"") : $_POST);
    581578        $wait = (isset($_POST['wait']) && (string) trim($_POST['wait']) == "true" ? true : false);
    582         if(!isset($limit['sort']) || $limit['sort'] == "") $limit['sort'] = $cols[0]['id'];
     579        if(!isset($limit['sort']) || $limit['sort'] == "" || !preg_match('/^[\d]+-?$/', trim($limit['sort']))) $limit['sort'] = $cols[0]['id'];
     580        if(!isset($limit['page']) || !is_numeric($limit['page'])) $limit['page'] = 1;
    583581        if(!isset($limit['search'])) $limit['search'] = "";
    584582       
     
    636634       
    637635        //if $_POST['rows'] use that instead of default RECORDS_PER_PAGE;
    638         if(isset($_POST['rows']) && is_numeric($_POST['rows']) && $_POST['rows'] > 0 && $_POST['rows'] <= 100) $rows = $_POST['rows'];
     636        if(isset($_POST['rows']) && is_numeric($_POST['rows']) && $_POST['rows'] > 0 && $_POST['rows'] <= 100) $rows = intval($_POST['rows']);
    639637       
    640638        //handle paging
    641639        $pg = array((int) $count, (int) $rows, (int) ceil($count/$rows));
    642         $pg[3] = (int) (!isset($limit['page']) || $limit['page']<1 || $limit['page']>$pg[2] ? 1 : $limit['page']);
     640        $pg[3] = (int) (!isset($limit['page']) || $limit['page']<2 || $limit['page']>$pg[2] ? 1 : $limit['page']);
    643641        $pg[4] = (int) ($pg[1]*$pg[3])-$pg[1];
    644642        $pg[5] = (int) ($pg[4]+$pg[1])-1; if($pg[5]+1>$pg[0]) $pg[5]=($pg[0]-1);
     
    12761274    global  $wpdb,$cols,            //wpdb object
    12771275            $staffdb,$staffmetadb;  //csvs and the like
    1278    
    1279     error_reporting(E_ALL); ini_set('display_errors',1);
    12801276
    12811277    //column names
     
    12881284    //sorting
    12891285    $sorts = array("last"=>"lastname","first"=>"firstname","dept"=>"department","email"=>"email");
    1290     $s = (isset($_GET['s']) && array_key_exists(rtrim($_GET['s'],"-"), $sorts) ? $_GET['s'] : "last-");
    1291     $dir = strstr($s,"-")?"ASC":"DESC";
    1292     $sort = $sorts[ str_replace("-","",$s) ];
    1293    
    1294     //filter by searched keyword
    1295     $w = (isset($_GET['search']) && (string) trim($_GET['search'])!="" ? strtolower($wpdb->_real_escape( stripslashes( trim($_GET['search']) ))) : false);
    1296     $where = ($w ? "WHERE LOWER(lastname) LIKE '%{$w}%' ".
    1297                       "OR LOWER(firstname) LIKE '%{$w}%' ".
    1298                       "OR LOWER(department) LIKE '%{$w}%' ".
    1299                       "OR LOWER(email) LIKE '%{$w}%'" : "");
    1300     $nonstd = getNonstandardRows(1); //add nonstandard rows to search
    1301     if($w && !empty($nonstd)) foreach($nonstd as $k=>$v) $where.= " OR LOWER({$k}) LIKE '%{$w}%' ";
    1302    
    1303     //query
    1304     $q =   "SELECT * FROM {$staffdb} {$where} ORDER BY {$sort} {$dir}";
    1305     $staff = $wpdb->get_results($q, ARRAY_A);
     1286    $s =    $_GET['s'] = (isset($_GET['s']) && in_array(trim($_GET['s']),array("last","first","dept","email","last-","first-","dept-","email-")) ? (string) trim($_GET['s']) : "last");
     1287    $sort = $sorts[str_replace("-","",$s)];
     1288    $dir =  (strstr($s,"-")?"DESC":"ASC");
     1289
     1290   
     1291    //handle search (use mb_strtolower, where available)
     1292    if(isset($_GET['search']) && (string) trim($_GET['search'])!=""){
     1293       
     1294        $w = (function_exists('mb_strtolower') ?
     1295                mb_strtolower(  sanitize_text_field($_GET['search']),'utf8') :
     1296                strtolower(     sanitize_text_field($_GET['search'])));
     1297        $ws = '%'.$wpdb->esc_like($w).'%';
     1298        $where = "WHERE LOWER(lastname)     LIKE %s OR
     1299                        LOWER(firstname)    LIKE %s OR
     1300                        LOWER(department)   LIKE %s OR
     1301                        LOWER(email)        LIKE %s";
     1302        $params = array($ws,$ws,$ws,$ws);
     1303       
     1304        //add nonstandard rows to search
     1305        $nonstd = getNonstandardRows(1);
     1306        if(!empty($nonstd)){
     1307            foreach($nonstd as $k=>$v){
     1308                $where.= " OR LOWER({$k}) LIKE %s ";
     1309                $params[] = $ws;
     1310            }
     1311        }
     1312       
     1313    } else {
     1314        $w = false;
     1315        $where = "";
     1316        $params = array();
     1317    }
     1318
     1319    //build query
     1320    $q =        "SELECT * FROM {$staffdb} {$where} ORDER BY {$sort} {$dir}"; //echo $q;
     1321    $sql =      $wpdb->prepare($q,$params);
     1322    $staff =    $wpdb->get_results($sql, ARRAY_A);                                          //myprint_r($staff);
    13061323
    13071324    //build the output
Note: See TracChangeset for help on using the changeset viewer.