Go Back   vb.org Archive > vBulletin Article Depository > Read An Article > General Articles
FAQ Community Calendar Today's Posts Search

Reply
 
Thread Tools
[How To] Never Worry About SQL Injections and Queries Again
vbresults
Join Date: Apr 2009
Posts: 687

 

Show Printable Version Email this Page Subscription
vbresults vbresults is offline 03-26-2012, 10:00 PM

Why use this? Queries are normally cumbersome to write for vBulletin, and when managing a lot of queries in even a small-medium-sized, it is easy to miss sanitizing an input here or there. If you use this tool, the SQL Injection prevention is completely automatic, queries are easier to create and maintain, and blocks of code that are common among similar queries are eliminated.

What is this? This tool prevents SQL injections by placing a layer of protection between the query and database. First, it is important to note that preventing SQL injections is top priority. It takes 1 SQL Injection for someone to take over an entire forum, as history has proven time and time again. After developing a few dozen add-ons, I realized that queries are annoying to write for vB, especially with this fact in mind. I constantly found myself checking queries over and over to make sure everything was safe. It became a big problem for applications that were too small to be moved over to a PHP framework (which has tools like this built in), but too large to police each database query. This tool is intended for add-on authors or people adding custom functionality to their forums themselves.

How is this used? This tool will require only basic knowledge of strings, arrays, functions, and printf's format -- nothing specific to vBulletin. If you are already writing vBulletin queries, then you are mostly ready. How to use this is listed below.

Let's compare the common ways of executing queries versus using Extended Databases.

1. Fetch one record; we are getting the username and userid of a user with the email address we input.

vB_Database::query_first (common way)
PHP Code:
$query 'SELECT userid, username FROM ' TABLE_PREFIX 'user WHERE email = "' $vbulletin->db->escape_string($vbulletin->GPC['email']) . '"';

$user $vbulletin->db->query_first($query); 
ExtendedDatabases_Query::first (improved way)
PHP Code:
$user ExtendedDatabases_Query::first(array(
    
'query' => 'SELECT userid, username FROM %1$suser WHERE email = "%2$s"',
    
'params' => $vbulletin->GPC['email']
)); 
Both will return exactly the same thing. One will not require direct use of TABLE_PREFIX, vB_Database::escape_string, or bizarre quoting. %1$s will always be the table prefix whether params is an array or not.

2. Fetch multiple records; we are getting the usernames for each user who has a username starting with our input (e.g. we input lancer, it returns lancerforhire).

vB_Database::query_read_slave (common way)
PHP Code:
$query 'SELECT username FROM ' TABLE_PREFIX 'user WHERE username REGEXP "^' preg_quote($vbulletin->db->escape_string($vbulletin->GPC['username'])) . '"';
$resource $vbulletin->db->query_read_slave($query);
$records null;

if (!
$vbulletin->db->num_rows($resource)) {
    
// no records
}

while (
$record $vbulletin->db->fetch_array($resource)) {
    
$records[] = $record;
}

$vbulletin->db->free_result($resource); 
ExtendedDatabases_Query::read (improved way)
PHP Code:
$records ExtendedDatabases_Query::read(array(
    
'query' => 'SELECT username FROM %1$suser WHERE username REGEXP "^%2$s"',
    
'params' => preg_quote($vbulletin->GPC['username'])
));

if (!
$records) {
    
// no records

Once again, both do exactly the same thing. One is just a LOT simpler. SQL injection prevention and other vital functions are AUTOMATIC.

3. Fetch a single field from a single record; we are getting the first full username for the user who has a username starting with our input (e.g. we input lancer, it returns lancerforhire). New in 1.4!

vB_Database::query_first (common way)
PHP Code:
$query 'SELECT username FROM ' TABLE_PREFIX 'user WHERE username REGEXP "^' preg_quote($vbulletin->db->escape_string($vbulletin->GPC['username'])) . '"';

$user $vbulletin->db->query_first($query);

$username $user $user['username'] : null
ExtendedDatabases_Query::field (improved way)
PHP Code:
$username ExtendedDatabases_Query::field(array(
    
'name' => 'username',
    
'query' => 'SELECT username FROM %1$suser WHERE username REGEXP "^%2$s"',
    
'params' => preg_quote($vbulletin->GPC['username'])
)); 

4. Fetch multiple records; we are getting the username, user id, and user group id of all users whose primary groups match our input (array). New in 1.4!

vB_Database::query_read_slave (common way)
PHP Code:
$query 'SELECT username, userid, usergroupid FROM ' TABLE_PREFIX 'user
    WHERE usergroup IN (' 
explode(', '$vbulletin->GPC['usergroupids']) . ')';

$resource $vbulletin->db->query_read_slave($query);
$records null;

if (!
$vbulletin->db->num_rows($resource)) {
    
// no records
}

while (
$record $vbulletin->db->fetch_array($resource)) {
    
$records[] = $record;
}

$vbulletin->db->free_result($resource); 
ExtendedDatabases_Query::read with array sub-parameters (improved way)
PHP Code:
$records ExtendedDatabases_Query::read(array(
    
'query' => 'SELECT username, userid, usergroupid FROM %1$suser
        WHERE %2$s'
    'params' 
=> array(
        
'usergroupid' => $vbulletin->GPC['usergroupids']
    )
));

if (!
$records) {
    
// no records

---

ExtendedDatabases_Query::write is the successor to vB_Database::query_write; I do not believe this warrants another example.

---

Implement this Right Now

If you are a coder, implement this immediately. If you are not a coder, ask the developers of your installed add-ons to do it. It's very simple and has long term benefits, but if you don't do it right now, chances are you never will (unless your forum implodes).

---

How do I get this?

Download the product-extended_databases_ Xml and add it (extended_databases) as a product dependency. Yes; that's it!
Attached Files
File Type: xml product-extended_databases-1.4.xml (4.2 KB, 23 views)
Reply With Quote
  #12  
Old 08-07-2012, 02:31 AM
Chris8's Avatar
Chris8 Chris8 is offline
 
Join Date: Nov 2009
Posts: 188
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by LancerForHireLLC View Post
Download the product-extended_databases_ Xml and add it (extended_databases) as a product dependency. Yes; that's it!
I'm sorry, I' m not sure if I understood it well, the part with adding it as dependency.

To get it running I should upload it and install product-extended_databases-1.2.1.xml you've attached here and then in every mod which I would like to make sure that has strings escaped add it as dependency right into <dependencies>extended_databases</dependencies> tags. And that's it. Do I get it right?
Reply With Quote
  #13  
Old 08-11-2012, 04:58 PM
vbresults vbresults is offline
 
Join Date: Apr 2009
Posts: 687
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Quote:
Originally Posted by Chris8 View Post
I'm sorry, I' m not sure if I understood it well, the part with adding it as dependency.

To get it running I should upload it and install product-extended_databases-1.2.1.xml you've attached here and then in every mod which I would like to make sure that has strings escaped add it as dependency right into <dependencies>extended_databases</dependencies> tags. And that's it. Do I get it right?
Put vBulletin in debug mode and add the extended_databases dependency to the product there, preferably with minimum version number 1.4. After you've done this, rewrite the queries using the format above.

---

On another note, 1.4 has been released!
Reply With Quote
  #14  
Old 02-25-2013, 05:09 PM
Dorgham's Avatar
Dorgham Dorgham is offline
 
Join Date: May 2012
Location: Egypt
Posts: 69
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I'm a big fan of your posts
And learn lots and lots
Thank you
Reply With Quote
Благодарность от:
vbresults
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 09:28 AM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2024, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.03979 seconds
  • Memory Usage 2,300KB
  • Queries Executed 21 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (8)bbcode_php
  • (2)bbcode_quote
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)modsystem_article
  • (1)navbar
  • (4)navbar_link
  • (120)option
  • (1)pagenav
  • (1)pagenav_curpage
  • (1)pagenav_pagelink
  • (4)post_thanks_box
  • (2)post_thanks_box_bit
  • (4)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (2)post_thanks_postbit
  • (4)post_thanks_postbit_info
  • (3)postbit
  • (1)postbit_attachment
  • (4)postbit_onlinestatus
  • (4)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_postinfo_query
  • fetch_postinfo
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • fetch_musername
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • post_thanks_function_fetch_thanks_bit_start
  • post_thanks_function_show_thanks_date_start
  • post_thanks_function_show_thanks_date_end
  • post_thanks_function_fetch_thanks_bit_end
  • post_thanks_function_fetch_post_thanks_template_start
  • post_thanks_function_fetch_post_thanks_template_end
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_attachment
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • pagenav_page
  • pagenav_complete
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete