A column with implanted PHP functionality - php

Lets say I have this PHP function:
function strlow($string){
strtolower(trim($string));
}
Now lets say I have a table with 2 columns [id - title] and I want to make all titles that are going to be inserted into the table in lowercase, The usual way is
$title = strlow($title);
$query = "INSERT INTO table (title) VALUES ($title);
Is there for example a way to implant in the column itself in the database the function, So instead of doing the strlow() by the PHP, the Database does it?
If yes, I wish for an example built on mine.

You could update your query to handle this if you really wanted (but I would still rather do this in the application layer) using the MySQL TRIM and LOWER commands:
INSERT INTO table (title) VALUES (TRIM(LOWER(($title)))
The reason I say I would rather do this in the application layer is that if you decide to switch database systems in future, you need to remember to port over all your database formatting rules such as these at that time too which although doesn't seem too bad now, trust me, in the future, you will forget.
In addition to this, if you ever want to add further logic to what you are putting in to the database you will likely find your options more limited in MySQL than you will in your application layer.
Also, please for my sanity look up how to use parametrized queries because you are wide open to SQL injection attacks at the moment. There is a great post here that covers this.

$query = "INSERT INTO table (title) VALUES (LCASE($title));

Related

Escape a pdo query, is that necessary?

My question of to day is. Do i need to escape PDO in my script?
$columns = implode(", ",$column);
$query = ''.$query.' '.$columns.' FROM '.$table.'';
$dbh_query = $dbh->prepare($query);
$dbh_query->execute();
$dbh_querys = $dbh_query->fetchAll();
return $dbh_querys;
The whole script can be found at.
https://github.com/joshuahiwat/crud/blob/master/control/query_connector.class.php
Can someone explain why do i need a escape at this time or why not.
I like to hear from you, thanks a lot!
The parts of your query that are dynamic are the table name and column names. You can't use bind functions for these parts of the query. Bind functions can be used only for the parts of the query that would otherwise be a simple value in an SQL query. Like a numeric constant, or a quoted string or quoted date literal.
To avoid SQL injection from dynamic table names or column names, you have the following choices:
Use values that are predefined in your class, or otherwise certain to be safe. Don't use external content from users or any other source.
Use escaping. Note that the function PDO::quote() doesn't do the kind of escaping you need for table names or column names.
Create a "allowlist" of known table names and the column names for the respective table, and compare the dynamic input to the allowlist. If it doesn't match the allowlist, raise an error.
First of all you need to understand that the word you are using - "escape" - is meaningless.
What you probably mean is "to make your query safe from SQL injection". But, unfortunately, there is no such magic "escaping" that will make some abstract query safe.
The traditional query building assumes that all the query parts beside data values are hard-coded, while data values are bound via placeholders, like this:
$query = 'SELECT col1, col2 FROM some_table WHERE id = ?';
$stmt = $dbh->prepare($query);
$stmt->execute([$id]);
$row = $stmt->fetch();
This kind of a query considered safe.
In your case of a dynamically constructed query, every part is potentially vulnerable.
And here it is very important to understand that a burden of sanitizing all the query parts is entirely on this function. You cannot dismiss the danger simply claiming that your data is coming from the trusted source. That's a slippery ground because people often have no idea whether their source is trusted or not.
So, if take your question as "Do I have to protect this code from SQL injection", than the answer is - YES, YOU HAVE.
In the meantime you are protecting only a small part of your query - the data values. So you still have to protect (this term is much better than "escape") all other parts.
On a side note, your code is connecting to database every time it runs a query, which is highly inefficient and makes it impossible to use some database features.

How to protect variable table names against SQL injection in PHP

I am building a web app which relies heavily on a database. Here is an example of the type of query I use a lot:
CREATE TABLE item$userenteredname$username
Basically each time a create a new item, there is a table which stores info for every time something is added. So I need the table names to remain the same.
I recently spent quite a while updating my code to use PDO. I understand how to prepare statements and bind values, but you can't do this with table names. Haven't been able to find a proper answer to my question, which to clarify is...
How can I sanitise user input against sql injection when I can't use prepare's or mysql_real_escape_string because the variable is in a table name?
My strategy for this use case would be to strip out non-alphanumeric characters.
$usereneteredname = preg_replace('/[^0-9a-zA-Z_]/', '', $usereneteredname);
$username = preg_replace('/[^0-9a-zA-Z_]/', '', $username);
// then "CREATE TABLE item$userenteredname$username"
This strategy is called whitelisting. That preg_replace call will replace anything that isn't 0-9a-zA-Z_.
Further considerations:
You may also wish to validate the string lengths after the output, and make sure you are operating on a string not an array.

What do you think about this solution instead of using tables name as a PDO parameter?

I'm using the PDO class to connect to mysql becuase I noticed that it's the best and surest way to do it. I noticed also that i can't use PDO parameter in tables name so I saw this question: Can PHP PDO Statements accept the table or column name as parameter?
I use in my application a GET parameter as a table name and now my question is:
It's better to use
function buildQuery( $get_var )
{
switch($get_var)
{
case 1:
$tbl = 'users';
break;
}
$sql = "SELECT * FROM $tbl";
}
or just give a "show tables" in MySql and compare every single table resulted from this command to the table passed via GET?
Thank you all!
Although "Just give a "show tables" in MySql and compare every single table resulted from this command to the table passed via GET" approach is flawed, it is not the main problem.
You are no the first one who, having no basic knowledge on database design, inventing yet another square wheel and then come to the community for help to make it move.
You need to rewind your ideas back some.
And reconsider database design, which should never involve dynamical tables, each of them used as a some sort of plain text file, queried with just SELECT * FROM table.
Please learn some relational database design basics first, then create a sensible design, then query your tables the way everyone do it: keep all the data in one table and use WHERE clause to get specific data.
Youre first solution is fine.
But don't pass the tablename via get. just pass a number which you can lookup via switch the table name.

SELECT FROM a database named from a value in a JOIN

I have a SQL statement that has to pull information from two databases, one is a constant and known database, and the other is dynamically found in the first database. The databases structure looks like this:
(database) lookup
(table) test
(fields) key, database_name
(row sample) "foo", "database_foo"
(database) database_foo
(table) bar
(fields) important1, important2
(row sample) "silly", "test"
So my SQL statement looks like this:
SELECT
test.key as key,
test.database_name as database_name,
bar.important1 as important1,
bar.importnat2 as important2,
FROM
lookup.test as test,
(database_name).bar as bar, # this, obviously, doesn't work
WHERE
key = 'foo'
LIMIT 1;
Is there a way I can make this work, or is it better for me to just do two separate SQL statements, one for the lookup, and one for the database?
If you must do it this way then you need to use dynamic sql and a two statements.
You have your query built as a string and then you run an EXEC on the query once it's constructed.
In this case you would have a string variable for the db name, then you would create a query from this variable and your literal query, then you would simply execute it.
Be aware, though, this makes you vulnerable to SQL Injection if you don't control the input parameters.
Erland Sommarskog has a great primer on using dynamic SQL:
http://www.sommarskog.se/dynamic_sql.html
EDIT: From #BryanMoyle comment below, you will likely need to do both a separate query and dynamic sql. You need to extract the value in order to determine the other DB name... Since you cannot use the DB name as a variable otherwise, you'll need to SELECT this information first, then stick it into the subsequent query.
I personally go for 2 separate statements; it would make it easier to control for errors such as the the lookup provides a row, that the row provides a valid database, etc.
As Matthew pointed out, beware of SQLIA and sanitize all user input. I like to MD5 hash inputs and compare to the hash of the value looked up.
I'd go for two separate queries, mediated by php: It's simpler, more robust, and will keep you sane and productive. Write one query to find out which database you should be talking to. Use php (not SQL) to direct your query to that database:
$row = $lookup->prepare("SELECT database_name WHERE key = 'foo'")->execute()->fetch();
$db = $row[0];
Then you contact $db and ask for the row with key foo. Use PHP code to select the right open connection, or switch databases inside the connection with USE:
$query2 = "USE " . $db . "; SELECT * FROM bar where key == 'foo'"

Select more tables after FROM statement?

this is part of a security audition, so there is no way to "change" the query.
Basically, what I found is a flaw that allows statement manipulation, so basically it goes like:
$query = "DELETE FROM `products` WHERE `products`.`whatever` = $variable";
This is PHP, so as far as I know there is no way to execute multiple queries. Using this SQL Injection, I was able to "clear" this table by running "0 OR 1=1#".
This works just fine, but it doesn't allow me to choose more tables to delete from.
This is, in pseudocode what I want to do:
DELETE FROM `products` WHERE `products`.`whatever` = **0 OR 1=1, FROM `othertable` WHERE `othertable`.`othercolumn` = 0 OR 1=1**
Is this plausible anyhow?
If this isn't reliable, is there any other way I could use this?
You can't have multiple FROM clauses for the same DELETE statement, so you can't go about it exactly how you'd want to. If the MySQL db had 'allow multiple queries per statement' turned on, you could try to terminate the one DELETE query and then tack on another to the end, so that it'd look like this:
DELETE FROM `products` WHERE `products`.`whatever` = **0 OR 1=1; DELETE FROM `othertable` WHERE `othertable`.`othercolumn` = 0 OR 1=1**
But that's about it.
Perhaps I don't fully understand the question, but what I take away is that you're building a SQL command as a string and running that string directly against a MySQL database.
You can separate multiple commands using the command separator (usually ';'), so you could run pretty much any command you want as this comic aptly illustrates.
If your database configuration supports multiple commands (or might in the future if someone changes today's setting), you want to ensure you don't have a command separator as part of the input. See this article for advice on sanitizing your input to prevent this type of attack.
As you stated, multiple queries are not supported by the normal MySQL driver module. From the manual for mysql_query:
mysql_query() sends a unique query
(multiple queries are not supported)
to the currently active database on
the server that's associated with the
specified link_identifier .
Unfortunately for your injection efforts, DELETE syntax only supports multiple table deletes by specifying them in the FROM clause. Your injected variable is part of the WHERE, so the most damage you can do is to the single specified table.
Contrary to popular belief, you can actually run multiple MySQL statements from PHP, you just have to be using a different database driver module such as MySQLi. See MySQLi::multi_query().

Categories