SQL Server vs MySQL - SQL Injection Vulnerabilities in Classic ASP - mysql

Recently one of our client's websites fell prey to a SQL Injection attack due to a failure to sanitize query string parameters provided to the page. The vulnerable code has since been identified and is being corrected, but it got me wondering about some of the differences between how MySQL and SQL Server process multi-query strings.
The vulnerable code is used on several dozen websites, two of which are are running on SQL server while the rest are on MySQL. With this code we have never before suffered an injection attack (by the grace of God), but once we released the two websites that are running on SQL server (with the same code base) the website was quickly exploited. The method of injection was quite simple:
page.asp?param=1;delete from [some_table];
Like I said, the vulnerable code is shared across many websites, but if I try to execute the same type of injection on our MySQL sites ASP throws up a nice Server Error letting us know that there was an error in the query:
SELECT * FROM Table1 WHERE ID = 1;DELETE FROM TABLE1;
Testing this further I was able to verify that the MySQL ODBC 3.51 Driver will not allow two SQL queries to be executed in the same statement when an ADODB.Connection object calls Execute(""), while SQL Server Native Client (10.1) doesn't have any problem running two side-by-side queries. Is this in fact just a configuration of the provider that makes SQL server vulnerable in this fashion while MySQL is not, or does this stem from somewhere else?

The MySQL client API does not permit multi-queries by default. You have to enable this explicitly, or else you'll get errors when trying to execute a query like you saw. This is a good thing for reducing risk of SQL injection attacks.
The MySQL ODBC driver 3.51.18 (August 2007) added support for a connect option FLAG_MULTI_STATEMENTS to enable multi-statements. See http://dev.mysql.com/doc/refman/5.1/en/connector-odbc-configuration-connection-parameters.html.
See also http://bugs.mysql.com/bug.php?id=7445 for the history of this option.
Also see my answer to "Mysql change delimiter for better SQL INJECTION handling?" Note that multi-statements is only one way to get an SQL injection vulnerability. Disabling multi-statements is not a 100% proof against these flaws.

It's a feature of SQL server that it supports multiple statements on a line. The solution is not so much to sanitize the input, as to use parameterized queries or stored procedures. If the query had been
SELECT * FROM Table1 WHERE ID = #id
Then passing "1;DELETE FROM TABLE1;" would have produced an error, since that's not a valid integer value.

I think this happened because SQL Server supports MARS. As far as I understand MySQL does not support this. Mars is a good feature to speed up database queires so there are fewer round trips. you can put more then one query in a sql statement.

It is possible to exploit SQL injection without stacking queries. A very common method is to use a "Union Select"
Here is a mysql injection exploit that I have written which uses a union select:
http://milw0rm.com/exploits/3002
A union select allows you make a select statement within other statement:
select 1 union select Password from mysql.user
You can also do a sub-select:
insert into sometable (some,col,id) values ((select Password from mysql.user),1,1)-- )
Blind sql injection works on all platforms, however depending on the database the exploit will be different. This is a blind SQL Injection exploit for mysql:"
milw0rm.com/exploits/4547
This is a very good paper on the topic of SQL Injection for MySQL:
www.ngssoftware.com/papers/HackproofingMySQL.pdf

Related

AWS Aurora MySQL prepared statement

I have an insert query that I want to execute using the JavaScript V3 AWS client, against an AWS Aurora MySQL Serverless database. I am using the Data API of the database. I got the #aws-sdk/client-rds-data set up in my code and I can connect and execute arbitrary SQL queries using the ExecuteStatementCommand.
What I would like to know is that how I make SQL prepared statements and execute them. I have an INSERT query whose values are user provided. I cannot just concatenate those values into the SQL query as it would create an SQL injection vulnerability.
Unfortunatelly, I couldn't find how to make prepared statements and execute them in the #aws-sdk/client-rds-data package's documentation.
If somebody knows how to do it, could that someone please explain. Big thanks in advance!
I'm not a user of the AWS SDK for client-rds-data, but I'm inferring the following from the documentation, and my own knowledge of MySQL.
I see that interface ExecuteSqlCommandInput has a property sqlStatements, which allows multiple SQL statements separated by semicolons. This precludes the use of query parameters, because in MySQL you can't use prepare() on a string that includes multiple SQL statements.
Whereas ExecuteStatementCommandInput has a property sql (a single statement) and a property parameters which is an array of scalar parameters (i.e. each scalar corresponds to one parameter placeholder in the sql string). This should allow you to run a parameterized SQL query.
Re your comment: When you said you wanted to use prepared statements to avoid SQL injection vulnerabilities, I assumed you understood how prepared statements protect against those vulnerabilities.
In fact, using prepared statements alone is not a defense. You have to separate dynamic inputs from your SQL query by using query parameters. It just happens that using query parameters requires using prepared statements, so people say "use prepared statements" to defend against SQL injection, when they should say "use query parameters, which implies you must use prepared statements."
Tutorials about using SQL with query parameters are abundant. Here's one for Node.js: https://www.veracode.com/blog/secure-development/how-prevent-sql-injection-nodejs
The calling convention for the AWS SDK is different, but the concept is the same. I have only found reference documentation for AWS SDK, no code examples or task-oriented documentation. This is disappointing but unfortunately typical for AWS.

Are the escape functions in the Node.js mysql package sufficient enough to securely query a mysql database (without the use of prepared statements)?

According to Node.js' mysql package documentation:
In order to avoid SQL Injection attacks, you should always escape any user provided data before using it inside a SQL query. You can do so using the mysql.escape(), connection.escape() or pool.escape() methods.
I cannot find any documentation / reference to using prepared statements with mysql, except for in a reference to using '?' characters. It states the following:
Alternatively, you can use ? characters as placeholders for values you would like to have escaped...
This looks similar to prepared statements in MySQL, however it really
just uses the same connection.escape() method internally.
From my experience with talking to other developers, the general consensus in the developer community is that prepared statements are the ONLY safe way to perform mysql queries from Node.js however, as you can see with the mysql package, there is no obvious support for prepared statements. However, it is indicated that their method for avoiding SQL injection is via the usage of the escape functions.
My Question:
Are the escape functions in the mysql package sufficient enough to securely query a mysql database (without the use of prepared statements)?
Escaping is actually just as safe as using parameterized queries, if you do it consistently.
But it's recommended to use parameters because it makes your code simpler. Therefore developers are probably more likely to do it.
If the Node.js library makes it just as convenient as parameters, but implements it internally by modifying query strings, replacing the ? marks with the parameter values, then you're good.
For what it's worth, Python's MySQL driver does this too, and also PHP's PDO extension when the "emulate prepares" option is in effect. As long as those libraries are well-tested, it should be safe.
FWIW, both escaping and parameters is limited in SQL injection prevention, because in both cases, you can only protect values that you would combine with your SQL query. You cannot protect identifiers (like table names, or column names), or SQL keywords, or expressions, etc. In these cases, just be careful that you have vetted any dynamic content before combining it with your SQL query.
See also:
Preventing SQL injection in Node.js
Difference between real_escape_string and prepare()?

Cheapest SQL Statement possible / Are there Client-Side SQL Statements?

Questions
What is/are the most cheapest SQL-Statment(s) (in terms of Processing Overhead/CPU Cycles).
Are there (this will most likely be DB-Client specific) any Statments that are evaluated directly by the client and even do not go to the database server?
The result doesn't matter, if an empty statement (which produces an SQL Error) is the cheapest OK, then this is good too. But I am more interested in non Error Responses.
Background:
I have an application that queries a lot of data from the DB. However I do not require this data. Sadly, I have no possibility to skip this query. But I have the possibility to change the SQL Query itself. So I am trying to find the cheapst SQL Statement to use, ideally it should not even go to the SQL Server and the SQL-Client Library should answer it. I will be using MySQL.
UPDATES (on comments):
Yes, it can be a No-Operation. It must be something I can pass as a regular SQL String to the mysql client library. Whatever that string could be, is the question. The goal is, that this Query then somehowreturns nothing, using the least Resources on the SQL Server as possible. But in idealcase the client itself will realize that this query doesnt even have to go to the server, like a version Check of the client library (OK I know this is no standard SQL then but maybe there is something I do not know about, a statement that will be "short circuited/answered" on the client itself).
Thanks very much!
DO 0
DO executes the expressions but does not return any results. In most respects, DO is shorthand for SELECT expr, ..., but has the advantage that it is slightly faster when you do not care about the result.

Query to detect MySQL

I'm fixing a bug in a proprietary piece of software, where I have some kind of JDBC Connection (pooled or not, wrapped or not,...). I need to detect if it is a MySQL connection or not. All I can use is an SQL query.
What would be an SQL query that succeeds on MySQL each and every time (MySQL 5 and higher is enough) and fails (Syntax error) on every other database?
The preferred way, using JDBC Metadata...
If you have access to a JDBC Connection, you can retrieve the vendor of database server fairly easily without going through an SQL query.
Simply check the connection metadata:
string dbType = connection.getMetaData().getDatabaseProductName();
This will should give you a string that beings with "MySQL" if the database is in fact MySQL (the string can differ between the community and enterprise edition).
If your bug is caused by the lack of support for one particular type of statement which so happens that MySQL doesn't support, you really should in fact rely on the appropriate metadata method to verify support for that particular feature instead of hard coding a workaround specifically for MySQL. There are other MySQL-like databases out there (MariaDB for example).
If you really must pass through an SQL query, you can retrieve the same string using this query:
SELECT ##version_comment as 'DatabaseProductName';
However, the preferred way is by reading the DatabaseMetaData object JDBC provides you with.
Assuming your interesting preconditions (which other answers try to work around):
Do something like this:
SELECT SQL_NO_CACHE 1;
This gives you a single value in MySQL, and fails in other platforms because SQL_NO_CACHE is a MySQL instruction, not a column.
Alternatively, if your connection has the appropriate privileges:
SELECT * FROM mysql.db;
This is an information table in a database specific to MySQL, so will fail on other platforms.
The other ways are better, but if you really are constrained as you say in your question, this is the way to do it.
MySql may be the only db engine that uses backticks. That means something like this should work.
SELECT count(*)
FROM `INFORMATION_SCHEMA.CHARACTER_SETS`
where 1=3
I might not have the backticks in the right spot. Maybe they go like this:
FROM `INFORMATION_SCHEMA`.`CHARACTER_SETS`
Someone who works with MySql would know.

What are the SQL Server query syntax not supported by MySQL?

I am working in a project where we are using SQL Server database currently. But recently a decision has been taken that the database will be changed to MySQL.
I am not using any stored procedures, views, triggers, user defined functions, etc. But I think even then some queries written for SQL Server will not be supported by MySQL.
Can anyone help: what are the things that I have to check (and change) so that all the queries will work properly for MySQL also?
Queries that I know without consulting the documentation that will not work:
(recursive) common table expressions
windowing functions
queries using the standard SQL string concatenation ||
UPDATEs with JOIN are different between the two systems
Date arithmetics: date_column + 1 behaves differently in SQL Server
Division by zero will produce an error
SQL Server will reject values that do not fit into a column (instead of silently truncating it, which MySQL does in the default installation)
DDL that will not work and might have an impact on performance and/or data quality
datetime columns where you need precision up to milliseconds
tables with check constraints
indexed views
triggers on views
table functions (select * from my_function(42);)
filtered indexes ("partial index")
function based indexes
There's always the option to take commercial support from MySQL AB for this problem. I'm pretty sure they've done enough MSSQL->MySQL migrations to know alot about that. If a price tag on the migration is not a problem.
Alternatively, you could try to run the MySQL Migration Toolkit over the data and look for meaningful error messages at the stuff it cannot migrate. MySQL Migration Toolkit is part of the MySQL GUI Tools.