Você está na página 1de 6

SQL Injection

Many web developers are unaware of how SQL queries can be tampered with, and ass
ume that an SQL query is a trusted command. It means that SQL queries are able t
o circumvent access controls, thereby bypassing standard authentication and auth
orization checks, and sometimes SQL queries even may allow access to host operat
ing system level commands.
Direct SQL Command Injection is a technique where an attacker creates or alters
existing SQL commands to expose hidden data, or to override valuable ones, or ev
en to execute dangerous system level commands on the database host. This is acco
mplished by the application taking user input and combining it with static param
eters to build an SQL query. The following examples are based on true stories, u
nfortunately.
Owing to the lack of input validation and connecting to the database on behalf o
f a superuser or the one who can create users, the attacker may create a superus
er in your database.
Example #1 Splitting the result set into pages ... and making superusers (Postgr
eSQL)
<?php
$offset = $argv[0]; // beware, no input validation!
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;"
;
$result = pg_query($conn, $query);
?>
Normal users click on the 'next', 'prev' links where the $offset is encoded into
the URL. The script expects that the incoming $offset is a decimal number. Howe
ver, what if someone tries to break in by appending a urlencode()'d form of the
following to the URL
0;
insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
select 'crack', usesysid, 't','t','crack'
from pg_shadow where usename='postgres';
--
If it happened, then the script would present a superuser access to him. Note th
at 0; is to supply a valid offset to the original query and to terminate it.
Note:
It is common technique to force the SQL parser to ignore the rest of the que
ry written by the developer with -- which is the comment sign in SQL.
A feasible way to gain passwords is to circumvent your search result pages. The
only thing the attacker needs to do is to see if there are any submitted variabl
es used in SQL statements which are not handled properly. These filters can be s
et commonly in a preceding form to customize WHERE, ORDER BY, LIMIT and OFFSET c
lauses in SELECT statements. If your database supports the UNION construct, the
attacker may try to append an entire query to the original one to list passwords
from an arbitrary table. Using encrypted password fields is strongly encouraged
.
Example #2 Listing out articles ... and some passwords (any database server)
<?php
$query = "SELECT id, name, inserted, size FROM products
WHERE size = '$size'
ORDER BY $order LIMIT $limit, $offset;";
$result = odbc_exec($conn, $query);
?>
The static part of the query can be combined with another SELECT statement which
reveals all passwords:
'
union select '1', concat(uname||'-'||passwd) as name, '1971-01-01', '0' from use
rtable;
--
If this query (playing with the ' and --) were assigned to one of the variables
used in $query, the query beast awakened.
SQL UPDATE's are also susceptible to attack. These queries are also threatened b
y chopping and appending an entirely new query to it. But the attacker might fid
dle with the SET clause. In this case some schema information must be possessed
to manipulate the query successfully. This can be acquired by examining the form
variable names, or just simply brute forcing. There are not so many naming conv
entions for fields storing passwords or usernames.
Example #3 From resetting a password ... to gaining more privileges (any databas
e server)
<?php
$query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
?>
But a malicious user sumbits the value ' or uid like'%admin%'; -- to $uid to cha
nge the admin's password, or simply sets $pwd to "hehehe', admin='yes', trusted=
100 " (with a trailing space) to gain more privileges. Then, the query will be t
wisted:
<?php
// $uid == ' or uid like'%admin%'; --
$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --"
;
// $pwd == "hehehe', admin='yes', trusted=100 "
$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
...;";
?>
A frightening example how operating system level commands can be accessed on som
e database hosts.
Example #4 Attacking the database hosts operating system (MSSQL Server)
<?php
$query = "SELECT * FROM products WHERE id LIKE '%$prod%'";
$result = mssql_query($query);
?>
If attacker submits the value a%' exec master..xp_cmdshell 'net user test testpa
ss /ADD' -- to $prod, then the $query will be:
<?php
$query = "SELECT * FROM products
WHERE id LIKE '%a%'
exec master..xp_cmdshell 'net user test testpass /ADD'--";
$result = mssql_query($query);
?>
MSSQL Server executes the SQL statements in the batch including a command to add
a new user to the local accounts database. If this application were running as
sa and the MSSQLSERVER service is running with sufficient privileges, the attack
er would now have an account with which to access this machine.
Note:
Some of the examples above is tied to a specific database server. This does
not mean that a similar attack is impossible against other products. Your databa
se server may be similarly vulnerable in another manner.
Avoiding techniques
You may plead that the attacker must possess a piece of information about the da
tabase schema in most examples. You are right, but you never know when and how i
t can be taken out, and if it happens, your database may be exposed. If you are
using an open source, or publicly available database handling package, which may
belong to a content management system or forum, the intruders easily produce a
copy of a piece of your code. It may be also a security risk if it is a poorly d
esigned one.
These attacks are mainly based on exploiting the code not being written with sec
urity in mind. Never trust any kind of input, especially that which comes from t
he client side, even though it comes from a select box, a hidden input field or
a cookie. The first example shows that such a blameless query can cause disaster
s.
* Never connect to the database as a superuser or as the database owner. Use
always customized users with very limited privileges.
* Check if the given input has the expected data type. PHP has a wide range
of input validating functions, from the simplest ones found in Variable Function
s and in Character Type Functions (e.g. is_numeric(), ctype_digit() respectively
) and onwards to the Perl compatible Regular Expressions support.
*
If the application waits for numerical input, consider verifying data with
is_numeric(), or silently change its type using settype(), or use its numeric r
epresentation by sprintf().
Example #5 A more secure way to compose a query for paging
<?php
settype($offset, 'integer');
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $off
set;";
// please note %d in the format string, using %s would be meaningless
$query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFF
SET %d;",
$offset);
?>
* Quote each non numeric user supplied value that is passed to the database
with the database-specific string escape function (e.g. mysql_real_escape_string
(), sqlite_escape_string(), etc.). If a database-specific string escape mechanis
m is not available, the addslashes() and str_replace() functions may be useful (
depending on database type). See the first example. As the example shows, adding
quotes to the static part of the query is not enough, making this query easily
crackable.
* Do not print out any database specific information, especially about the s
chema, by fair means or foul. See also Error Reporting and Error Handling and Lo
gging Functions.
* You may use stored procedures and previously defined cursors to abstract d
ata access so that users do not directly access tables or views, but this soluti
on has another impacts.
Besides these, you benefit from logging queries either within your script or by
the database itself, if it supports logging. Obviously, the logging is unable to
prevent any harmful attempt, but it can be helpful to trace back which applicat
ion has been circumvented. The log is not useful by itself, but through the info
rmation it contains. More detail is generally better than less.

Error Reporting> <Encrypted Storage Model Last updated: Fri, 25 Feb 2011
add a note add a note User Contributed Notes SQL Injection
kirby4 at live dot ca 19-Feb-2011 10:35
A good way to counter SQL injection for queries of type SELECT is use hash funct
ion on data by PHP and the database server.
For example, it is possible to use the MySQL function MD5 () to produce a hash o
f data-server side , and the equivalent function in php web-server side.
<?php
$login = mysql_query("select f_uname, f_passwd from t_user where MD5(f_uname) =
'".md5($uname)."' and MD5(f_passwd)='".md5($passwd)."'");
?>
Thus, the injected requests will be crushed and it will become much more difficu
lt to obtain data in the database. Use both sides of the hash result in a compar
ison of hash, not the execution of the injected queries.
Unfortunately, it probably does not work with other types of queries.
smunday at visionaryweb dot com 17-Dec-2010 10:58
Another suggestion would be to build a series of DB procedures / functions that
you give the DB user access to to manipulate or select data. That way, all input
would run through this exposed interface and all parameters are forced to be ty
pecast (or rejected).
Anonymous 27-Sep-2010 04:16
Pangolin is an automatic SQL injection penetration testing tool developed by NOS
EC.
Its goal is to detect and take advantage of SQL injection vulnerabilities on web
applications. Once it detects one or more SQL injections on the target host, th
e user can choose among a variety of options to perform an extensive back-end da
tabase management system fingerprint, retrieve DBMS session user and database, e
numerate users, password hashes, privileges, databases, dump entire or user"s sp
ecific DBMS tables/columns, run his own SQL statement, read specific files on th
e file system and more.
wang dot liang dot com at gmail dot com 11-Mar-2010 11:11
another way to stop sql injection when you odbc_*: create two users,
one has only select permission,
the other has only delete, update, and insert permission,
so you can use select-only user to call odbc_exec while you don't have to check
the sql injection; and you use d/u/i only user to update database by calling odb
c_prepare and odbc_execute.
fyrye 06-Aug-2009 10:59
Another way to prevent SQL injections as opposed to binary, is to use URL Encodi
ng or Hex Encoding.
I haven't seen a complete example of stopping SQL Injections, most refer to use
the mysql_real_escape_string function or param statements.
Several examples at http://en.wikipedia.org/wiki/SQL_injection
Which will stop \x00, \n, \r, \, ', " and \x1a based attacks.
Alot depends on your SQL query structure, though vector level attacks are still
viable.
Other than that build your own regex replacement to protect specific queries tha
t could alter or compromise your database/results for specific sections of your
processing pages.
Also use unique table and field names. Not just putting _ infront of them...
Example, don't store User/s or Customer/s information in a table named the same.
And NEVER use the same form field names for database field names.
bendikt [at] armed [dot] nu 27-Jul-2009 02:31
i just played around with the array_walk function.
It suddenly struck me that almost all super globals are arrays.
So what i discovered was that i can apply the array_walk function to the super g
lobals. Doing so you automatically run a function call through the super globals
With this piece of code i wrote you should be able to secure most of you input d
ata.
<?php
class secure
{
function secureSuperGlobalGET(&$value, $key)
{
$_GET[$key] = htmlspecialchars(stripslashes($_GET[$key]));
$_GET[$key] = str_ireplace("script", "blocked", $_GET[$key]);
$_GET[$key] = mysql_escape_string($_GET[$key]);
return $_GET[$key];
}
function secureSuperGlobalPOST(&$value, $key)
{
$_POST[$key] = htmlspecialchars(stripslashes($_POST[$key]));
$_POST[$key] = str_ireplace("script", "blocked", $_POST[$key]);
$_POST[$key] = mysql_escape_string($_POST[$key]);
return $_POST[$key];
}
function secureGlobals()
{
array_walk($_GET, array($this, 'secureSuperGlobalGET'));
array_walk($_POST, array($this, 'secureSuperGlobalPOST'));
}
}
?>
Note that you can modify this in anyway to suit your needs.
The Script has been tested.
Quietust 03-Jun-2009 12:23
An anonymous comment below suggests using PEAR with prepare() / execute() - thou
gh it was posted 3 years ago, it is still true today, though it's even easier no
w since PDO is included in most distributions. For SET/WHERE clauses and INSERT
statements, just prepare the query with question marks in place of the dynamic p
arameters, bind each value in, then execute it, and it'll do all of the escaping
for you, rendering the query immune to injection. Dynamic substitution of ORDER
BY or LIMIT clauses has to be done the old fashioned way, though, so you still
need to be careful with those.
Even without PDO, if you're using Postgres, you've already got the means to use
parameterized queries, and if you're using MySQL, you simply need to ignore the
outdated "mysql" extension and use "mysqli" instead.
fOV 12-Nov-2008 12:53
The best prevention is to deactivate master..xp_cmdshell.
Run in isql the command `sp_configure 'xp_cmdshell''
If the value for "config value" is 1 then make in the isql
`sp_configure 'xp_cmdshell',0'.
If you want see the options from your mssql-Server make
`sp_configure 'show advanced options',1'
and then `sp_configure'
jaimthorn at yahoo dot com 13-Oct-2008 09:32
dark dot avenger at email dot cz wrote:
"I think that easy way to protect against SQL injection is to convert inputted d
ata into binary format, so that whatever input is, in sql query it will consist
only of 1s and 0s."
Unless there is a 1-to-1 correspondence between your inputted data and the chara
cters in your 'binary' format, a SELECT query wouldn't work anymore. Not a bina
ry format, but it makes my point: MIME encoding the text 'Dark Avenger' results
in 'RGFyayBBdmVuZ2Vy'. If I wanted to look up anyone with 'Avenger' in his/her
name, then 'Avenger' would be encoded as 'QXZlbmdlcg==' which clearly wouldn't r
esult in a hit on 'RGFyayBBdmVuZ2Vy'.
If there IS a 1-to-1 correspondence, then EITHER your solution only makes it a b
it harder to perform a SQL injection (a hacker would have to figure out what map
ping was used between the text and the 'binary' format), OR you've come up with
simply another way to escaping your data. Either isn't a terribly good solution
to the SQL injection problem.
dark dot avenger at email dot cz 14-Aug-2008 08:09
I think that easy way to protect against SQL injection is to convert inputted da
ta into binary format, so that whatever input is, in sql query it will consist o
nly of 1s and 0s.
valerylourie at gmail dot com 15-Apr-2008 07:23
Note that PHP 5 introduced filters that you can use for untrusted user input:
http://us.php.net/manual/en/intro.filter.php
ctm at etheon dot net 01-Aug-2006 03:39
This is a very helpful document from the MySQL site (in .pdf format) :
http://dev.mysql.com/tech-resources/articles/
guide-to-php-security-ch3.pdf
17-Mar-2006 05:48
If you use the PEAR package and prepare() / execute() your queries,
you will hardly have to worry about any of this. Of course, it's still
a good idea to make sure you're putting valid data in your database...

Você também pode gostar