{"id":1703,"date":"2012-01-30T16:29:03","date_gmt":"2012-01-30T16:29:03","guid":{"rendered":"http:\/\/kedar.nitty-witty.com\/?p=1703"},"modified":"2014-06-25T13:11:48","modified_gmt":"2014-06-25T13:11:48","slug":"access-control-in-mysql-stored-routines-by-example-definer-invoker-sql-security","status":"publish","type":"post","link":"https:\/\/kedar.nitty-witty.com\/blog\/access-control-in-mysql-stored-routines-by-example-definer-invoker-sql-security","title":{"rendered":"Access Control in MySQL Stored Routines: DEFINER, INVOKER &#038; SQL SECURITY"},"content":{"rendered":"<p>MySQL Stored Routines (functions and procedures) are not only used for improving performance but also they&#8217;re handy when it comes to enhancing security and restricting user access. This post briefs you about security aspects of stored routines by means of example.<\/p>\n<p>By the definition of a Stored Routine,<br \/>\n&#8211; DEFINER clause specifies the creator of the stored routine.<br \/>\n&#8211; SQL SECURITY clause specifies the execution context of the stored routine.<\/p>\n<p>Now let&#8217;s start with an example:<\/p>\n<p>Create a very basic stored routine in test database:<\/p>\n<p><code>DELIMITER \/\/<br \/>\nCREATE PROCEDURE user_cnt()<br \/>\nBEGIN<br \/>\n  SELECT COUNT(*) as total_user FROM mysql.user;<br \/>\nEND;\/\/<br \/>\nDELIMITER ;<\/code><\/p>\n<p>Our current user is: root@localhost<br \/>\n[ You can see your current user by issuing <code>select CURRENT_USER(); <\/code> ]<\/p>\n<p>Call the procedure:<br \/>\n<code>CALL user_cnt()\\G<br \/>\ntotal_user: 10<\/code><\/p>\n<p>Here, We created a stored routine using root@localhost user.<br \/>\n&#8211; DEFINER: The user who creates this procedure. i.e. root@localhost<br \/>\n&#8211; SQL SECURITY: Defines under whose privileges the routine will be executed; defaults to DEFINER. i.e. root@localhost<\/p>\n<p>As SQL SECURITY is set to DEFINER, a user even with only EXECUTE permission for routine can call and get the output of the stored routine regardless of whether that user has permission on mysql database or not. <\/p>\n<p>Lets see how this works. Create a &#8220;execuser&#8221; with limited privileges:<br \/>\n<code>GRANT EXECUTE ON test.* TO 'execuser'@'localhost' IDENTIFIED BY 'execuser' ;<br \/>\nFLUSH PRIVILEGEES;<\/code><\/p>\n<p>Login using execuser to mysql prompt and call the procedure created under test database:<br \/>\n<code>mysql> CALL user_cnt()\\G<br \/>\ntotal_user: 10<\/code><\/p>\n<p>Now check that below command fired by execuser fails due to lack of privileges:<br \/>\n<code>mysql> select count(*) from mysql.user;<br \/>\nERROR 1142 (42000): SELECT command denied to user 'execuser'@'localhost' for table 'user'<\/code><\/p>\n<p>&#8211; Thus stored procedure allows us to restrict users to access tables directly but still getting access to certain data.<br \/>\n&#8211; User execuser@localhost is not having permission on mysql database and still he could get the data.<br \/>\n&#8211; As the SQL SECURITY was set to DEFINER (default), the execution of the routine happened under the security context of root@localhost user and returned the result. <\/p>\n<p>Is this behaviour something that you don&#8217;t want to happen? Hmmm we have a way out here.<br \/>\nLets rewrite the stored procedure as below:<\/p>\n<p><code>DELIMITER \/\/<br \/>\nDROP PROCEDURE IF EXISTS user_cnt;<br \/>\nCREATE DEFINER='root'@'localhost' PROCEDURE user_cnt()<br \/>\nSQL SECURITY INVOKER<br \/>\nBEGIN<br \/>\n  SELECT COUNT(*) as total_user FROM mysql.user;<br \/>\nEND;\/\/<br \/>\nDELIMITER ;<\/code><\/p>\n<p>&#8211; Did you note &#8220;SQL SECURITY INVOKER&#8221;!! That&#8217;s our saviour.<br \/>\n&#8211; We&#8217;ve specified the DEFINER attribute explicitly.<br \/>\n&#8211; SQL SECURITY decides under whose privileges the stored routine gets executed! Here it is INVOKER, the user that CALLs the routine!<\/p>\n<p>Let&#8217;s check through execuser@localhost user:<br \/>\n<code>mysql> call user_cnt();<br \/>\nERROR 1142 (42000): SELECT command denied to user 'execuser'@'localhost' for table 'user'<\/code><\/p>\n<p>So, this is now pretty clear that the stored routine tried to execute the SELECT query under INVOKER&#8217;s (execuser@localhost) privileges; and the routine failed as the INVOKER has no privileges on user table.<\/p>\n<p>Finally, a few points:<br \/>\nTogether DEFINER &#038; SQL SECURITY clauses define the security context to be used during routine execution time.<br \/>\nThe DEFINER attribute defaults to the current user &#038; defines the creator of the Stored Routine.<br \/>\nSQL SECURITY defines the execution permission of the stored routine and defaults to DEFINER.<\/p>\n<p>I hope this cleared the basics; thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"MySQL Stored Routines (functions and procedures) are not only used for improving performance but also they&#8217;re handy when it comes to enhancing security and restricting user access. This post briefs&hellip;\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[8,377],"tags":[299,300,301,427,303,298,302],"class_list":{"0":"post-1703","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-mysql","7":"category-mysql-articles","8":"tag-acess-control","9":"tag-definer","10":"tag-invoker","11":"tag-mysql","12":"tag-mysql-stored-procedure","13":"tag-mysql-stored-routines","14":"tag-sql-security"},"aioseo_notices":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/posts\/1703","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/comments?post=1703"}],"version-history":[{"count":11,"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/posts\/1703\/revisions"}],"predecessor-version":[{"id":1712,"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/posts\/1703\/revisions\/1712"}],"wp:attachment":[{"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/media?parent=1703"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/categories?post=1703"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kedar.nitty-witty.com\/blog\/wp-json\/wp\/v2\/tags?post=1703"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}