I research around the forum of postgresql injection in Go and I found some useful information in SQL injection like below:
How to execute an IN lookup in SQL using Golang?
How can I prevent SQL injection attacks in Go while using "database/sql"?
but I still need some advice because my code in Go is using a different kind of code and usecases.
some usecase/question i need advice for are like this
Using query looping to multiple insert like
INSERT INTO a (a1,a2,a3) VALUES (%d,%d,%s) using fmt.Sprintf, I know using sprinft is bad. so is there any solution for this loop query for insert ?
Ex: INSERT INTO a (a1,a2,a3) VALUES (%d,%d,%s),(%d,%d,%s),(%d,%d,%s)
Is it safe to use fmt.Sprintf to generate query if the param is using %d instead of %s ?
Using Prepare statement and Query is safe, but what if I'm using function Select (using $1,$2) and function NamedQuery (using struct named.)
Ex: Select * from a where text = $1 -> is using this $1 safe ?
and
Ex : Select * from a where text = :text -> is this safe in function NamedQuery?
Kindly need your advice guys. Thank you!
Firstly, usually prefer to use the db placeholders ? $1 etc.
Yes it is safe to use fmt.Sprintf with integer parameters to build SQL, though worth avoiding if you can, but your third param is %s - avoid that and use ?
Yes it is safe to use fmt.Sprintf with integer parameters, but %s or %v is far more risky and I'd avoid, can't think why you'd need it.
Use placeholders here, then yes it is safe.
General rules:
Use placeholders by default, it should be rare to use %d (as in your IN query for example)
Parse params into types like integer before any validation or use
Avoid string concat if you can, and be particularly wary of string params
Always hard code things like column and table names, never generate them from user input (e.g. ?sort=mystringcolname)
Always validate that the params you get are only those authorised for that user
Related
On this very useful page there is this statement...
CREATE OR REPLACE FUNCTION user_access (p_uname TEXT)
RETURNS timestamp LANGUAGE sql AS
$func$
SELECT accessed_at FROM users WHERE username = $1
$func$;
...as an explanation of how to be safe from SQL injection. I am trying to understand why i would be safe this way. What does PostgreSQL do for me, that keeps me safe? Can someone please point me in the right direction?
Why is it safe?
PostgreSQL (and about any other DBMS) will first compile the statement with the $1 in place, and only then will use the actual value provided by the user. So whatever is in the value cannot be interpreted as a part of the statement. In other words, using the parameter separates code from data.
Why do I need a procedure for this?
In most cases, you don't. What you really need is a mechanism that separates code from data, i.e. the parameter. In most languages and DB connectivity libraries nowadays there is a parameterized query support present, which allows you to write queries with placeholders (such as ?) and provide data through a separate parameter.
I use DB2 with iBatis in my project.
There are many
FETCH FRIST $perPg$ ROWS ONLY
queries for paging in DaoMap.xml files. But it seems dangerous in case of query injection. so I want to change them using # instead of $, but I can't figure it out.
Functions like CAST(#perPg# AS INTEGER) doesn't work on FETCH query. How can I solve this problem?
If you want to convert to int (and ensure that the value arrived is int) you can try with this:
#perPg:BIGINT#
This should be stupidly simple to answer, but for the life of me I cannot find a definitive answer on this.
Can you use "?" in postgres, like you can in other database engines?
For example:
SELECT * FROM MyTable WHERE MyField = ?
I know I can use the $n syntax for this, for example from psql this works:
CREATE TABLE dummy (id SERIAL PRIMARY KEY, value INT);
PREPARE bar(int) AS INSERT INTO dummy (value) VALUES ($1);
EXECUTE bar(10);
SELECT * FROM DUMMY;
But if I try to prepare a statement using "?", eg.
PREPARE bar(int) AS INSERT INTO dummy (value) VALUES (?);
I get:
ERROR: syntax error at or near ")"
LINE 1: PREPARE bar(int) AS INSERT INTO dummy (value) VALUES (?);
...and yet, in various places I read that "postgres supports the ? syntax".
What's going on here? Does postgres support using ? instead of $1, $2, etc.
If so, how do you use it?
Specifically, this is making my life a pain porting a bunch of existing sql server queries to postgres, and if I can avoid having to rewrite all the where conditions an all of the sql statements that would be very, very nice.
SQL-level PREPARE in PostgreSQL does not support the ? placeholder, it uses the $1 ... $n style.
Most client libraries support the standard placeholders used by that language in parameterized queries, eg PgJDBC uses ? placeholders.
If you're sending your queries via a client library like nPgSQL, psqlODBC, PgJDBC, psycopg2, etc then you should be able to use the usual placeholders for that language and client.
The website i worked was recently attempted to be hacked by the following SQL injection script
boys' and 3=8 union
select 1,
concat(0x232425,ifnull(`table_name`,0x30),char(9),ifnull(`table_rows`,0x30), char(9),0x252423),
3,4,5,6,7,8,9
from `information_schema`.`tables`
where table_schema=0x62646B3032 limit 44,1 -- And '8'='8
This injection returned the mysql table name. This was reported by the error reporting system on that website and we managed to fix that part however I am not able to understand what does the above injection mean?
Anyone can explain this?
Penuel
They're using a select from the Information Schema views in mysql server :
http://dev.mysql.com/doc/refman/5.0/en/information-schema.html
They use some clever hacks to rout out simple sql injection prevention techniques.
According to this the MySQL concat()
Returns the string that results from
concatenating the arguments. May have
one or more arguments. If all
arguments are nonbinary strings, the
result is a nonbinary string. If the
arguments include any binary strings,
the result is a binary string. A
numeric argument is converted to its
equivalent binary string form
So 0x232425 is converted to #$% which is simply added to the begining and end of the table_name field. Maybe just to make it easier for them to pull out the Table names later using Regex.
Later on the char(9) is equivalent to a tab as you can see here and is just there to format the output nicer.
The 3,4,5,6,7,8,9 is just there so that the columns match the boys table that they are performing the Union on.
This injection returned the mysql table name.
Do you mean that your website displayed the table name when you gave it this input, or that the query returns that when run from the mysql client? If it showed on your website, then the attacker has the ability to inject much more harmful queries. Check your data.
This question already has answers here:
How to anticipate and escape single quote ' in oracle
(2 answers)
Closed 7 years ago.
I have a database with names in it such as John Doe etc. Unfortunately some of these names contain quotes like Keiran O'Keefe. Now when I try and search for such names as follows:
SELECT * FROM PEOPLE WHERE SURNAME='O'Keefe'
I (understandably) get an error.
How do I prevent this error from occurring. I am using Oracle and PLSQL.
The escape character is ', so you would need to replace the quote with two quotes.
For example,
SELECT * FROM PEOPLE WHERE SURNAME='O'Keefe'
becomes
SELECT * FROM PEOPLE WHERE SURNAME='O''Keefe'
That said, it's probably incorrect to do this yourself. Your language may have a function to escape strings for use in SQL, but an even better option is to use parameters. Usually this works as follows.
Your SQL command would be :
SELECT * FROM PEOPLE WHERE SURNAME=?
Then, when you execute it, you pass in "O'Keefe" as a parameter.
Because the SQL is parsed before the parameter value is set, there's no way for the parameter value to alter the structure of the SQL (and it's even a little faster if you want to run the same statement several times with different parameters).
I should also point out that, while your example just causes an error, you open youself up to a lot of other problems by not escaping strings appropriately. See http://en.wikipedia.org/wiki/SQL_injection for a good starting point or the following classic xkcd comic.
Oracle 10 solution is
SELECT * FROM PEOPLE WHERE SURNAME=q'{O'Keefe}'
Parameterized queries are your friend, as suggested by Matt.
Command = SELECT * FROM PEOPLE WHERE SURNAME=?
They will protect you from headaches involved with
Strings with quotes
Querying using dates
SQL Injection
Use of parameterized SQL has other benefits, it reduces CPU overhead (as well as other resources) in Oracle by reducing the amount of work Oracle requires in order to parse the statement. If you do not use parameters (we call them bind variables in Oracle) then "select * from foo where bar='cat'" and "select * from foo where bar='dog'" are treated as separate statements, where as "select * from foo where bar=:b1" is the same statement, meaning things like syntax, validity of objects that are referenced etc...do not need to be checked again. There are occasional problems that arise when using bind variables which usually manifests itself in not getting the most efficient SQL execution plan but there are workarounds for this and these problems really depend on the predicates you are using, indexing and data skew.
Input filtering is usually done on the language level rather than database layers.
php and .NET both have their respective libraries for escaping sql statements. Check your language, see waht's available.
If your data are trustable, then you can just do a string replace to add another ' infront of the ' to escape it. Usually that is enough if there isn't any risks that the input is malicious.
I suppose a good question is what language are you using?
In PHP you would do: SELECT * FROM PEOPLE WHERE SURNAME='mysql_escape_string(O'Keefe)'
But since you didn't specify the language I will suggest that you look into a escape string function mysql or otherwise in your language.
To deal quotes if you're using Zend Framework here is the code
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$db->quoteInto('your_query_here = ?','your_value_here');
for example ;
//SELECT * FROM PEOPLE WHERE SURNAME='O'Keefe' will become
SELECT * FROM PEOPLE WHERE SURNAME='\'O\'Keefe\''
Found in under 30s on Google...
Oracle SQL FAQ