Is it injection safe to remove all quotes from the user input? - sql

$id = $_GET['id'];
$id = str_replace("'", "", $id);
$sql = "select name from test where id='$id'";
$stmt = $conn->query($sql);
As the php code snippet above, it removes all single quotes from the user input, and then put it in a sql query, whaterver it gets from the user is not able to escape from the quotes surrounding them, it seems safe from sql injection. I am quite curious about how to inject sql code to this.
Some question said about escaping quotes, which has examples to exploit it. But in my occasion, removing all quotes isn't really the same as escaping.
I know there is the parameterized query way to prevent sql injection. And yes, it's possible that single quotes may be contained in legitimate data. I am asking this question out of curiosity while learing sql injection, all I want to know is there are any examples to exploit this code?

If you don't want to use parameterization or escaping, and assuming your id is an integer, you could use typecasting. This is totally safe, and faster code than calling a function to do string replacement:
$id = (int) $_GET['id'];
$sql = "select name from test WHERE id=$id";
$stmt = $conn->query($sql);
But you should just get into the habit of using parameters. It's simple and fast. It works for strings, even if the strings contain special characters like quotes.
It's super easy in PDO, and it takes just one extra line of code:
$id = $_GET['id'];
$sql = "select name from test WHERE id=?";
$stmt = $conn->prepare($sql);
$stmt->execute([$id]);
my question [is], is it safe to remove quotes for string fields?
No. Don't do this. You don't know enough to do this safely. For example, what about backslash (\)? And other special characters?
Do you know why the internal MySQL API https://dev.mysql.com/doc/refman/5.7/en/mysql-real-escape-string.html escapes more than just the quotes? This is the list of characters that are escaped:
\, ', ", NUL (ASCII 0), \n, \r, and Control+Z
So is it enough to remove these characters? No, you still have to think about character sets and hex-encoded characters.
There's no reason to do this. You already have more reliable solutions to make SQL queries safe.
Don't get fixated on your remove-the-quote solution. It's not sufficient.

Related

SQL UPDATE statement with large HTML data

I have some automated workflow, which includes updating a column via SQL with HTML tags in it.
The basic SQL statement goes like this:
UPDATE content SET bodytext = '<div class="one two three">Here comes a whole lot of HTML with all special chars and double quotes " and single quotes ' and empty lines and all possible kind of stuff...</div>' WHERE pid = 10;
Is there a way to make MariaDB or MySQL to escape things automatically in SQL (without PHP)?
I'd suggest to use prepared statements. This way you separate the statement from it's parameters and don't need to care about additional escaping necessary in plain SQL.
Using functionality provided in PHP's MySQLi driver would simplify the process:
https://www.w3schools.com/php/php_mysql_prepared_statements.asp
Prepared statements are also possible in plain SQL, but I'm not sure if doing it manually would be worth the hassle
https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html
Thank you for your input, but I think, I found a solution which works for me. It seems that you actually can tell the SQL server to accept a raw string by this kind of syntax:
SELECT q'[The 'end' of the day]'
(Source: https://www.databasestar.com/sql-escape-single-quote/)
So I did the following:
SELECT #html := '[<div class="one two three">Here comes a whole lot of HTML with all special chars and double quotes " and single quotes '' and empty lines and all possible kind of stuff...</div>]';
UPDATE content SET bodytext = #html WHERE pid = 10;
And it works that way without any escaping problems.

How to insert into session row using pdo [duplicate]

I am still getting my head around a PDO statement but the code below does not do what I assumed it would
$temp = "6c ";
$weather_report = "Its currently $temp " ;
$qry = $pdo->exec("UPDATE data_weather SET text= '$weather_report' WHERE period='report' ");
This does update my database but only with 'Its currently' and the temp value is missing ,
After reading some articles I believe I need to use quote but I am not sure how to implement it ?
any help please ?
Please use query parameters instead of interpolating variables into SQL strings.
It's safer, faster, and easier.
$temp = "6c ";
$weather_report = "It's currently $temp " ;
$sql = "UPDATE data_weather SET text= ? WHERE period='report'";
$stmt = $pdo->prepare($sql);
$stmt->execute(array($weather_report));
Note that you don't need to quote the string. In fact, you must not put quotes around the ? placeholder. You can use apostrophes inside your weather report string safely.
You can use a parameter placeholder any place you would normally put a single scalar value in an SQL expression. E.g. in place of a quoted string, quoted date, or numeric literal. But not for table names or column names, or for lists of values, or SQL keywords.
Although Bill has already answered the question, I'd like to add:
Do not use named parameters with TEXT columns, at least not with MySQL. It won't work. Use question marks instead.

SQL injection - protection

I am not using prepared statements and i dont want to use it if not necessary
Example :
$sqlServ = new mysqli(SQL_HOST, SQL_USER, SQL_PASS);
$char = isset($_GET['char']) ? sanitize($_GET['char']) : null;
$check = $sqlServ->query("SELECT name FROM player.player WHERE name LIKE '{$char}'");
function sanitize($var)
{
$var = htmlentities($var, ENT_QUOTES);
$var = htmlspecialchars($var, ENT_QUOTES, 'UTF-8');
if (get_magic_quotes_gpc()) {
$var = stripslashes($var);
}
return $var;
}
Is it enough for sql injection protection?
Thanks for answer.
$var = htmlentities($var, ENT_QUOTES);
This is a bad idea. HTML-encoding is for the output stage, where you <?php echo htmlspecialchars($var); ?> variables in an HTML template. If you try to handle this output-time concern at input-time you end up with input that is unnecessarily encoded in the database, preventing you from properly matching, slicing and sorting it. And if you then output the content from the database without escaping, you've still got XSS bugs for any content that comes in through a means other than form input.
HTML-encode when creating HTML and at no other time.
$var = htmlspecialchars($var, ENT_QUOTES, 'UTF-8');
Huh? It's already HTML-encoded, why double-encode it? This is guaranteed to mangle characters like & and <, as well as (because of the previous htmlentities) all non-ASCII characters.
Is it enough for sql injection protection?
Not exactly. Mainly: there is no SQL injection protection code here at all.
There is HTML-escaping, but backslashes are special characters in MySQL string literals, and backslashes are not touched by HTML-escaping. So input strings with a trailing backslash break the end ' in the query, making the query invalid.
It so happens that because there are no other ' characters or injections in the string after that, there isn't a way to exploit this particular query; you can only make it break. But as soon as the query changes that's no longer true.
To do SQL injection ‘protection’, you would call $sqlServ->real_escape_string() on the value just before putting it into the string literal in the query. But this is really easy to forget or get wrong. Using parameterised queries consistently is a more reliable approach and no more difficult.

How can I escape single and double quotes in SQL prepared statement?

I have a SQL statement similar to the one shown below in Perl:
my $sql="abc..TableName '$a','$b' ";
The $a is free text which can contain anything including single quotes, double quotes, back- and front-slash characters, etc.
How can these characters be escaped to make the SQL statement work?
Thanks.
You can either use the ->quote method (assuming you're using DBI):
my $oldValue = $dbh->quote('oldValue');
my $newValue = $dbh->quote('newValue');
$dbh->do("UPDATE myTable SET myValue=$newValue where myValue=$oldValue");
Better still, the best practice is to use bind values:
my $sth = $dbh->prepare('UPDATE myTable SET myValue=? WHERE myValue=?');
$sth->execute('newValue','oldValue');
This should also work for stored procedure calls, assuming the statement once the strings have been expanded is valid SQL. This may be driver/DB specific so YMMV.
my $sth = $dbh->prepare("DBName..ProcName ?,? ");
$sth->execute($a, $b);
Use a prepared statement. Replace the variable with a ?. To crib an example from DBI manpages:
$sql = 'SELECT * FROM people WHERE lastname = ?';
$sth = $dbh->prepare($sql);
$sth->execute($user_input_here);
Interpolating user input into your SQL is asking for security holes.
If you use query parameter placeholders, you don't have to escape the content of the strings.
my $sql="DBName..ProcName ?, ?";
$sth = $dbh->prepare($sql);
$sth->execute($a, $b);
If the DBI is using true query parameters, it sends the parameter values to the RDBMS separately from the SQL statement. The values are never combined with the SQL statement string, therefore the values never have an opportunity to cause SQL injection.
If the DBI is "emulating" prepared statements by interpolating the variables into the query string, then DBI should handle the correct escaping logic so you don't have to. Let the experts (those who write and test DBI) worry about how to do it.
If you don't want to use ->quote (for some reason, this function doesn't run on my version of DBI) then try this:
$query=~s/\"/\\\"/g;
I tend to do the same with single quotes and commas too just to be safe.
Seems to work fine for me...!

Split SQL statements

I am writing a backend application which needs to be able to send multiple SQL commands to a MySQL server.
MySQL >= 5.x support multiple statements, but unfortunately we are interfacing with MySQL 4.x.
I am trying to find a way (hint: regex) to split SQL statements by their semicolon, but it should ignore semicolons in single and double quotes strings.
http://www.dev-explorer.com/articles/multiple-mysql-queries has a very nice regex to do that, but doesn't support double quotes.
I'd be happy to hear your suggestions.
Can't be done with regex, it's insufficiently powerful to parse SQL. There may be an SQL parser available for your language — which is it? — but parsing SQL is quite hard, especially given the range of different syntaxes available. Even in MySQL alone there are many SQL_MODE flags on a server and connection level that can affect how basic strings and comments are parsed, making statements behave quite differently.
The example at dev-explorer goes to amusing lengths to try to cope with escaped apostrophes and trailing strings, but will still fail for many valid combinations of them, not to mention the double quotes, backticks, the various comment syntaxes, or ANSI SQL_MODE.
As bobince said, regular expressions are probably not going to be powerful enough to do this. They're certainly not going to be powerful enough to do it in any halfway elegant manner. The second link cdonner provided also does not address this; most answers there were trying to talk the questioner out of doing this without semicolons; if he had taken the general advice, then he'd have ended up where you are.
I think the quickest path to solving this is going to be with a string scanner function, that examines every character of the string in sequence, and reacts based on a bit of stored state. Rough pseudocode:
Read in a character
If the character is not special, CONTINUE
If the character is escaped (checking this probably requires examining the previous character), CONTINUE
If the character would start a new string or end an existing one, toggle a flag IN_STRING (you might need multiple flags for different string types... I've honestly tried and succeeded at remaining ignorant of the minutiae of SQL quoting/escaping) and CONTINUE
If the character is a semicolon AND we are not currently in a string, we have found a query! OUTPUT it and CONTINUE scanning until the end of the string.
Language parsing is not any of my areas of experience, so you'll want to consider that approach carefully; nonetheless, it's going to be fast (with C-style strings, none of those steps are at all expensive, save possibly for the OUTPUT, depending on what "outputting" means in your context) and I think it should get the job done.
maybe with the following Java Regexp? check the test...
#Test
public void testRegexp() {
String s = //
"SELECT 'hello;world' \n" + //
"FROM DUAL; \n" + //
"\n" + //
"SELECT 'hello;world' \n" + //
"FROM DUAL; \n" + //
"\n";
String regexp = "([^;]*?('.*?')?)*?;\\s*";
assertEquals("<statement><statement>", s.replaceAll(regexp, "<statement>"));
}
I would suggest seeing if you can redefine the problem space so the need to send multiple queries separated only by their terminator is not required.
Try this. Just replaced the 1st ' with \" and it seems to work for both ' and "
;+(?=([^\"|^\\']['|\\'][^'|^\\']['|\\'])[^'|^\\'][^'|^\\']$)