This question already has answers here:
Insert text with single quotes in PostgreSQL
(8 answers)
Closed 7 years ago.
When I am trying to find all records in details table which have Linux present in the array column operating_systems.
Query select * from details where 'Linux' = ANY(operating_systems); works perfectly and returns all records which have Linux in operating_systems column.
But if I want to get all records where I don't know is present in operating_systems I am unable to form a correct query.
Query select * from details where 'I don\'t know' = ANY(operating_systems); does not escape single quotes and takes it literally, resulting in an incomplete query.
Found that single quotes can be escaped by adding another single quote before it. So select count(*) from details where 'I don''t know' = ANY(operating_systems); works.
This is acceptable for ad-hoc queries, or queries where a data literal is hard coded.
It's absolutely not OK if the string comes from an application user. Do not do this. See http://bobby-tables.com/ for why.
Use parameterised queries (often incorrectly called prepared statements, though they're not quite the same thing). Exactly how to do that depends on your programming language and client, which you have not mentioned, but it usually involves "preparing" a statement then executing it with parameters.
Found that single quotes can be escaped by adding another single quote before it. So select count(*) from details where 'I don''t know' = ANY(operating_systems); works.
Related
This question already has answers here:
Android SQLite Date query issue, cannot compare records between 2 dates
(3 answers)
Closed 4 hours ago.
I've stored fields with the local date(Shamsi) in my SQLite DB. I want to get a list of DB where its date is between date_1 and date_2. It works when using a const value as below:
db!.rawQuery(("SELECT * FROM $tblVisit WHERE $colVisitDate BETWEEN '1401-10-01' AND '1401-12-29' ")
but I like to use variables from function input instead of const value. How can I write something like follows:
String? date_1, String? date_2
db!.rawQuery("SELECT * FROM $tblVisit WHERE $colVisitDate BETWEEN $date_1 AND $date_2 ")
Now, the last statement returns no list but the first one works well.
Thanks
Text/String values must be enclosed in single quotes so
db!.rawQuery("SELECT * FROM $tblVisit WHERE $colVisitDate BETWEEN '$date_1' AND '$date_2' ")
Otherwise the dates, as they only contain numerics and operators, are considered an expression so 1401-10-01 becomes 1390 and thus unusual results.
However, this is susceptible to SQL injection and thus it is considered better practice by the SQL Injection Police to use parameter binding. That is, code ? placeholders instead of the values, e.g. BETWEEN ? AND ? and then use the selectionArgs parameter of rawQuery for the 2 date values (note that you cannot bind component names and keywords).
See rawQuery
This question already has answers here:
"ERROR: cached plan must not change result type" when mixing DDL with SELECT via JDBC
(2 answers)
Closed 5 years ago.
Let's say I want to add a column in my table. If I add column in DB without restarting the application, my application starts failing with "cached plan must not change result type" because return type changes for queries doing wildcard select after this column addition.
jdbc postgres driver automatically creates prepared statement after a certain threshold, default threshold value is 5.
Either I can disable it by setting prepareThreshold to 0 which is bad since I'm losing on the benefits of prepared statement optimization driver was doing for me.
Or I'll have to change all my SQL statements to specify the exact list of columns it will operate upon. So, writing statements like "SELECT * FROM TABLE" is not feasible.
Is there any other approach to solve this problem?
It is a bad habit to use * in SQL queries (except in certain cases like count(*)) for the reason that queries can suddenly fail or behave differently when a column is added.
If you really want that, you can catch the exception, close the prepared statement and recreate a new one with the same query string.
I just saw this come up in our request logs. What were they trying to achieve?
The full request string is:
properties?page=2side1111111111111 UNION SELECT CHAR(45,120,49,45,81,45),CHAR(45,120,50,45,81,45),CHAR(45,120,51,45,81,45),CHAR(45,120,52,45,81,45),CHAR(45,120,53,45,81,45),CHAR(45,120,54,45,81,45),CHAR(45,120,55,45,81,45),CHAR(45,120,56,45,81,45),CHAR(45,120,57,45,81,45),CHAR(45,120,49,48,45,81,45),CHAR(45,120,49,49,45,81,45),CHAR(45,120,49,50,45,81,45),CHAR(45,120,49,51,45,81,45),CHAR(45,120,49,52,45,81,45),CHAR(45,120,49,53,45,81,45),CHAR(45,120,49,54,45,81,45) -- /*
Edit: As a google search didn't return anything useful I wanted to ask the question for people who encounter the same thing.
This is just a test for injection. If an attacker can see xQs in the output then they'll know injection is possible.
There is no "risk" from this particular query.
A developer should pay no attention to whatever injection mechanisms, formats or meanings - these are none of his business.
There is only one cause for for all the infinite number of injections - an improperly formatted query. As long as your queries are properly formatted then SQL injections are not possible. Focus on your queries rather than methods of SQL injection.
The Char() function interprets each value as an integer and returns a string based on given the characters by the code values of those integers. With Char(), NULL values are skipped. The function is used within Microsoft SQL Server, Sybase, and MySQL, while CHR() is used by RDBMSs.
SQL's Char() function comes in handy when (for example) addslashes() for PHP is used as a precautionary measure within the SQL query. Using Char() removes the need of quotation marks within the injected query.
An example of some PHP code vulnerable to an SQL injection using Char() would look similar to the following:
$uname = addslashes( $_GET['id'] );
$query = 'SELECT username FROM users WHERE id = ' . $id;
While addslashes() has been used, the script fails properly sanitize the input as there is no trailing quotation mark. This could be exploited using the following SQL injection string to load the /etc/passwd file:
Source: http://hakipedia.com/index.php/SQL_Injection#Char.28.29
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 13 years ago.
So, I read article about SQL injection and there was an example:
SELECT * FROM table_name WHERE smth = 'x';
UPDATE table_name SET smth ='smth#email.addr' WHERE user = 'admin';
Why it doesn't work? Or it is an old article and nowadays this way is nonsense? So how hackers update mysql then?
Thanks.
Most sites nowadays are using parametized SQL -- not inline SQL. The situation would occur above if for instance, there was parsed, inline SQL, similar to the following:
Non-Parameterized Pseudo
string sql = "SELECT * FROM table_name WHERE smth='" + UserInput + "'";
ExecuteSql(sql);
...where UserInput defines an element on the website.
Instead of adding valid data to the UserInput field, you add,
UserInput = '';DROP table_name;
...you would actually be adding new logic to the end of the query, resulting in a malicious use of the system.
Parametized statements eliminate the possibility of SQL injection, since you can't modify the structure of the query by inserting logic into the signature.
If you attempted to set the UserInput field to a malacious query, but the site used parameters in the statement, then you would be out of luck.
Parameterized Pseudo:
Adapter proc;
proc.StoredProcedure = "GetUserNames"
proc.AddParameter("#USER",UserInput);
proc.Execute();
...as #USER is now equal to the literal "'\;DROP table_name;", which the SQL will treat as a regular ol' parameter.
It depends on how you execute the code above.
Many code languages have dedicated database communication classes which you can supply with sql parameters instead of concatenated strings.
The risk in SQL injection is forgetting to escape some of the user input in your query thus allowing malformed queries to be executed.
The idea behind SQL injection attacks is this:
I have a website that let's users searching for information about animals. The user types in the name of the animal, then it runs:
select * from animals where name = '$[what the user typed in]';
so if they type in sheep, the query becomes:
select * from animals where name = 'sheep';
However, what if they type in: `sheep'; drop table animals'? If I simply copy what they typed into the query and run it, I'll run:
select * from animals where name = 'sheep'; drop table animals;
which would be bad.
This kinds of attacks can still happen if the person setting up the website and database isn't careful to look for and clean up any SQL that is in something the user enters.
DB 101 warns ardently about SQL injection, so most developers these days are aware of it and prevent it. This is most often done by using some sort of prepared statement where your parameters are injected via a mechanism that prevents arbitrary SQL from being executed. Lazy programming can still lead to vulnerabilities and they're out there, for sure, but blind dynamic SQL building is rarer and rarer.
SQL injection attacks are possible when you have query "templates" and you require user input to fill in some of the query. For example, you might have a PHP script that does something like this:
<?php
$smth_value = $_POST["smth"]; // some form field
$smth_user = $_POST["user"]; // some other form field
$smth_email = $_POST["email"]; // yet another form field
$sql1 = "SELECT * FROM table_name WHERE smth = '".$smth_value."'";
$sql2 = "UPDATE table_name SET smth ='".$smth_email."' WHERE user = '".$smth_user."'";
mysql_query($sql1);
mysql_query($sql2);
?>
If an individual knew the structure of my table (or figured it out somehow), they could "inject" SQL into my queries by putting SQL text into the form fields that results in my SQL variable strings looking like two valid queries separated by a semicolon. For example, someone could type into the "smth" form field something like:
';DELETE FROM table_name WHERE 1=1 OR smth='
and then $sql1 would end up looking like:
SELECT * FROM table_name WHERE smth = '';DELETE FROM table_name WHERE 1=1 OR smth=''
... and there goes all the data from table_name.
That's why there are functions in PHP like mysql_escape_string to help guard strings from these kind of attacks. If you know a variable is supposed to be a number, cast it to a number. If you have text, wrap it in a string escaping function. That's the basic idea on how to defend.
I have some code which utilizes parameterized queries to prevent against injection, but I also need to be able to dynamically construct the query regardless of the structure of the table. What is the proper way to do this?
Here's an example, say I have a table with columns Name, Address, Telephone. I have a web page where I run Show Columns and populate a select drop-down with them as options.
Next, I have a textbox called Search. This textbox is used as the parameter.
Currently my code looks something like this:
result = pquery('SELECT * FROM contacts WHERE `' + escape(column) + '`=?', search);
I get an icky feeling from it though. The reason I'm using parameterized queries is to avoid using escape. Also, escape is likely not designed for escaping column names.
How can I make sure this works the way I intend?
Edit:
The reason I require dynamic queries is that the schema is user-configurable, and I will not be around to fix anything hard-coded.
Instead of passing the column names, just pass an identifier that you code will translate to a column name using a hardcoded table. This means you don't need to worry about malicious data being passed, since all the data is either translated legally, or is known to be invalid. Psudoish code:
#columns = qw/Name Address Telephone/;
if ($columns[$param]) {
$query = "select * from contacts where $columns[$param] = ?";
} else {
die "Invalid column!";
}
run_sql($query, $search);
The trick is to be confident in your escaping and validating routines. I use my own SQL escape function that is overloaded for literals of different types. Nowhere do I insert expressions (as opposed to quoted literal values) directly from user input.
Still, it can be done, I recommend a separate — and strict — function for validating the column name. Allow it to accept only a single identifier, something like
/^\w[\w\d_]*$/
You'll have to rely on assumptions you can make about your own column names.
I use ADO.NET and the use of SQL Commands and SQLParameters to those commands which take care of the Escape problem. So if you are in a Microsoft-tool environment as well, I can say that I use this very sucesfully to build dynamic SQL and yet protect my parameters
best of luck
Make the column based on the results of another query to a table that enumerates the possible schema values. In that second query you can hardcode the select to the column name that is used to define the schema. if no rows are returned then the entered column is invalid.
In standard SQL, you enclose delimited identifiers in double quotes. This means that:
SELECT * FROM "SomeTable" WHERE "SomeColumn" = ?
will select from a table called SomeTable with the shown capitalization (not a case-converted version of the name), and will apply a condition to a column called SomeColumn with the shown capitalization.
Of itself, that's not very helpful, but...if you can apply the escape() technique with double quotes to the names entered via your web form, then you can build up your query reasonably confidently.
Of course, you said you wanted to avoid using escape - and indeed you don't have to use it on the parameters where you provide the ? place-holders. But where you are putting user-provided data into the query, you need to protect yourself from malicious people.
Different DBMS have different ways of providing delimited identifiers. MS SQL Server, for instance, seems to use square brackets [SomeTable] instead of double quotes.
Column names in some databases can contain spaces, which mean you'd have to quote the column name, but if your database contains no such columns, just run the column name through a regular expression or some sort of check before splicing into the SQL:
if ( $column !~ /^\w+$/ ) {
die "Bad column name [$column]";
}