Does Laminas Framework DB Adapter automatically strip tags etc. like mysqli_real_escape_string? - zend-db

I'm using Laminas framework (formerly ZEND Framework) and would like to know if the DB Adapter automatically strip tags etc. at Insert and Select Statements / Execution ($statement->prepare() / $statement->execute()->current()) to avoid SQL injection?
If not what is the best method to implement it while working with LAMINAS DB Adapter? A Wrapper function to get a clean SQL statement?
Before, I was using a wrapper function that cleaned the input with mysqli_real_escape_string

You'd need to provide some sample code in order to get a more accurate answer to this question, however the topic you're talking of here is parameterisation. If you use laminas-db properly, you won't have to call mysqli_real_escape_string or similar to protect against SQL injection. However, you should still be very wary of any potential cross site scripting (XSS) issues if any data written to your database eventually gets echoed back to the browser. See the section below on that.
How to NOT do it
If you do anything like this, laminas-db won't parameterise your query for you, and you'll be susceptible to SQL injection:
// DO NOT DO THIS
$idToSelect = $_POST['id'];
$myQuery = "select * from myTable where id = $idToSelect";
$statement->prepare($myQuery);
$results = $statement->execute();
How to do it properly
Personally, I make use of the Laminas TableGatewayInterface abstraction, because it generally makes life a lot easier. If you want to operate at the lower level, something like this is a much safer way of doing it; it'll ensure that you don't accidentally add a whole heap of SQL injection vulnerabilities to your code
Named Parameters
$idToSelect = $_POST['id'];
$myQuery = "select * from myTable where id = :id";
$statement->prepare($myQuery);
$results = $statement->execute(['id' => $idToSelect]);
Anonymous Parameters
$idToSelect = $_POST['id'];
$myQuery = "select * from myTable where id = ?";
$statement->prepare($myQuery);
$results = $statement->execute([$idToSelect]);
If you do it in a way similar to this, you won't need any additional wrapper functions or anything, the underlying components will take care of it for you. You can use either the named or anonymous parameter version, however I personally prefer the named parameters, as I find it aids code readability and generally makes for easier debugging.
Sanitising Input/Escaping Output
Be very careful with sanitising input. Not only can it lead to a false sense of security, it can also introduce subtle and very frustrating behaviour that the end user will perceive as a bug.
Take this example: Someone tries to sign up to a site under the name "Bob & Jane Smith", however the input sanitisation routine spots the ampersand character and strips it out. All of a sudden, Bob has gained a middle name they never knew they had.
One of the biggest problems with input sanitisation is context. Some characters can be unsafe in one given context, but entirely benign in another. Furthermore, if you need to support the entire unicode character set (as we generally should be unless we have a very good reason to not), trying to sanitise out control characters in data that will potentially pass through several different systems (html, javascript, html, php, sql, etc) becomes a very hard problem due to the way multibyte characters are handled.
When it comes to MySQL, parameterisation pretty much takes care of all of these issues, so we don't need to worry about the "Little Bobby Tables" scenario.
It's much easier to flip all of this on its head and escape output. In theory, the code that's rendering the output data knows in which context it's destined for, so can therefore escape the output for said context, replacing control characters with safe alternatives.
For example, let's say someone's put the following in their bio on a fictional social networking site:
My name is Bob, I like to write javascript
<script>window.postStatusUpdate("Bob is my hero ♥️");</script>
This would need to be escaped in different ways, depending upon the context in which this data is to be displayed. If it's to be displayed in a browser, the escaper needs to replace the angle brackets with an escaped version. If it's going out as JSON output, the double quotes need to be backslash escaped, etc.
I appreciate this is a rather windy answer to a seemingly simple question, however these things should certainly be considered earlier on in the application design; It can save you heaps of time and frustration further on down the line.

Related

Can SQL be injected when the input is hashed?

The passwords and my SQL database are hashed. If the input is hashed, can the field be injected?
The hash is SHA256. My command is to be:
SELECT true FROM accounts WHERE password = '[hex digits]';
I suggest that you not ask this question, because maybe there is a way that you can be in danger, but probably there isn't. Instead, use SQL placeholders and bind variables because that's why they exist.
Any time you are building a SQL statement using data that you are not directly controlling, you are running a risk.
Prepared SQL statements with placeholders also have the benefit of being less work for the database.
Do you have a reason that you can't do it this way?
Strictly speaking, the example you give is safe. Similarly, if you have an application variable that can only be an integer, it is safe. Or even if it's a string, if your code is in control of the string, and you can be sure the string doesn't contain characters that would cause SQL injection (e.g. quote characters like ' or "), then it's safe.
But I agree with Andy Lester's answer — just use query parameters, and then you don't have to think about it. You don't have to wonder if there's an edge case where the input string may be out of your control. You don't have to ask if a string of hex digits is safe or not.
And even more importantly, you don't have to worry that not every developer on your team has the same understanding of how to tell if an input is safe or not. Many developers don't know how to tell safe inputs from non-safe inputs, so it's safest to just establish a policy that all inputs must be parameterized into an SQL query after it is parsed, instead of concatenated into the SQL query before it is parsed.
Imagine you are an electrician. You don't want to touch a live circuit, but if you're well trained you know if you touch it with the right kind of insulated protection, or if you're not grounded, or other conditions are true, then you're probably safe. Probably.
But what is safest is to just make sure the circuit has been disconnected from the power source. That's just a smart habit. It always works, and even if you work with other people who are not as smart as you, it still works.
I agree with the previous answers from Bill and Andy - it's safe, but you should still bind variables / parameterized query parameters. Doing so will:
Improve performance in many databases - the query string will only need to be parsed and cached once
Reduce false positives for human code reviewers and static code analysis
Reinforce the correct coding techniques for anyone reading the code
Future proof it against changes (for example if someone changes the hash output to include quotes)

Custom, user-definable "wildcard" constants in SQL database search -- possible?

My client is making database searches using a django webapp that I've written. The query sends a regex search to the database and outputs the results.
Because the regex searches can be pretty long and unintuitive, the client has asked for certain custom "wildcards" to be created for the regex searches. For example.
Ω := [^aeiou] (all non-vowels)
etc.
This could be achieved with a simple permanent string substitution in the query, something like
query = query.replace("Ω", "[^aeiou]")
for all the elements in the substitution list. This seems like it should be safe, but I'm not really sure.
He has also asked that it be possible for the user to define custom wildcards for their searches on the fly. So that there would be some other input box where a user could define
∫ := some other regex
And to store them you might create a model
class RegexWildcard(models.Model):
symbol = ...
replacement = ...
I'm personally a bit wary of this, because it does not seem to add a whole lot of functionality, but does seem to add a lot of complexity and potential problems to the code. Clients can now write their queries to a db. Can they overwrite each other's symbols?
That I haven't seen this done anywhere before also makes me kind of wary of the idea.
Is this possible? Desirable? A great idea? A terrible idea? Resources and any guidance appreciated.
Well, you're getting paid by the hour....
I don't see how involving the Greek alphabet is to anyone's advantage. If the queries are stored anywhere, everyone approaching the system would have to learn the new syntax to understand them. Plus, there's the problem of how to type the special symbols.
If the client creates complex regular expressions they'd like to be able to reuse, that's understandable. Your application could maintain a list of such expressions that the user could add to and choose from. Notionally, the user would "click on" an expression, and it would be inserted into the query.
The saved expressions could have user-defined names, to make them easier to remember and refer to. And you could define a syntax that referenced them, something otherwise invalid in SQL, such as ::name. Before submitting the query to the DBMS, you substitute the regex for the name.
You still have the problem of choosing good names, and training.
To prevent malformed SQL, I imagine you'll want to ensure the regex is valid. You wouldn't want your system to store a ; drop table CUSTOMERS; as a "regular expression"! You'll either have to validate the expression or, if you can, treat the regex as data in a parameterized query.
The real question to me, though, is why you're in the vicinity of standardized regex queries. That need suggests a database design issue: it suggests the column being queried is composed of composite data, and should be represented as multiple columns that can be queried directly, without using regular expressions.

What must be escaped in SQL?

When using SQL in conjunction with another language what data must be escaped? I was just reading the question here and it was my understanding that only data from the user must be escaped.
Also must all SQL statements be escaped? e.g. INSERT, UPDATE and SELECT
EVERY type of query in SQL must be properly escaped. And not only "user" data. It's entirely possible to inject YOURSELF if you're not careful.
e.g. in pseudo-code:
$name = sql_get_query("SELECT lastname FROM sometable");
sql_query("INSERT INTO othertable (badguy) VALUES ('$name')");
That data never touched the 'user', it was never submitted by the user, but it's still a vulnerability - consider what happens if the user's last name is O'Brien.
Most programming languages provide code for connecting to databases in a uniform way (for example JDBC in Java and DBI in Perl). These provide automatic techniques for doing any necessary escaping using Prepared Statements.
All SQL queries should be properly sanitized and there are various ways of doing it.
You need to prevent the user from trying to exploit your code using SQL Injection.
Injections can be made in various ways, for example through user input, server variables and cookie modifications.
Given a query like:
"SELECT * FROM tablename WHERE username= <user input> "
If the user input is not escaped, the user could do something like
' or '1'='1
Executing the query with this input will actually make it always true, possibly exposing sensitive data to the attacker. But there are many other, much worse scenarios injection can be used for.
You should take a look at the OWASP SQL Injection Guide. They have a nice overview of how to prevent those situations and various ways of dealing with it.
I also think it largely depends on what you consider 'user data' to be or indeed orignate from. I personally consider user data as data available (even if this is only through exploitations) in the public domain, i.e. can be changed by 'a' user even if it's not 'the' user.
Marc B makes a good point however that in certain circumstances you may dirty your own data, so I guess it's always better to be safer than sorry in regards to sql data.
I would note that in regards to direct user input (i.e. from web forms, etc) you should always have an additional layer server side validation before the data even gets near a sql query.

Are sql injection attacks only a threat on a page that has a form?

I know it's a simple question, but in everything I've read, I've never seen this spelled out specifically.
If you do a query on a page, do you need to worry about SQL injection attacks? Or is it only a problem when you ask the user for input?
Thanks!
You don't have to have user input to suffer a SQL injection attack.
Let's say you have a product page that is called using a URL such as this:
product.aspx?ID=123
And in your code you have a query constructed such as this:
string sql = "SELECT * FROM Products WHERE ID = " + Request.Querystring["ID"];
Someone could call your page with this url:
product.aspx?ID=123;DROP Table Students;
And bam, you've just been had.
In addition to ANYTHING that can be passed in via a user, querystring, post, cookie, browser variable, etc. I think it is just good practice to always use parameters, even if you have the literals in your code. For example:
if(SomeCondition)
{
sql = "Select * from myTable where someCol = 'foo'";
}
else
{
sql = "Select * from myTable where someCol = 'bar'";
}
this may be injection safe, but your RDBMS will cache them as two different queries.
if you modiy it to this:
sql = "Select * from myTable where someCol = #myParam";
if(SomeCondition)
{
myCommand.Parameters.Add("#myParam").value = "foo";
}
else
{
myCommand.Parameters.Add("#myParam").value = "bar";
}
You achieve the same result but the RDBMS will only cache it as one query, substituting the parameter at runtime. I use it as a rule of thumb to ALWAYS use parameterized queries, just to keep things consistent, not to mention a slight cache improvement.
SQL injection is caused by unsanitized data. You should always always always sanitize data going into a database. Not just for SQL injection, but also for making your app just work.
For example, some systems won't use my name because it has a ' character in it, and their database is not sanitized. I did not enter my name, my name was taken from another database. Doesn't matter -- the data should be sanitized.
SQL Injection snippets can also come in from the QueryString (aka "URL arguments") passed in with the GET method instead.
As hinted by Billy O'Neal [single quote intended ;-) ], any piece of data that is not intrinsic to the program (or to its very trusted back-end), should be "sanitized". The Sanitizing term seems to imply to be a sophisticated process, but in effect it typically means little more than:
[may vary with your specific SQL server make]
remove (or escape) single quotes characters embedded within a string
watch from strings exceeded the length of the underlying SQL column (in particular if such length is readily long)
A possible reason for the idea that HTTP Forms would be the only source of SQL injection snippets is that a -valid- recommendation is to ensure that one gets the user-supplied submitted text from the Request's form exclusively. Several Web Application frameworks expose the HTTP request as an object which exposes, by default, all key-values pairs from either the QueryString, from a Form, or even from cookies, accessible as from a single hash. While this can be practical for applications that sometimes get the info from a form an sometimes from the querystring, this can facilitate the work of would-be-injectors, because it is easier to craft a URL than a Form. (But with the proper tool, one can also fake a POST request as well...)
No, there are several other cases. For example, you may have some of the variables as a querystring passed into a php page. The 'user' could modify that string to include some dodgy scripting.
http://en.wikipedia.org/wiki/SQL_injection includes a large section on the types of vulnerabilities and how to combat them effectively.
To summarize - any type of input from the user that is used in SQL queries is a potential target of sql injection
Also consider preventing against cross-site-scripting ("XSS").
SQL Injections is possible if you use any kind of data that comes from the browser. It could be form data, querystring data, cookie values, or even data from the request header.
The obvious and easy ways in is the form data and querystring data, but anything that comes from the browser could be spoofed.
Anything that the code takes as input from the HTTP request can be a SQL injection vector:
POST/PUT content
GET URL parameters
Cookies
At a higher level these show up as $_REQUEST or Page.Request values, session variable, it all depends on a miriad of factors. but ultimately, is not just POST forms. Although probably the most prvalent vector is form POST content and GET URL variables.
When the user can modify the values of the parameters of a query, then it can become a threat.
You need to worry about cross site scripting (XSS) attacks in this case if the data you are displaying on the page came from user submitted data.
ESCAPE INPUT, FILTER OUTPUT
As I concern you should never trust this variables: $_POST, $_GET, $_REQUEST, $_COOKIE even $_SERVER can contain malicious code. So ALWAYS make sure that inserted data match your expectation.
For example as an extra paranoid measure on validation email address you can encrypt email address with md5 like this:
"SELECT username FROM users WHERE MD5(email)='" . md5($_POST['email']) . "' AND active=1"
As a general rule parameterized queries should always be used.
It prevents malicious user input from being executed against your database (SQL injection attacks). [You should do user input validation as well to ensure that malicious code isn't rendered on the page and that JavaScript can be run against your server.]
It enables you to re-use your queries.
You can precompile your queries.
It organizes your input and makes it more readable. You might want to use the same parameter in more than one location.
It has better support for different data type such as dates, strings and the like. You won't run into problems with weird characters when you use parameterized queries.
In my use case I always generate parameter based queries. I have a wrapper that will always compile them so that if a second query gets executed in the same request path, it will run that much faster on the same connection. This takes a fair bit of work to setup, but is worth the performance gain in any medium to enterprise level system.
I agree that parameterisation is the best approach.
As an alternative (which might be easier to retro fit into your code, at least initially) doubling the single quotes in a string will prevent SQL Injection.
To take Neil N's example:
sql = "Select * From Products Where ID = " + Request.Querystring["ID"];
wrap the variable in a function that doubles the quotes, and wrap the varible with single quotes too.
sql = "Select * From Products Where ID = "
+ fnSQLSafeParam(Request.Querystring["ID"]);
The function would be something like (VBscript example):
Function fnSQLSafeParam(ByVal strStr)
If IsNull(strStr) or IsEmpty(strStr) then strStr = ""
fnSQLSafeParam = "'" & replace(Trim(CStr(strStr)), "'", "''") & "'"
End Function

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.