Skip to:
Content

BuddyPress.org

Changeset 7015


Ignore:
Timestamp:
05/07/2013 11:45:58 PM (11 years ago)
Author:
boonebgorges
Message:

Audit of parameter sanitization in Groups and Core database classes

  • Uses wp_parse_id_list() to sanitize parameters of integer arrays
  • Implements a more consistent approach to LIKE clause sanitization

Props johnjamesjacoby

Introduces a number of unit tests for the Groups and Core database classes, to
accompany the security hardening.

See #4989

Location:
trunk
Files:
2 added
1 deleted
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/bp-core/bp-core-classes.php

    r7008 r7015  
    839839
    840840        if ( !empty( $search_terms ) && bp_is_active( 'xprofile' ) ) {
    841             $search_terms             = like_escape( $wpdb->escape( $search_terms ) );
     841            $search_terms             = esc_sql( like_escape( trim( $search_terms ) ) );
    842842            $sql['where_searchterms'] = "AND spd.value LIKE '%%$search_terms%%'";
    843843        }
     
    956956        }
    957957
    958         $letter     = like_escape( $wpdb->escape( $letter ) );
     958        $letter     = esc_sql( like_escape( trim( $letter ) ) );
    959959        $status_sql = bp_core_get_status_sql( 'u.' );
    960960
    961         $exclude_sql = ( !empty( $exclude ) ) ? " AND u.ID NOT IN ({$exclude})" : "";
     961        if ( !empty( $exclude ) ) {
     962            $exclude     = wp_parse_id_list( $r['exclude'] );
     963            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
     964            $exclude_sql = " AND u.id NOT IN ({$exclude})";
     965        } else {
     966            $exclude_sql = '';
     967        }
    962968
    963969        $total_users_sql = apply_filters( 'bp_core_users_by_letter_count_sql', $wpdb->prepare( "SELECT COUNT(DISTINCT u.ID) FROM {$wpdb->users} u LEFT JOIN {$bp->profile->table_name_data} pd ON u.ID = pd.user_id LEFT JOIN {$bp->profile->table_name_fields} pf ON pd.field_id = pf.id WHERE {$status_sql} AND pf.name = %s {$exclude_sql} AND pd.value LIKE '{$letter}%%'  ORDER BY pd.value ASC", bp_xprofile_fullname_field_name() ) );
     
    10481054        $pag_sql  = $limit && $page ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * intval( $limit ) ), intval( $limit ) ) : '';
    10491055
    1050         $search_terms = like_escape( $wpdb->escape( $search_terms ) );
     1056        $search_terms = esc_sql( like_escape( trim( $search_terms ) ) );
    10511057        $status_sql   = bp_core_get_status_sql( 'u.' );
    10521058
  • trunk/bp-groups/bp-groups-classes.php

    r6997 r7015  
    222222            $user_id = bp_displayed_user_id();
    223223
    224         $filter = like_escape( $wpdb->escape( $filter ) );
     224        $filter = esc_sql( like_escape( $filter ) );
    225225
    226226        if ( !empty( $limit ) && !empty( $page ) )
     
    241241    }
    242242
     243    /**
     244     * @todo Deprecate in favor of get()
     245     */
    243246    function search_groups( $filter, $limit = null, $page = null, $sort_by = false, $order = false ) {
    244247        global $wpdb, $bp;
    245248
    246         $filter = like_escape( $wpdb->escape( $filter ) );
     249        $filter = esc_sql( like_escape( $filter ) );
    247250
    248251        if ( !empty( $limit ) && !empty( $page ) )
     
    250253
    251254        if ( !empty( $sort_by ) && !empty( $order ) ) {
    252             $sort_by   = $wpdb->escape( $sort_by );
    253             $order     = $wpdb->escape( $order );
    254             $order_sql = "ORDER BY $sort_by $order";
     255            $sort_by   = esc_sql( $sort_by );
     256            $order     = esc_sql( $order );
     257            $order_sql = "ORDER BY {$sort_by} {$order}";
    255258        }
    256259
     
    365368
    366369        if ( !empty( $search_terms ) ) {
    367             $search_terms = like_escape( $wpdb->escape( $search_terms ) );
     370            $search_terms = esc_sql( like_escape( $search_terms ) );
    368371            $sql['search'] = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
    369372        }
     
    384387
    385388        if ( !empty( $include ) ) {
    386             if ( is_array( $include ) )
    387                 $include = implode( ',', $include );
    388 
    389             $include = $wpdb->escape( $include );
     389            $include        = wp_parse_id_list( $r['include'] );
     390            $include        = $wpdb->escape( implode( ',', $include ) );
    390391            $sql['include'] = " AND g.id IN ({$include})";
    391392        }
    392393
    393394        if ( !empty( $exclude ) ) {
    394             if ( is_array( $exclude ) )
    395                 $exclude = implode( ',', $exclude );
    396 
    397             $exclude = $wpdb->escape( $exclude );
     395            $exclude        = wp_parse_id_list( $r['exclude'] );
     396            $exclude        = $wpdb->escape( implode( ',', $exclude ) );
    398397            $sql['exclude'] = " AND g.id NOT IN ({$exclude})";
    399398        }
     
    544543
    545544        if ( !empty( $search_terms ) ) {
    546             $search_terms = like_escape( $wpdb->escape( $search_terms ) );
     545            $search_terms = esc_sql( like_escape( trim( $search_terms ) ) );
    547546            $search_sql = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
    548547        }
    549548
    550549        if ( !empty( $exclude ) ) {
    551             $exclude = $wpdb->escape( $exclude );
     550            $exclude     = wp_parse_id_list( $exclude );
     551            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
    552552            $exclude_sql = " AND g.id NOT IN ({$exclude})";
    553553        }
    554554
    555555        if ( !empty( $user_id ) ) {
    556             $user_id = $wpdb->escape( $user_id );
     556            $user_id      = absint( $wpdb->escape( $user_id ) );
    557557            $paged_groups = $wpdb->get_results( "SELECT DISTINCT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bp->groups->table_name_members} m, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.topics > 0 {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql} ORDER BY f.topics DESC {$pag_sql}" );
    558558            $total_groups = $wpdb->get_var( "SELECT COUNT(DISTINCT g.id) FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_groupmeta} gm3, {$bbdb->forums} f, {$bp->groups->table_name} g WHERE g.id = gm1.group_id AND g.id = gm2.group_id AND g.id = gm3.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND (gm3.meta_key = 'forum_id' AND gm3.meta_value = f.forum_id) AND f.topics > 0 {$hidden_sql} {$search_sql} AND m.user_id = {$user_id} AND m.is_confirmed = 1 AND m.is_banned = 0 {$exclude_sql}" );
     
    585585
    586586        if ( !empty( $search_terms ) ) {
    587             $search_terms = like_escape( $wpdb->escape( $search_terms ) );
     587            $search_terms = esc_sql( like_escape( trim( $search_terms ) ) );
    588588            $search_sql = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
    589589        }
    590590
    591591        if ( !empty( $exclude ) ) {
    592             $exclude = $wpdb->escape( $exclude );
     592            $exclude     = wp_parse_id_list( $exclude );
     593            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
    593594            $exclude_sql = " AND g.id NOT IN ({$exclude})";
    594595        }
     
    627628
    628629        if ( !empty( $exclude ) ) {
    629             $exclude = $wpdb->escape( $exclude );
     630            $exclude     = wp_parse_id_list( $exclude );
     631            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
    630632            $exclude_sql = " AND g.id NOT IN ({$exclude})";
    631633        }
     
    634636            $hidden_sql = " AND status != 'hidden'";
    635637
    636         $letter = like_escape( $wpdb->escape( $letter ) );
     638        $letter = esc_sql( like_escape( $letter ) );
    637639
    638640        if ( !empty( $limit ) && !empty( $page ) ) {
     
    666668
    667669        if ( !empty( $search_terms ) ) {
    668             $search_terms = like_escape( $wpdb->escape( $search_terms ) );
     670            $search_terms = esc_sql( like_escape( trim( $search_terms ) ) );
    669671            $search_sql = " AND ( g.name LIKE '%%{$search_terms}%%' OR g.description LIKE '%%{$search_terms}%%' )";
    670672        }
    671673
    672674        if ( !empty( $exclude ) ) {
    673             $exclude = $wpdb->escape( $exclude );
     675            $exclude     = wp_parse_id_list( $exclude );
     676            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
    674677            $exclude_sql = " AND g.id NOT IN ({$exclude})";
    675678        }
     
    699702            return $paged_groups;
    700703
     704        // Sanitize group IDs
     705        $group_ids = wp_parse_id_list( $group_ids );
     706        $group_ids = implode( ',', $group_ids );
     707
    701708        // Fetch the logged in users status within each group
    702709        $user_status = $wpdb->get_col( $wpdb->prepare( "SELECT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND group_id IN ( {$group_ids} ) AND is_confirmed = 1 AND is_banned = 0", bp_loggedin_user_id() ) );
     
    800807        $sql['where']  = "WHERE gm.meta_key = 'forum_id' {$status_sql} AND t.topic_status = '0' AND t.topic_sticky != '2'";
    801808
    802         if ( $search_terms ) {
    803             $st = like_escape( $search_terms );
     809        if ( !empty( $search_terms ) ) {
     810            $st = esc_sql( like_escape( $search_terms ) );
    804811            $sql['where'] .= " AND (  t.topic_title LIKE '%{$st}%' )";
    805812        }
     
    10621069
    10631070        if ( !empty( $filter ) ) {
    1064             $filter = like_escape( $wpdb->escape( $filter ) );
     1071            $filter     = esc_sql( like_escape( $filter ) );
    10651072            $filter_sql = " AND ( g.name LIKE '%%{$filter}%%' OR g.description LIKE '%%{$filter}%%' )";
    10661073        }
     
    10841091
    10851092        if ( !empty( $filter ) ) {
    1086             $filter = like_escape( $wpdb->escape( $filter ) );
     1093            $filter     = esc_sql( like_escape( $filter ) );
    10871094            $filter_sql = " AND ( g.name LIKE '%%{$filter}%%' OR g.description LIKE '%%{$filter}%%' )";
    10881095        }
     
    11061113
    11071114        if ( !empty( $filter ) ) {
    1108             $filter = like_escape( $wpdb->escape( $filter ) );
     1115            $filter     = esc_sql( like_escape( trim( $filter ) ) );
    11091116            $filter_sql = " AND ( g.name LIKE '%%{$filter}%%' OR g.description LIKE '%%{$filter}%%' )";
    11101117        }
     
    11371144        $pag_sql = ( !empty( $limit ) && !empty( $page ) ) ? $wpdb->prepare( " LIMIT %d, %d", intval( ( $page - 1 ) * $limit), intval( $limit ) ) : '';
    11381145
    1139         $exclude_sql = !empty( $exclude ) ? $wpdb->prepare( " AND g.id NOT IN (%s)", $exclude ) : '';
     1146        if ( !empty( $exclude ) ) {
     1147            $exclude     = wp_parse_id_list( $exclude );
     1148            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
     1149            $exclude_sql = " AND g.id NOT IN ({$exclude})";
     1150        } else {
     1151            $exclude_sql = '';
     1152        }
    11401153
    11411154        $paged_groups = $wpdb->get_results( $wpdb->prepare( "SELECT g.*, gm1.meta_value as total_member_count, gm2.meta_value as last_activity FROM {$bp->groups->table_name_groupmeta} gm1, {$bp->groups->table_name_groupmeta} gm2, {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE g.id = m.group_id AND g.id = gm1.group_id AND g.id = gm2.group_id AND gm2.meta_key = 'last_activity' AND gm1.meta_key = 'total_member_count' AND m.is_confirmed = 0 AND m.inviter_id != 0 AND m.invite_sent = 1 AND m.user_id = %d {$exclude_sql} ORDER BY m.date_modified ASC {$pag_sql}", $user_id ) );
     
    12401253    }
    12411254
    1242     function get_random_groups( $user_id, $total_groups = 5 ) {
     1255    function get_random_groups( $user_id = 0, $total_groups = 5 ) {
    12431256        global $wpdb, $bp;
    12441257
    12451258        // If the user is logged in and viewing their random groups, we can show hidden and private groups
    12461259        if ( bp_is_my_profile() ) {
    1247             return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0 ORDER BY rand() LIMIT $total_groups", $user_id ) );
     1260            return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT group_id FROM {$bp->groups->table_name_members} WHERE user_id = %d AND is_confirmed = 1 AND is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) );
    12481261        } else {
    1249             return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT m.group_id FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 ORDER BY rand() LIMIT $total_groups", $user_id ) );
     1262            return $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT m.group_id FROM {$bp->groups->table_name_members} m, {$bp->groups->table_name} g WHERE m.group_id = g.id AND g.status != 'hidden' AND m.user_id = %d AND m.is_confirmed = 1 AND m.is_banned = 0 ORDER BY rand() LIMIT %d", $user_id, $total_groups ) );
    12501263        }
    12511264    }
     
    12921305        $exclude_sql = '';
    12931306        if ( !empty( $exclude ) ) {
    1294             $exclude = implode( ',', wp_parse_id_list( $exclude ) );
     1307            $exclude     = wp_parse_id_list( $exclude );
     1308            $exclude     = $wpdb->escape( implode( ',', $exclude ) );
    12951309            $exclude_sql = " AND m.user_id NOT IN ({$exclude})";
    12961310        }
  • trunk/bp-templates/bp-legacy/buddypress-functions.php

    r7002 r7015  
    416416    // If page and search_terms have been passed via the AJAX post request, use those.
    417417    if ( ! empty( $_POST['page'] ) && '-1' != $_POST['page'] )
    418         $qs[] = 'page=' . $_POST['page'];
     418        $qs[] = 'page=' . absint( $_POST['page'] );
    419419
    420420    $object_search_text = bp_get_search_default_text( $object );
  • trunk/bp-themes/bp-default/_inc/ajax.php

    r6740 r7015  
    125125    // If page and search_terms have been passed via the AJAX post request, use those.
    126126    if ( ! empty( $_POST['page'] ) && '-1' != $_POST['page'] )
    127         $qs[] = 'page=' . $_POST['page'];
     127        $qs[] = 'page=' . absint( $_POST['page'] );
    128128
    129129    $object_search_text = bp_get_search_default_text( $object );
  • trunk/tests/includes/testcase.php

    r6932 r7015  
    137137     * directory queries. This is a shorthand wrapper for the user factory
    138138     * create() method.
     139     *
     140     * Also set a display name
    139141     */
    140142    function create_user( $args = array() ) {
     
    151153        update_user_meta( $user_id, 'last_activity', $last_activity );
    152154
     155        if ( bp_is_active( 'xprofile' ) ) {
     156            $user = new WP_User( $user_id );
     157            xprofile_set_field_data( 1, $user_id, $user->display_name );
     158        }
     159
    153160        return $user_id;
    154161    }
Note: See TracChangeset for help on using the changeset viewer.