Parameterized SQL statements vs. very simple method - sql

When I started to write the first SQL-Statements in my programs I felt quite comfortable with protecting myself against SQL-Injection with a very simple method that a colleague showed me. It replaced all single quotes with two single quotes.
So for example there is a searchfield in which you can enter a customername to search in the customertable. If you would enter
Peter's Barbershop
The SELECT Statement would look like
SELECT *
FROM Customers
WHERE Customername = 'Peter''s Barbershop'
If now an attacker would insert this:
';DROP TABLE FOO; --
The statement would look like:
SELECT *
FROM Customers
WHERE Customername = ''';DROP TABLE FOO;--'
It would not drop any table, but search the customertable for the customername ';DROP TABLE FOO;-- which, I suppose, won't be found ;-)
Now after a while of writing statements and protecting myself against SQL-Injection with this method, I read that many developers use parameterized statements, but I never read an article where "our" method was used. So definitely there is a good reason for it.
What scenarios would parameterized statements cover but our method doesn't? What are the advantages of parameterized statements compared to our method?
Thanks
Philipp

The parametrized queries has more proc than the defence to sql-injection.
It solves problem with date & time formating & parsing.
You can prepare execution plan for parametrized query.
The sql-injection protection.
I can't remember now for another pros :).
However the way "double every quotes" has problem with fields with limited character length.
For example:
The page has box for "nickname" which can be 10 character long.
The user insert "Don't care" - the exact 10 characters.
Now if you double the quotes, the value has 11 characters and the database will "cut" it, and you got another value in db than user typed.
So I recommend the parameters.

One big dis-advantage is that your solution relies on a developer remembering to add the character, obviously the compiler won't complain. That is dangerous.
Secondly, performance should be enhanced with parameterized SQL statements, as Jeff points out here (in 2005!!!).

One advantage is that the driver itself will determine what he has to escape and what doesn't need to be escaped. Your method could be broken with an input like this:
\'; DROP TABLE foo;--
Which would result in
SELECT *
FROM Customers
WHERE Customername = '\'';DROP TABLE FOO;--'
The first quote gets escaped, the second doesn't and closes the string.

Short answer:
You should use parameterized queries simply because the database server knows better than you do which characters need to be escaped.
Long answer:
' is not necessarily the only special character that needs escaping. These special characters differ from DB server to DB server. MySQL, for example, uses \ as an escape character as well (unless sql_mode=NO_BACKSLASH_ESCAPES is set). Therefore, '' and \' mean the same thing.
This is not true of, say, Oracle.

What are the advantages of
parameterized statements compared to
our method?
The advantage is that it's harder to make a mistake; you can't do the parameterized method, and forget to replace the quotes. Also, replacing quotes is vulnerable if you do it twice.
The disadvantage of parameterized queries (and the reason I never use them) is complexity. You can write ten times as many ad-hoc queries before you get RSI.

Related

how to separate the parameters in the sql query and push it in to array to avoid sql injection

SELECT * FROM table1 WHERE year_month BETWEEN '2021-08' AND '2022-01';
update table2 set note_description = 'test #8:57am', patient_id = '5840', note_updated_by = '10000019', note_update_date = '2022-07-13 09:45:49' where note_id = '639'
now my backend queries can be attacked by sql injection so i want to avoid the sql injection
in the above queries I want to separate the parameters from queries and replace it with special characters so that I can avoid sql injection is there any package or anything to do it.
If you have received the SQL statement with the parameters already concatenated in, then this is the wrong place to fix your issue - there’s no way to safely parse the statement and separate out the parameters from the query.
You should find the place in the code where the parameters are concatenated into the Statement and leveraging Prepared Statements/Parameterized Queries to safely pass/bind the parameters.
If that’s not possible (for example because the code is structured to only pass along the statement) a less desirable alternative is to encode/enquote the parameters before concatenating them in, while ensuring they are all quoted in the statement. How you do that part will depend on the database / language being used.
I've seen one product that does this: pt-query-digest. It's a free tool that parses the MySQL query log, and produces reports of aggregate time spent running each query. To do this, it must establish a query "fingerprint" which allows it to group queries that are the same except for constant values. Like SELECT * FROM mytable WHERE id = 123 has the same fingerprint as SELECT * FROM mytable WHERE id = 456.
This means it must parse the queries and replace each constant value, like a numeric or string literal, with a placeholder ?. In cases of IN() predicates, it replaces the list of values with ?+. Also it reduces whitespace and removes comments.
It's a non-trivial amount of code, about 100 lines of Perl: https://github.com/percona/percona-toolkit/blob/3.x/lib/QueryRewriter.pm#L139-L248
In spite of this, the function is preceded by a comment that the developers acknowledge it is not perfect, and may miss some cases. Implementing a recursive-descent parser using regular expressions is not efficient or correct.
But this is probably not what you want to do anyway. You shouldn't be starting from a query with constant values and making them into a parameterized query. You should design parameterized queries yourself, as needed.
Not every constant value in an SQL query necessarily must be parameterized. Only the ones that aren't fixed values. That is, if you need to combine a variable from your client code into the SQL query string, and you can't guarantee that the variable is safe, then use a parameter. If a query has a constant value that is fixed (not interpolated from a variable), then it can remain in the query. If a query has a value that comes from a variable, but that variable is known to be safe, and never can be tainted by untrusted input, then it can remain in the query.
It's more reliable and economical for you to make these judgments. You know the code and the context much better than any automated system can.

Reasons for Prepared Statements with Bind Parameters over Interpolated Statements with Escaped / Quoted Parameters

To protect against SQL injection one is advised to use prepared statements with bind values. This ensures, that the database can distinguish between the actual logic in the SQL (which has to be parsed, interpreted and optimized) and the data (which doesn't need interpretation) and therefore will not interpret and execute commands which are found in data.
Another method accomplishing some protection is using an escaping library, which disarms significant chars in the data, so that they will not be interpreted.
It seems to me that in general it is advised to prefer prepared statements with bind parameters over escaping the input. Prepared statements with bind values do for example have some performance benefits in loops.
My question: is there any security reason to prefer prepared statements with bind values over escaping? And if yes, what are the exact reasons?
One reason I might think of is that "escaping is tricky" and the escaping library needs to match exactly the database features... anything else?
One reason is that escaping only works to protect quoted string literals. For example (I'll use pseudocode since you didn't reference any particular programming language):
$escapedName = EscapeString("O'Reilly")
$sql = "SELECT * FROM MyTable WHERE name = '$escapedName'"
In the above example, the apostrophe should be escaped, so it will become WHERE name = 'O\'Reilly' and therefore be safe to interpolate into the SQL query without causing any error.
However, numbers don't need to be quoted in SQL, and escaping a string that contains an apostrophe won't do the right thing:
$escapedId = EscapeString("123'456")
$sql = "SELECT * FROM MyTable WHERE id = $escapedId"
This will result in WHERE id = 123\'456 which is still an error.
You might say, "well put the number in single-quotes" but this isn't always possible, for example the LIMIT clause in MySQL required real integers, not a quoted string containing digits.
Besides the above issue, it's just easier to write code using parameters instead of using escaping!
For example, you could write code like the following:
$sql = "INSERT INTO mytable (col1, col2, col3, col4, col5, col6)
VALUES ('" . mysqli_real_escape_string($_POST['col1']) . "', "
. $mysqli->real_escape_string($_POST['col2']) . "', '"
. $mysqli->real_escape_string($_POST['col3']) . "', '"
. $mysqli->real_escape_string($_POST['col4']) . ", '"
. $mysqli->real_escape_string($_POST['col5']) . "', '"
. $mysqli->real_escape_string($_POST['col6']) . "')";
Can you spot the mistakes? With enough time, I’m sure you can. But it will slow down your coding and may give you eyestrain as you look for missing quote characters and other mistakes.
But it’s so much easier to write this, and easier to read it afterwards:
$sql = "INSERT INTO mytable (col1, col2, col3, col4, col5, col6)
VALUES (?, ?, ?, ?, ?, ?)";
Query parameters are safe for more data types, and they help you write code more quickly, with fewer mistakes. That's a big win.
The whole statement of question is coming for one ancient grave delusion
escaping which disarms significant chars in the data
Is, frankly, a nonsense.
There are no all-embracing "significant characters". A character that could have a devastating effect on one query part if cut loose, could be as harmless as a lamb in another. And vice versa.
There is no abstract all-embracing "data". All query parts are distinct, but escaping works for only one part.
And there is no such practice as "using escaping for protection" whatsoever.
Escaping is intended to escape special characters in SQL strings. And never has been intended for any protection. It's just a technological measure that has been awfully misunderstood and mistreated. It is like claiming that we are following a proper syntax in our programs solely for the protection. We are following the proper syntax to make the interpreter / compiler understand our code. Same here. Escaping is used to produce syntactically correct SQL strings. Which are of course injection-proof as a side effect. But again - the mission of escaping is anything but protection.
And here comes the the Escaping problem #1: strings are not the only data types to be used in the query. While using string escaping on the any other data literal is a straight road to disaster.
Moreover, even for strings, escaping is an essentially detachable measure, which alone constitutes a whole can of worms, making your code is prone to human errors of all sorts and constituting the Escaping problem #2:
Citing my article on the matter, Why should I use prepared statements if escaping is safe?:
As you can see, formatting a value for a database is effectively split into two parts, escaping variables and quoting values in the query. And this is where all the magic happens lies the cause for innumerable real life cases of SQL injections.
With your simplified example, where all the code is bound together, it is hard to overlook the proper routine. But in the real life the code is much more complex, consisting of large distinct modules. And escaping is done in one module while quoting in another. Or not. Nobody can tell actually. I'd just trust that this value has been escaped already. Or I will escape it just to be sure, and introduce extra escaping characters in the data. Or I am a new dev, who don't understand the example you posted here, and I was watching a youtube video that said escaping prevents SQL injection. I know the value has been escaped already, so I can put in the query safely. And as it is an integer, why would I waste quotes on it?
Or I know that the data has been escaped already when it was entering the application, so I won't have to escape it during some internal manipulations sometime later (when moving into another table for example). And have a first class second order SQL injection as a result.
Trust me, I've seen all these cases in the wild. Such a separated formatting introduces a total mess and a wast opportunity for injections.
Unlike escaping, prepared statements always make sure that a query part is treated properly.
Though I have no empirical evidence on the matter that I can point to that proves it's used, it's perhaps worth pointing out that using prepared statements that use a mix of parameter variables and constant values would allow a database query optimizer to know which parts of a query will be varied by the application and which parts will be constant. This could be of use in query planning. If you get into a mode of quoting all your data along with the query then the optimizer can't guess which parts are likely to very and which parts are fixed without keeping history of all variations of the query and looking at differences to work out which parts vary.
--we could infer that name will vary and type will not
--but we'd have to analyze all queries sent to work this out
SELECT * FROM person WHERE type = 1 AND name = 'john'
SELECT * FROM person WHERE type = 1 AND name = 'mark'
SELECT * FROM person WHERE type = 1 AND name = 'luke'
--we can easily say that type will vary and name will too
--the previously seen queries would infer differently
SELECT * FROM person WHERE type = #t AND name = #n
I mentioned I've never read anything that indicates it's used, but one can read about decisions that sql server makes called Parameter Sniffing, whereby it caches and reuses plans based on the first set of values it sees loaded into parameters, which might not generate optimal queries in all cases
Of course; this may harden your resolve to ditch parameters, or use hints to make the db re-plan the query every time, but it would be better to work with the server rather than against it, and use techniques to make it plan based on common or optimal-as-possible values
Even if we aren't getting cute with tweaking plans according to what we know about variables and constants, using a prepared statement should, at the very least, allow the db to compile and then reuse that compilation effort rather than redoing it, lowering the amount of resources that must go into readying a statement for run.
Think about your proposal in front end language terms:
To change the value of a variable action you could either change the runtime value with a simple value assignment in memory:
sayHello(string name){
console.print("hello " + name);
}
var name = console.readString(),
sayHello(name);
Or you could instead build a whole new script file with the new value in it, write it to disk, invoke the compiler on it, quit the running version of your app and start the newly compiled version:
main(){
disk.write("sayHello(string name){console.print(\"hello \"" + name +");}", "c:\\temp\\new.lang");
launchExe("langcompiler.exe", "c:\\temp\\new.lang");
launchExe("c:\\temp\\new.exe");
}
It's ridiculous to self modify the program and recompile just to change a value used in a function call, right?
Except that's what a db server does with every unparameterized SQL it receives, unless it goes to some effort to work out whether the query it just got is mostly the same as one it got X minutes ago except for some data part, extract that data, plug it into the compilation effort from 5 minutes ago..

ColdFusion Query - Injection Protection

I ask this question with a bit of sheepishness because I should know the answer. Could someone be kind and explain if and how injection could occur in the following code?
<cfquery>
select * from tableName
where fieldName = '#value#'
</cfquery>
I'm specifically curious about injection attempts and other malicious input, not about best practices or input validation for handling "normal" user input. I see folks strongly advocating use of CFQueryParam, but don't think I see the point. If user input has been validated for consistency to the database schema (e.g. so that input must be numeric for numerical database fields), is there anything else gained by using CFQueryParam? What does <cfqueryparam CFSQLType = "CF_SQL_VARCHAR"> do that '#value#' doesn't do?
Update:
While this answers part of your question, Peter's response is better, in that it directly addresses your question of "Why use cfqueryparam, when CF automatically adds protection by escaping single quotes?". Answer: In short, because the latter does not always work. Bind variables do.
It says in the docs "escapes string variables in single-quotation
marks" but doesn't CF already "magically" do this in CF query tag when
you wrap evaluated variables in single quotes?
Yes, most versions automatically escape single quotes as a protection measure for those not using cfqueryparam. However, as Scott noted above, it is better to use cfqueryparam (ie bind variables) because they ensure parameters are not executed as sql commands. Bind variables work, even in cases where the automatic escaping does not, as Peter's answer demonstrates.
That said, sql injection protection is really just a side effect of using bind variables. The primary reason to use bind variables is performance. Bind variables encourage databases to re-use query plans, instead of creating a new plan every time your #parameters# change. That cuts down on compilation time, improving performance.
Cfqueryparam also has a number of other benefits:
Provides data type checking (length, value, type, ...)
Provides attributes that simplify handling of "lists" and null values
Performs data type checking before any sql is sent to the database, preventing wasted database calls
While it does not really apply to string columns, IMO another big reason to use it is accuracy. When you pass a quoted string to the database, you are relying on implicit conversion. Essentially you are leaving it up to the database to figure out how to best perform the comparison, and the results are not always what you were expecting. (Date strings are a prime example). You may end with inaccurate results, or sometimes slower queries, depending on how the database decides to execute the sql. Using cfqueryparam avoids those issues by eliminating the ambiguity.
doesn't CF already "magically" do this in CF query tag when you wrap evaluated variables in single quotes?
Yep, it'll convert ' to '' for you.
Now guess what SQL you get from this code:
<cfset value = "\'; DROP TABLE tableName -- " />
<cfquery>
select * from tableName
where fieldName = '#value#'
</cfquery>
The cfqueryparam tag works; using query params solves SQL injection.
Any custom written attempts at validating, sanitizing, or escaping (all separate things, btw) are, at best, only as good as the developer's knowledge of the database system the code is running against.
If the developer is unaware of other escape methods, or if the values are modified between validation/escaping and them being rendered into SQL, or even if the codebase is ported to another database system and seems to be fine, there's a chance of custom code breaking down.
When it comes to security, you don't want chances like that. So use cfqueryparam.
To answer the first part of your question, setting your #value# variable to the following:
someValue'; DELETE FROM tableName WHERE '1' = '1
would result in this query being executed:
<cfquery>
select * from tableName
where fieldName = 'someValue'; DELETE FROM tableName WHERE '1' = '1'
</cfquery>

ColdFusion adding extra quotes when constructing database queries in strings

I am coding in ColdFusion, but trying to stay in cfscript, so I have a function that allows me to pass in a query to run it with
<cfquery blah >
#query#
</cfquery>
Somehow though, when I construct my queries with sql = "SELECT * FROM a WHERE b='#c#'" and pass it in, ColdFusion has replaced the single quotes with 2 single quotes. so it becomes WHERE b=''c'' in the final query.
I have tried creating the strings a lot of different ways, but I cannot get it to leave just one quote. Even doing a string replace has no effect.
Any idea why this is happening? It is ruining my hopes of living in cfscript for the duration of this project
ColdFusion, by design, escapes single quotes when interpolating variables within <cfquery> tags.
To do what you want, you need to use the PreserveSingleQuotes() function.
<cfquery ...>#PreserveSingleQuotes(query)#</cfquery>
This doesn't address, however, the danger of SQL injection to which you are exposing yourself.
Using <cfqueryparam> also allows your database to cache the query, which in most cases will improve performance.
It might be helpful to read an old Ben Forta column and a recent post by Brad Wood for more information about the benefits of using <cfqueryparam>.
The answer to your question, as others have said, is using preserveSingleQuotes(...)
However, the solution you actually want, is not to dynamically build your queries in this fashion. It's Bad Bad Bad.
Put your SQL inside the cfquery tags, with any ifs/switches/etc as appropriate, and ensure all CF variables use the cfqueryparam tag.
(Note, if you use variables in the ORDER BY clause, you'll need to manually escape any variables; cfqueryparam can't be used in ORDER BY clauses)
ColdFusion automatically escapes single quotes quotes in <cfquery> tags when you use the following syntax:
SELECT * FROM TABLE WHERE Foo='#Foo#'
In case you would want to preserve single quotes in #Foo# you must call #PreserveSingleQuotes(Foo)#.
Be aware the the automatic escaping works only for variable values, not for function results.
SELECT * FROM TABLE WHERE Foo='#LCase(Foo)#' /* Single quotes are retained! */
In that light, the function PreserveSingleQuotes() (see Adobe LiveDocs) is not much more than a "null operation" on the value - turning it into a function result to bypass auto-escaping.
I voted up Dave's answer since I thought he did a good job.
I'd like to add however that there are also several different tools designed for ColdFusion that can simplify a lot of the common SQL tasks you're likely to perform. There's a very light-weight tool called DataMgr written by Steve Bryant, as well as Transfer from Mark Mandel, Reactor which was originally created by Doug Hughes and one I developed called DataFaucet. Each of these has its own strengths and weaknesses. Personally I think you're apt to consider DataFaucet to be the one that will give you the best ability to stay in cfscript, with a variety of syntaxes for building different kinds of queries.
Here are a few examples:
qry = datasource.select_avg_price_as_avgprice_from_products(); //(requires CF8)
qry = datasource.select("avg(price) as avgprice","products");
qry = datasource.getSelect("avg(price) as avgprice","products").filter("categoryid",url.categoryid).execute();
qry = datasource.getSelect(table="products",orderby="productname").filter("categoryid",url.categoryid).execute();
The framework ensures that cfqueryparam is always used with these filter statements to prevent sql-injection attacks, and there are similar syntaxes for insert, update and delete statements. (There are a couple of simple rules to avoid sql-injection.)

Is there some way to inject SQL even if the ' character is deleted?

If I remove all the ' characters from a SQL query, is there some other way to do a SQL injection attack on the database?
How can it be done? Can anyone give me examples?
Yes, there is. An excerpt from Wikipedia
"SELECT * FROM data WHERE id = " + a_variable + ";"
It is clear from this statement that the author intended a_variable to be a number correlating to the "id" field. However, if it is in fact a string then the end user may manipulate the statement as they choose, thereby bypassing the need for escape characters. For example, setting a_variable to
1;DROP TABLE users
will drop (delete) the "users" table from the database, since the SQL would be rendered as follows:
SELECT * FROM DATA WHERE id=1;DROP TABLE users;
SQL injection is not a simple attack to fight. I would do very careful research if I were you.
Yes, depending on the statement you are using. You are better off protecting yourself either by using Stored Procedures, or at least parameterised queries.
See Wikipedia for prevention samples.
I suggest you pass the variables as parameters, and not build your own SQL. Otherwise there will allways be a way to do a SQL injection, in manners that we currently are unaware off.
The code you create is then something like:
' Not Tested
var sql = "SELECT * FROM data WHERE id = #id";
var cmd = new SqlCommand(sql, myConnection);
cmd.Parameters.AddWithValue("#id", request.getParameter("id"));
If you have a name like mine with an ' in it. It is very annoying that all '-characters are removed or marked as invalid.
You also might want to look at this Stackoverflow question about SQL Injections.
Yes, it is definitely possible.
If you have a form where you expect an integer to make your next SELECT statement, then you can enter anything similar:
SELECT * FROM thingy WHERE attributeID=
5 (good answer, no problem)
5; DROP table users; (bad, bad, bad...)
The following website details further classical SQL injection technics: SQL Injection cheat sheet.
Using parametrized queries or stored procedures is not any better. These are just pre-made queries using the passed parameters, which can be source of injection just as well. It is also described on this page: Attacking Stored Procedures in SQL.
Now, if you supress the simple quote, you prevent only a given set of attack. But not all of them.
As always, do not trust data coming from the outside. Filter them at these 3 levels:
Interface level for obvious stuff (a drop down select list is better than a free text field)
Logical level for checks related to data nature (int, string, length), permissions (can this type of data be used by this user at this page)...
Database access level (escape simple quote...).
Have fun and don't forget to check Wikipedia for answers.
Parameterized inline SQL or parameterized stored procedures is the best way to protect yourself. As others have pointed out, simply stripping/escaping the single quote character is not enough.
You will notice that I specifically talk about "parameterized" stored procedures. Simply using a stored procedure is not enough either if you revert to concatenating the procedure's passed parameters together. In other words, wrapping the exact same vulnerable SQL statement in a stored procedure does not make it any safer. You need to use parameters in your stored procedure just like you would with inline SQL.
Also- even if you do just look for the apostrophe, you don't want to remove it. You want to escape it. You do that by replacing every apostrophe with two apostrophes.
But parameterized queries/stored procedures are so much better.
Since this a relatively older question, I wont bother writing up a complete and comprehensive answer, since most aspects of that answer have been mentioned here by one poster or another.
I do find it necessary, however, to bring up another issue that was not touched on by anyone here - SQL Smuggling. In certain situations, it is possible to "smuggle" the quote character ' into your query even if you tried to remove it. In fact, this may be possible even if you used proper commands, parameters, Stored Procedures, etc.
Check out the full research paper at http://www.comsecglobal.com/FrameWork/Upload/SQL_Smuggling.pdf (disclosure, I was the primary researcher on this) or just google "SQL Smuggling".
. . . uh about 50000000 other ways
maybe somthing like 5; drop table employees; --
resulting sql may be something like:
select * from somewhere where number = 5; drop table employees; -- and sadfsf
(-- starts a comment)
Yes, absolutely: depending on your SQL dialect and such, there are many ways to achieve injection that do not use the apostrophe.
The only reliable defense against SQL injection attacks is using the parameterized SQL statement support offered by your database interface.
Rather that trying to figure out which characters to filter out, I'd stick to parametrized queries instead, and remove the problem entirely.
It depends on how you put together the query, but in essence yes.
For example, in Java if you were to do this (deliberately egregious example):
String query = "SELECT name_ from Customer WHERE ID = " + request.getParameter("id");
then there's a good chance you are opening yourself up to an injection attack.
Java has some useful tools to protect against these, such as PreparedStatements (where you pass in a string like "SELECT name_ from Customer WHERE ID = ?" and the JDBC layer handles escapes while replacing the ? tokens for you), but some other languages are not so helpful for this.
Thing is apostrophe's maybe genuine input and you have to escape them by doubling them up when you are using inline SQL in your code. What you are looking for is a regex pattern like:
\;.*--\
A semi colon used to prematurely end the genuine statement, some injected SQL followed by a double hyphen to comment out the trailing SQL from the original genuine statement. The hyphens may be omitted in the attack.
Therefore the answer is: No, simply removing apostrophes does not gaurantee you safety from SQL Injection.
I can only repeat what others have said. Parametrized SQL is the way to go. Sure, it is a bit of a pain in the butt coding it - but once you have done it once, then it isn't difficult to cut and paste that code, and making the modifications you need. We have a lot of .Net applications that allow web site visitors specify a whole range of search criteria, and the code builds the SQL Select statement on the fly - but everything that could have been entered by a user goes into a parameter.
When you are expecting a numeric parameter, you should always be validating the input to make sure it's numeric. Beyond helping to protect against injection, the validation step will make the app more user friendly.
If you ever receive id = "hello" when you expected id = 1044, it's always better to return a useful error to the user instead of letting the database return an error.