Comments in MySql view scripts - mysql

Is it possible to do so? I've tried multiple gui(mysql workbench, navicat, toad for mysql) and none of them save the comments like this:
-- something important
select .....
-- something else important
etc.
Is there a setting I am passing by or is this something that simply cannot be done? I ask since TOAD for Oracle saves what I posted in the code block above.

The mysql command line client will save comments for EVENTs, FUNCTIONs, PROCEDUREs, TRIGGERs, but only if you include the --comments option.
You can always have mysql include comments, by creating a ~/.my.cnf file with the following:
[mysql]
comments=1
Unfortunately, MySQL doesn't seem to preserve comments for VIEWs, even if this option is provided.
The only way I have determined to store comments inside a VIEW, is to include a dummy string at the end of the ORDER BY fields. For example:
CREATE
DEFINER = `root`#`localhost`
SQL SECURITY INVOKER
VIEW
ex
AS
SELECT
*
FROM
mysql.user
ORDER BY
user,
'a comment can go here';
Visit the MySQL Manual for more details.
Before MySQL 5.1, you could use MySQL-specific comments (/*! a comment */) inside VIEWs, but that "feature" was removed in 5.1 and letter. See here for more details.

Related

mysql: logging specific user logins

I'm looking for a stored procedure or something to log user-logins to mysql.
Users will have to be in a positive list.
I need to log user, login time, ip/hostname and query ( query not essential, but a nice-to-have).
My major problem is that I cannot do it via general query log, as is generates +23Gb of log per instance/day (i have 18 instances) and I don't have capacity for it.
I was thinking somewhat in lines of stored procedures, but cannot get my head around it, but not sure if it is the right way to go about it.
Capacity expansion is not an option.
Platform is:
CentOS Linux release 7.3.1611
mysql-community-server-5.6.36-2
Any thoughts on how to solve my issue are welcome.
You may be looking for the mysql init_connect system variable :
A string to be executed by the server for each client that connects. The string consists of one or more SQL statements, separated by semicolon characters.
So basically you want to create a table where logins will be logged, and set the init_connect system variable to something like :
INSERT INTO my_logging_audit
SELECT USER(), NOW()
WHERE USER() IN ('foo', 'bar');

How can i see the definer of a table?

I am currently trying to make a dump of my production database and deploy it in my development database.
Before i do so, i am willing to add a script that will change the definer of the database's tables to a definer that is used in my development database after the deployment is complete.
Is there a way to tell what is the current definer for a table?
Iv'e tried SHOW CREATE TABLE but it doesn't give me the definer of that table.
Note that i already have a script that does so for another schema, but i am not sure if the definer for the other schema is the same.
Also, i couldn't find an answer to this over the internet, so i am asking this here.
Thanks.
Databases and tables do not have a 'definer' (or DBO) in MySQL.
"users" are "GRANTed" permissions to access databases and/or tables. Will having different GRANTs solve whatever you are trying to solve?
A related topic... Stored Routines execute as the "invoker" or a specified "user" (your choice when creating the routine), but I don't think that is what you are asking about.
You, or others lead to this question, may be thinking of procedures/functions/triggers/events/views that may be correlated with the tables you're attempting to find definers for.
Stored Object Access Control
Stored programs (procedures, functions, triggers, and events) and views are defined prior to use and, when referenced, execute within a security context that determines their privileges. The privileges applicable to execution of a stored object are controlled by its DEFINER attribute and SQL SECURITY characteristic.
In which case, you may find the following queries helpful:
SHOW CREATE PROCEDURE proc_name
SHOW CREATE FUNCTION func_name
SHOW TRIGGERS FROM db_name
SHOW CREATE EVENT event_name
SHOW CREATE VIEW view_name

Mysql Client Option: How to Use –comments in mysql client

I am learning mysql client program.I was trying to understand client option -comments.I have seen document regarding this in mysql MySQL 5.6 Reference Manual.
But I didn't get any code example to illustrate this option.Please tell me how to Enter this command in correct syntax.Also it would more clear to me if i get opportunity to see this example on any online mysql terminal.Thanks
MySQL comments are lines that begin with #, like Unix shells. It's as simple as that. Example:
# this is a comment describing the next line which select all data from the `users` table
SELECT * from `users`;
The -comments argument to the mysql command line client is used to tell it to send the comments to the server which is not done by default. These comments are later visible in the query logs and stored procedures (which is the simplest way to see it in action).

How can I edit a view in MySQL Workbench without it auto prefixing a database name to the tables/views used

When I create a view, I create it in the context of the default database. So none of my references to table have a prefix which explicitly specify a database. However, when I edit a view in Workbench it automatically adds the database prefix!
I don't want the database prefix because when I restore a database under a different name it causes the restore to fail.
Is this possible to stop the prefixing in a view edit or there another way to get round the restore issue?
see https://bugs.mysql.com/bug.php?id=85176
The mysql 8.0.3 or above has been fixed
That's not possible. Views are stored in specific databases, not in some space "above" all databases. Consider following...
use playground_a; /*or whatever database*/
create view view_whatever as
select * from table_whatever;
use playground_b;
select * from view_whatever; /*here you will get an error that view_whatever does not exist*/
select * from playground_a.view_whatever; /*this works*/
That's why there will always be database prefixes in the view definition.
The only possibility I see, would be to use a stored procedure with a database name as parameter. In the procedure you'd use a prepared statement to execute a concated string of your query and the database name parameter. Of course this comes with downsides, like i.e. you can't add a where clause easily.
Creating the view without explicitely specifying a schema is a convenience feature. Behind the scenes the view is still saved in a specific schema (the default one in this case). When editing the source code is retrieved from the server which returns the real code (including the schema qualification). Hence already when you send the view code the association happens and cannot be removed again later.
Here is the command I use to create the backup:
mysqldump -u xxxxxx -pxxxxxx --routines database_a | gzip -9 > $FULLGZIPPATH
If you aren't easily able to update to MySQL 8.X then a workaround I've implemented was a post-processing step performed on the dump file itself prior to importing. I just remove the explicit prefixed db name, since the import process / view creation doesn't need it.
PowerShell -Command ^
"filter replace-dbname { $_ -replace '`<DB_NAME>`.`', '`' }"^
"Get-Content dump.sql -ReadCount 10 | replace-dbname | Add-Content replaced_dump.sql"
I've used PowerShell since I'm on Windows, but any scripting language will do. The only notes are that:
You'll need to do the replacement a-few-lines-at-a-time if you can't afford to read the entire dump into memory. Our dumps are about 11GB, which'd be a strain on our testing server's resources.
In my script I'm not doing an in-place string replacement, so it'll create a new dump file replaced_dump.sql alongside the original dump.sql. For me this was useful for diagnostics, because it meant if there was an issue, I didn't have to dump it again. Again, depending on your dump/disk size this might be an issue.
If your database happens to have `<DB_NAME>`.` as content in something like a text-field, this basic approach will also remove the string there as well.

MySQL Injection - Use SELECT query to UPDATE/DELETE

I've got one easy question: say there is a site with a query like:
SELECT id, name, message FROM messages WHERE id = $_GET['q'].
Is there any way to get something updated/deleted in the database (MySQL)? Until now I've never seen an injection that was able to delete/update using a SELECT query, so, is it even possible?
Before directly answering the question, it's worth noting that even if all an attacker can do is read data that he shouldn't be able to, that's usually still really bad. Consider that by using JOINs and SELECTing from system tables (like mysql.innodb_table_stats), an attacker who starts with a SELECT injection and no other knowledge of your database can map your schema and then exfiltrate the entirety of the data that you have in MySQL. For the vast majority of databases and applications, that already represents a catastrophic security hole.
But to answer the question directly: there are a few ways that I know of by which injection into a MySQL SELECT can be used to modify data. Fortunately, they all require reasonably unusual circumstances to be possible. All example injections below are given relative to the example injectable query from the question:
SELECT id, name, message FROM messages WHERE id = $_GET['q']
1. "Stacked" or "batched" queries.
The classic injection technique of just putting an entire other statement after the one being injected into. As suggested in another answer here, you could set $_GET['q'] to 1; DELETE FROM users; -- so that the query forms two statements which get executed consecutively, the second of which deletes everything in the users table.
In mitigation
Most MySQL connectors - notably including PHP's (deprecated) mysql_* and (non-deprecated) mysqli_* functions - don't support stacked or batched queries at all, so this kind of attack just plain doesn't work. However, some do - notably including PHP's PDO connector (although the support can be disabled to increase security).
2. Exploiting user-defined functions
Functions can be called from a SELECT, and can alter data. If a data-altering function has been created in the database, you could make the SELECT call it, for instance by passing 0 OR SOME_FUNCTION_NAME() as the value of $_GET['q'].
In mitigation
Most databases don't contain any user-defined functions - let alone data-altering ones - and so offer no opportunity at all to perform this sort of exploit.
3. Writing to files
As described in Muhaimin Dzulfakar's (somewhat presumptuously named) paper Advanced MySQL Exploitation, you can use INTO OUTFILE or INTO DUMPFILE clauses on a MySQL select to dump the result into a file. Since, by using a UNION, any arbitrary result can be SELECTed, this allows writing new files with arbitrary content at any location that the user running mysqld can access. Conceivably this can be exploited not merely to modify data in the MySQL database, but to get shell access to the server on which it is running - for instance, by writing a PHP script to the webroot and then making a request to it, if the MySQL server is co-hosted with a PHP server.
In mitigation
Lots of factors reduce the practical exploitability of this otherwise impressive-sounding attack:
MySQL will never let you use INTO OUTFILE or INTO DUMPFILE to overwrite an existing file, nor write to a folder that doesn't exist. This prevents attacks like creating a .ssh folder with a private key in the mysql user's home directory and then SSHing in, or overwriting the mysqld binary itself with a malicious version and waiting for a server restart.
Any halfway decent installation package will set up a special user (typically named mysql) to run mysqld, and give that user only very limited permissions. As such, it shouldn't be able to write to most locations on the file system - and certainly shouldn't ordinarily be able to do things like write to a web application's webroot.
Modern installations of MySQL come with --secure-file-priv set by default, preventing MySQL from writing to anywhere other than a designated data import/export directory and thereby rendering this attack almost completely impotent... unless the owner of the server has deliberately disabled it. Fortunately, nobody would ever just completely disable a security feature like that since that would obviously be - oh wait never mind.
4. Calling the sys_exec() function from lib_mysqludf_sys to run arbitrary shell commands
There's a MySQL extension called lib_mysqludf_sys that - judging from its stars on GitHub and a quick Stack Overflow search - has at least a few hundred users. It adds a function called sys_exec that runs shell commands. As noted in #2, functions can be called from within a SELECT; the implications are hopefully obvious. To quote from the source, this function "can be a security hazard".
In mitigation
Most systems don't have this extension installed.
If you say you use mysql_query that doesn't support multiple queries, you cannot directly add DELETE/UPDATE/INSERT, but it's possible to modify data under some circumstances. For example, let's say you have the following function
DELIMITER //
CREATE DEFINER=`root`#`localhost` FUNCTION `testP`()
RETURNS int(11)
LANGUAGE SQL
NOT DETERMINISTIC
MODIFIES SQL DATA
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DELETE FROM test2;
return 1;
END //
Now you can call this function in SELECT :
SELECT id, name, message FROM messages WHERE id = NULL OR testP()
(id = NULL - always NULL(FALSE), so testP() always gets executed.
It depends on the DBMS connector you are using. Most of the time your scenario should not be possible, but under certain circumstances it could work. For further details you should take a look at chapter 4 and 5 from the Blackhat-Paper Advanced MySQL Exploitation.
Yes it's possible.
$_GET['q'] would hold 1; DELETE FROM users; --
SELECT id, name, message FROM messages WHERE id = 1; DELETE FROM users; -- whatever here');