Say, I have a complex MySQL procedure. The procedure is basically a complex SELECT query that use data inside a table to output some records.
For convenience, the procedure need to write to a temporary table to calculate the final result.
So can I grant properly so that a user that can only read the database can call this procedure to get its output, although the procedure actually need to write to the database? Because essentially this procedure don't intend to write, it just cache some data to a specific table with a name start with underscore so it shouldn't break anything seriously, beside costing storage of disk.
A stored program or view that executes in definer security context executes with the privileges of the account named by its DEFINER attribute. These privileges may be entirely different from those of the invoking user.
https://dev.mysql.com/doc/refman/5.7/en/stored-programs-security.html
As long as the user defining the procedure has the necessary permissions and doesn't explicitly force the procedure to run in INVOKER context, the permissions of the invoking user have no impact on what the procedure can do. The permissions of the defining user apply to the procedure's actions.
The invoking user only needs to be able to run it. No special arrangements are necessary, because this is the default behavior.
The DEFINER defaults to the user creating the procedure. If that account has the SUPER privilege, they can actually declare a different definer account whose privileges will apply.
Typically, stored procedures in MySQL operate with privileges associated with the procedure's definer, not the user who invokes the procedure, who only needs execute privilege on the procedure.
A stored procedure can be configured to run in invoker context, thus executing with same privilege as the invoking user, but this is not common.
Just make sure when you define the procedure the definer has appropriate permission to do everything that needs to be done during execution.
Related
There are procedures as below for a lot of things. What are the benefits of doing this? Are there any security benefits?
DELIMITER //
CREATE
DEFINER = 'webappuser'#'localhost' PROCEDURE find_number_users()
SQL SECURITY INVOKER
BEGIN
SELECT COUNT(*) as total_users FROM user WHERE userCost = 1;
END;
//
DELIMITER ;
Procedures can be used to implement some simple security mechanisms.
If a procedure is defined with SQL SECURITY DEFINER then it runs with the grants of the definer. This allows you to restrict access to some databases or tables, but then allow restricted users to execute procedures that access them. So they can't write arbitrary queries that access the tables, but they can get the data in ways that are controlled by the database administrator who defines the procedures.
The procedure you showed has SQL SECURITY INVOKER, so it doesn't take advantage of this feature.
This can also be done with views.
I have a scenario where I need to have a read-only user to a database. This user can read tables, as in just view anything. However after executing the below command :
GRANT EXECUTE
ON `randomdatabase`.*
TO readonlyuser#192.168.16.85;
I am able to read any table or view. But when it comes to UDFs and stored procedures, I am not able to execute them. But if I grant execute privilege for the user, I get to execute the UDFs and procedures, even those which have the code to insert to a table. So this contradicts to being a read-only user. Is there way to prevent executing specific UDFs and procedures which can insert to a table?
When you grant EXECUTE privilege to a routine, execute permission is what the user gets. The permissions do not examine what the content / behavior of the routine is. This allows for you to allow user to modify the content of the database, but only through set of rules defined in the routines.
If you need only to grant read-only access, then you need to exclude those routines that add/delete/update the database.
This behavior is not specific to MySQL, but all other databases work the same way.
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
I use SQLyog to write procedures and functions in a remote MySQL database I am developing. The database has only one username/password. It is accessed via a front end executable application that I have written in Delphi and which is used by a couple of dozen different people, all using the same username.
When I use SQLYog to write a procedure using, for example,
CREATE PROCEDURE age_frequency_count(IN bin_size INT)
The resulting procedure gets the definer put in whether I like it or not, resulting in
CREATE DEFINER=<the_user_name>#<my_IP_address> PROCEDURE age_frequency_count(IN bin_size INT)
(I think this is being done by MySQL, not by the SQLYog DBMS.)
From reading the documentation and from posts here on SO, I have a rough, but rather confused idea of how the definer is used to say what permissions are needed to execute, or maybe alter, the procedure and what the procedure is allowed to do, but I would welcome some clarification.
Question
If my IP address is in the definer, can the procedure still be executed by other people who will be logging in from a different IP address (although with the same username)?
Can someone please clarify what the definer is doing? i.e. what can a connection from my IP address do that connections from other IP addresses can't?
I use the DEFINER clause to create a stored procedure with the security privileges of a powerful user that also has UPDATE, DELETE, SELECT, and INSERT rights to a particular database table. Then, I only grant EXECUTE on that stored procedure to a minon user (some people call it a www user, versus the more powerful wwwproxy user).
In this way, the minion can only execute designated stored procedures and has no UPDATE, DELETE, SELECT, INSERT, or other rights on a database table.
I hope that helps frame the idea behind the DEFINER clause. Use it to separate power from tasks.
You are correct, by default, MySQL uses the identity of the current user as the DEFINER when creating a stored procedure. This identity could be the identity of the front-end application (so to speak), or, like I said, you can use a proxy user that has normal table privileges. Then the application user would be the minion with only one privilege on the stored procedure, EXECUTE.
In short, if the default DEFINER user does not represent what the front end application uses to login to the database, and you want it to, then you need to change the stored procedure with ALTER, if possible.
On the other hand, the better idea would be to use the minon/proxy scenario. Application users on the Internet have no bearing on the IP that ends up in the stored procedures DEFINER clause. All that matters is the IP of where your app is logging in from to MySQL. Your app is talking to the database, not user agents on peoples' computers. However, that notion is, generally, a point of initial confusion. You are fine!
Hope that helps.
I created a stored procedure, 'myProc', in a MySQL database.
Then I dropped this procedure.
I wanna create again a procedure with the same name to the before.
I create the procedure again and name it 'myProc'.
CALL myProc();
But, when I execute this procedure, it is an error like that "PROCEDURE myProc does not exit".
Also code is same to the before one.
Unable to call a stored procedure in MySQL
You've created a procedure in MySQL 5. You've granted EXECUTE privileges to your application's user account. But when your application prepares a statement to call that procedure, an exception is thrown. Perhaps it's a NullPointerException deep inside of ConnectorJ. Perhaps the exception claims that the procedure does not exist. Or perhaps you've gotten lucky enough to get the exception that leads you down the right path(Driver requires declaration of procedure to either contain a ''\nbegin'' or ''\n'' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types). Here are the troubleshooting steps that I've gleaned from hours of searching the MySQL forums.
First, open two console windows. In one, log into MySQL as the application user. In the other, log in as root. In your app window, list the databases.
SHOW DATABASES;
If your application's database does not appear, then you should go to your root window and grant database privileges.
USE mydatabase;
GRANT ALL ON mydatabase TO appuser;
Now go back to the app window. List the databases again to ensure that it appears. Now that it does, go into it.
USE mydatabase;
Once you're in, try to view the procedure.
SHOW CREATE PROCEDURE myproc /G
One of three things will happen. If you get a message saying "PROCEDURE myproc does not exist" then the app user does not have privileges for it. Go back to the root window and grant them.
GRANT EXECUTE ON PROCEDURE myproc TO appuser;
The second thing that might happen is that the procedure will be found, but the body will not be listed. Instead, it will say "Create Procedure: NULL". If so, go back to the root window and take care of that.
GRANT SELECT ON mysql.proc TO appuser;
The third thing that could happen is what you want to happen; the body of the procedure will be listed. Now you should be able to call the procedure from your application.
Warnings
You may be tempted to take a couple of short-cuts to resolve problems like these. Please don't. Shortcuts may cause bigger problems down the road.
The first thing you might try is to use the root account from within your application. This is extremely dangerous. Security comes in layers. While you should use stored procedures and prepared statements to avoid SQL injection attacks, you should also apply the principle of least privilege just in case they occur anyway. Allowing your application to connect as root gives an attacker access to your most valuable resource: your data. But giving each part of the application a separate account with only the privilege that it requires quarantines the bad guy.
The second thing that you might try after hours of research is to set the "noAccessToProcedureBodies" flag in the ConnectorJ connection string. Please avoid this flag, as it circumvents the parameter type checking that the JDBC driver provides for you. This flag causes ConnectorJ to convert all of the parameters to strings, which MySQL will then convert back to the required type.
But by walking through the problem step-by-step, these short-cuts should not be necessary.
Reference
http://adventuresinsoftware.com/blog/?p=74