Delete Query inside Where clause - sql

Is there any possibility to write delete query inside Where clause.
Example:
Select ID,Name From MyTable Where ID IN(Delete From MyTable)
It may be crazy, but let me explain my situation. In our reporting tool, we are supporting to enter SQL where query.
We will use our own Select and From Clause query and combine the user's where query input.
Example:
Select ID,Name From MyTable Where ("Query typed by user")
Here, user can type any kind of where query filter..
If he types like ID=100 our final query becomes like this
Select ID,Name From MyTable Where (ID=100)
One of our customer asked us what will happen if anyone type the delete query as where query filter. he feels this may be the security hole..so we have tried that kind of possibility in our dev environment. But the sql returns error for the following query.
Select ID,Name From MyTable Where ID IN(Delete From MyTable)
So finally, my question is, is there any other possibility to write Delete Query inside Where clause or Select clause.. If it possible, how can I restrict it?

Yes. They can run a delete. They can type:
1 = 1; DELETE FROM MY_TABLE;
Or even worse in some ways, (since you should have backups):
1 = 0 UNION SELECT SOCIAL_SECURITY_NUMBER, CREDIT_CARD_NUMBER, OTHER_SENSITIVE_DATA FROM MY_SENSITIVE_TABLE;
Now, in your case its hard to validate. Normally if you are just passing a value to filter on you can use parameterised sql to save yourself. You however also need to let the user select a column. In cases like these, usually we use a drop down to allow the user to select a predefined list of columns and then validate the column name server side. We give the user a text box to enter the value to match and then parameterise that.

It's not quite possible. But he can do something like this :
Select ID,Name From MyTable Where (ID=100); (DELETE FROM MyTable Where 1 = 1)
by using ID=100); (DELETE FROM MyTable Where 1 = 1 instead of ID=100

I believe what your customer is talking about is SQL injection, as long as you have taken appropriate methods to block other queries from running after your select statement is done, then you should have no problem in letting them type whatever it is that you want.
From my experience there is no way to delete anything when you are doing a select statement.
Just make sure you have query terminator characters so they don't write something like the following.
select column1,column2, from myTable where ID in (1,2); delete from my table
this would be a valid worry from your customer if you aren't taking proper steps to prevent sql injection from happening.
You could have your SQL reporting tool just not have update, or delete permission and just have it have Read permission. However, it is up to you guys have you handle your sql injection security.

Related

SQL injection payload after order by in SQL query

Trying to exploit SQL injection for my assignment. Is it possible to execute delete or drop query after order by in select query without using the semicolon in Postgresql?
This is my sample query:
Select *
from table
order by {sql injection payload}
Without using the semicolon in the payload, can we delete data or drop a table?
https://stackoverflow.com/a/6800585
Do we have similar to this Postgrsql?
I tried
Select * from (delete from table_name returning *) a
But getting sql error as 'syntax error at or near from'
Check this document it says we can bypass forbidden character by CHR()
https://book.hacktricks.xyz/pentesting-web/sql-injection/postgresql-injection
DELETE cannot be put inside a subquery. Nor can DELETE be part of a UNION.
So aside from running a second query (that is, separated by a semicolon), there's almost no way you can do what you describe.
You could invoke a stored procedure or function, if you knew of an existing function that performs a DELETE. Example:
Select *
from table
order by {sql injection payload}
After your payload modifies this query:
Select *
from table
order by SomeFunctionThatDeletes()
Another type which works because you can select from a procedure in PostgreSQL:
Select *
from table
order by id
UNION
Select *
from SomeProcedureThatDeletes()
You can't create the function or procedure with SQL injection, so that routine must exist already, and you would need to know its name and how to call it.
DELETE or DROP TABLE are not the only bad things that can happen from SQL injection. It could be a problem if the query returns data that the current user shouldn't have privilege to see. For example, records about a different user's purchases or medical history.
SQL injection can also be accidental instead of malicious. I would even say that most instances of SQL injection result in simple errors instead of data breaches. Those aren't really attacks, but they lead to an unsatisfactory experience for your users.

SQL update multiple rows with different values where they match a value from a list

So perhaps the title is a little confusing. If you can suggest better wording for that please let me know and i'll update.
Here's the issue. I've got a table with many thousands of rows and i need to update a few thousand of those many to store latest email data.
For example:
OldEmail#1.com => NewEmail#1.com
OldEmail#2.com => NewEmail#2.com
I've got a list of old emails ('OldEmail#1.com','OldEmail#2.com') and a list of the new ('NewEmail#1.com','NewEmail#2.com'). The HOPE was was to sort of do it simply with something like
UPDATE Table
SET Email = ('NewEmail#1.com','NewEmail#2.com')
WHERE Email = ('OldEmail#1.com','OldEmail#2.com')
I hope that makes sense. Any questions just ask. Thanks!
You could use a case expression:
update mytable
set email = case email
when 'OldEmail#1.com' then 'NewEmail#1.com'
when 'OldEmail#2.com' then 'NewEmail#2.com'
end
where email in ('OldEmail#1.com','OldEmail#2.com')
Or better yet, if you have a large list of values, you might create a table to store them (like myref(old_email, new_email)) and join it in your update query, like so:
update t
set t.email = r.new_email
from mytable t
inner join myref r on r.old_email = t.email
The actual syntax for update/join does vary accross databases - the above SQL Server syntax.
With accuracy to the syntax in particular DBMS:
WITH cte AS (SELECT 'NewEmail#1.com' newvalue, 'OldEmail#1.com' oldvalue
UNION ALL
SELECT 'NewEmail#2.com', 'OldEmail#2.com')
UPDATE table
SET table.email = cte.newvalue
FROM cte
WHERE table.email = cte.oldvalue
or, if CTE is not available,
UPDATE table
SET table.email = cte.newvalue
FROM (SELECT 'NewEmail#1.com' newvalue, 'OldEmail#1.com' oldvalue
UNION ALL
SELECT 'NewEmail#2.com', 'OldEmail#2.com') cte
WHERE table.email = cte.oldvalue
Consider prepared statement for rows update in large batches.
Basically it works as following :
database complies a query pattern you provide the first time, keep the compiled result for current connection (depends on implementation).
then you updates all the rows, by sending shortened label of the prepared function with different parameters in SQL syntax, instead of sending entire UPDATE statement several times for several updates
the database parse the shortened label of the prepared function , which is linked to the pre-compiled result, then perform the updates.
next time when you perform row updates, the database may still use the pre-compiled result and quickly complete the operations (so the first step above can be skipped).
Here is PostgreSQL example of prepare statement, many of SQL databases (e.g. MariaDB,MySQL, Oracle) also support it.

VBA Access Table reference in SQL query

I have been running into trouble executing SQL code in VBA Access when I refer to certain Table names.
For example,
INSERT INTO TempTable (ClientName) SELECT DISTINCT 1_1_xlsx.ClientName FROM 1_1_xlsx'<--does not work
The code works fine when I changed the Table name from 1_1_xlsx to Stuff.
INSERT INTO TempTable (ClientName) SELECT DISTINCT Stuff.ClientName FROM Stuff '<--works
I have no idea why the first query results in a syntax error and the second code is runs fine even when they refer to the same thing. I suspect it should be the naming conventions but I could not find any concrete answers.
Also, are there any ways that I could use 1_1_xlsx as my table name? Or am I just writing my query wrong?
try this:
INSERT INTO TempTable (ClientName) SELECT DISTINCT [1_1_xlsx].ClientName FROM [1_1_xlsx]
In many SQL based databases you can't have a table name or field name that starts with a number.
I suspect this is the underlying reason for your problem. Although Access will allow it, I have seen it cause problems in the past.
The problem is the number at the beginning of the table name. That is bad -- because it confuses the parser.
This is a bad table name, but SQL allows you to define table aliases. And, in this case, you don't even need to repeat the table name. So, here are two simple solutions:
INSERT INTO TempTable (ClientName)
SELECT DISTINCT ClientName
FROM 1_1_xlsx;
Or:
INSERT INTO TempTable (ClientName)
SELECT DISTINCT t.ClientName
FROM 1_1_xlsx as t
There is no reason to use the complete table name as an alias. That just makes the query harder to write and to read.

Sub-Queries in Sybase SQL

We have an application which indexes data using user-written SQL statements. We place those statements within parenthesis so we can limit that query to a certain criteria. For example:
select * from (select F_Name from table_1)q where ID > 25
Though we have discovered that this format does not function using a Sybase database. Reporting a syntax error around the parenthesis. I've tried playing around on a test instance but haven't been able to find a way to achieve this result. I'm not directly involved in the development and my SQL knowledge is limited. I'm assuming the 'q' is to give the subresult an alias for the application to use.
Does Sybase have a specific syntax? If so, how could this query be adapted for it?
Thanks in advance.
Sybase ASE is case sensitive w.r.t. all identifiers and the query shall work:
as per #HannoBinder query :
select id from ... is not the same as select ID from... so make sure of the case.
Also make sure that the column ID is returned by the Q query in order to be used in where clause .
If the table and column names are in Upper case the following query shall work:
select * from (select F_NAME, ID from TABLE_1) Q where ID > 25

How to write a update SQL using a select SQL

I want to write a update SQL statement, but one conidtion of this statement is the result from a select SQL statement, and I also want to return the result of the select SQL statement.
Like this: update ... set ... where id = (select id from ...)
I want to return the value of id back.
Does anybody know how should I do this?
Thanks in advance!
I don't believe that's possible in one statement. Update then query (select) the new value, or query the value first, and then submit an update.
Alternative would be a stored procedure on the database, which executes the multiple queries and returns the result for you.
This is not possible in all Java database frameworks that I know. Probably you need to separate your query and update in Java.
I don't see any problem in using a subselect in a WHERE clause of an update statement.
For the second request, getting back the value of id, I know this is possible in DB2, and maybe others implement that syntax too:
SELECT id FROM FINAL TABLE (
update ... set ... where id = (select id from ...)
)
This works also for INSERT and DELETE statements. (See the documentation.)
Update statements won't return the updated datasets. The select in that case would be a subselect that isn't directly accessible.
You'd thus have to use at least two queries:
select the ids you want
call the update query passing the previously selected ids as a parameter