{"id":230,"date":"2009-04-03T20:49:25","date_gmt":"2009-04-03T18:49:25","guid":{"rendered":"https:\/\/www.sqlinthewild.co.za\/?p=230"},"modified":"2010-12-10T09:01:13","modified_gmt":"2010-12-10T07:01:13","slug":"dynamic-sql-and-sql-injection","status":"publish","type":"post","link":"https:\/\/www.sqlinthewild.co.za\/index.php\/2009\/04\/03\/dynamic-sql-and-sql-injection\/","title":{"rendered":"Dynamic SQL and SQL injection"},"content":{"rendered":"<p>When I wrote about the catch-all queries, someone asked why the dynamic SQL that I offered wasn&#8217;t vulnerable to SQL injection. I thought I&#8217;d go into the whys and the wherefores of that in a little bit more detail.<\/p>\n<p>I&#8217;m just going to look at SQL injection from the aspect of dynamic SQL. The front-end code aspect has been dealt with hundreds of times, most recently here &#8211; <a href=\"http:\/\/www.simple-talk.com\/community\/blogs\/philfactor\/archive\/2009\/03\/30\/72651.aspx\">http:\/\/www.simple-talk.com\/community\/blogs\/philfactor\/archive\/2009\/03\/30\/72651.aspx<\/a><\/p>\n<p>The most important thing to realise with SQL Injection (and with all other forms of command injection) is that it requires that a user-inputted string be incorperated as part of a command that&#8217;s going to be executed. Not as part of a paramter value, but as part of the command itself.<\/p>\n<p>Let me show you want I mean.<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">DECLARE @sSQL varchar(500)\r\nSET @sSQL = 'SELECT * FROM sys.objects'\r\n\r\nEXECUTE (@sSQL)<\/pre>\n<p>In this exeedingly simple example, there&#8217;s no possibility for SQL injection. There&#8217;s no user-inputted string that can become part of the command. Let&#8217;s look at two slightly more complex examples<\/p>\n<p><strong>Example 1:<\/strong><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nDECLARE @inputParam VARCHAR(100) -- Assume this comes from user input\r\nDECLARE @sSQL varchar(500)\r\n\r\nSET @sSQL = 'SELECT * FROM '\r\n\r\nIF @inputParam = 'Table1'\r\nSET @sSQL = @sSQL + 'Table1'\r\nIF @inputParam = 'Table2'\r\nSET @sSQL = @sSQL + 'Table2'\r\nIF @inputParam = 'Table3'\r\nSET @sSQL = @sSQL + 'Table3'\r\nIF @inputParam = 'Table4'\r\nSET @sSQL = @sSQL + 'Table4'\r\n\r\nEXECUTE (@sSQL)<\/pre>\n<p><strong>Example 2:<\/strong><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nDECLARE @inputParam VARCHAR(100) -- Assume this comes from user input\r\nDECLARE @sSQL varchar(500)\r\n\r\nSET @sSQL = 'SELECT * FROM ' + @inputParam\r\n\r\nEXECUTE (@sSQL)<\/pre>\n<p><!--more-->Now, what about these two examples? Let&#8217;s assume that someone&#8217;s trying a SQL injection attack and has passed, for @inputParam, a value of &#8220;Table1; Drop Table Table1 &#8211;&#8221;<\/p>\n<p>In example 1, that value that&#8217;s passed in does not match any of the IF conditions. Hence, the resulting SQL that will get executed is &#8216;SELECT * FROM &#8216;. That&#8217;s going to throw a syntax error, but nothing more. The malicious statement did not get injected into the command that was run. Hence, no SQL injection here.<\/p>\n<p>What about example 2? For the same value of @inputParam, the command that will be executed is &#8216;SELECT * FROM Table1; Drop Table Table1 &#8211;&#8216;. When that&#8217;s run, assuming sufficient permissions, Table1 is going to be dropped. Not good.<\/p>\n<p>In this case, because the input parameter was made a direct part of the string that was getting executed, there was a possibility of SQL injection; this example is vulnerable.<\/p>\n<p>Now let&#8217;s look at a couple of examples similar to the one I gave in my previous post, ones with dynamic where clauses.<\/p>\n<p><strong>Example 1:<\/strong><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nDECLARE @inputParam1 VARCHAR(100) -- Assume this comes from user input\r\nDECLARE @inputParam2 VARCHAR(100) -- Assume this comes from user input\r\nDECLARE @sSQL nvarchar(500)\r\n\r\nSET @sSQL = 'SELECT * FROM SomeTable WHERE Active = 1 '\r\nIF @inputParam1 IS NOT NULL\r\nSET @sSQL = @sSQL + ' AND Column1 = @innerParameter1'\r\nIF @inputParam2 IS NOT NULL\r\nSET @sSQL = @sSQL + ' AND Column2 = @innerParameter2'\r\n\r\nexec sp_executesql @sSQL, '@innerParameter1 varchar(100), @innerParameter2 varchar(100)', @innerParameter1 = @inputParam1, @innerParameter2 = @inputParam2\r\n\r\n<\/pre>\n<p><strong>Example 2:<\/strong><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nDECLARE @inputParam1 VARCHAR(100) -- Assume this comes from user input\r\nDECLARE @inputParam2 VARCHAR(100) -- Assume this comes from user input\r\nDECLARE @sSQL varchar(500)\r\n\r\nSET @sSQL = 'SELECT * FROM SomeTable WHERE Active = 1 '\r\nIF @inputParam1 IS NOT NULL\r\nSET @sSQL = @sSQL + ' AND Column1 = ''' + @inputParam1 + ''''\r\nIF @inputParam2 IS NOT NULL\r\nSET @sSQL = @sSQL + ' AND Column2 = ''' + @inputParam2 + ''''\r\n\r\nEXECUTE (@sSQL)\r\n\r\n<\/pre>\n<p>In the first example, the imput parameters never become a direct part of the string that is being executed. They are used to control what portions are added to the string and they are passed, as parameters, to sp_executesql, but they themselves are not incorperated into the string.<\/p>\n<p>In the second example, the parameters are used to control what portions are added to the string but they are also directly concatenated into the string. So whatever&#8217;s inside the parameters will become part of the string that is going to be executed.<\/p>\n<p>So, what happens in this case if a malicious user passes, for inputParam1, this: &#8220;abc&#8217;; drop table SomeTable;&#8211;&#8221; and leaves inputParameter2 blank<\/p>\n<p>In the first example, since inputParam1 has a value and inputParam2 does not, the resulting SQL string is<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nSELECT * FROM SomeTable\r\nWHERE Active = 1 AND Column1 = @innerParameter1\r\n\r\n<\/pre>\n<p>That is then executed by sp_executesql and the value with the attempted SQL injection is then passed as a parameter and the query executes looking for rows where Column1 has the actual value &#8220;abc&#8217;; drop table SomeTable;&#8211;&#8221; (which is quite unlikely to match anything). Since the input parameters did not become part of the string executed, there is no possibility for SQL injection here<\/p>\n<p>What about the second example?<\/p>\n<p>Well, in that example, if inputParam1 has the same value given in above and inputparam2 is blank, the resulting string that will be executed is<\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n\r\nSELECT * FROM SomeTable\r\nWHERE Active = 1 AND Column1 = 'abc'; drop table SomeTable;--'\r\n\r\n<\/pre>\n<p>Not good.<\/p>\n<p>So, in summary, if a user-specified value is included as actual part of a SQL statement to be executed, it is vulnerable to SQL injection. If the parameters are used rather to control what the string looks like but are not made a direct part of it, then there is no opening for SQL injection. I hope this has cleared up at least a little bit of the confusion around the topic.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When I wrote about the catch-all queries, someone asked why the dynamic SQL that I offered wasn&#8217;t vulnerable to SQL injection. I thought I&#8217;d go into the whys and the wherefores of that in a little bit more detail. I&#8217;m&#8230; <a class=\"read-more-button\" href=\"https:\/\/www.sqlinthewild.co.za\/index.php\/2009\/04\/03\/dynamic-sql-and-sql-injection\/\">(Read more)<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[15,16,17],"tags":[],"class_list":["post-230","post","type-post","status-publish","format-standard","hentry","category-sql-server","category-syndication","category-t-sql"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p7h6n-3I","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/230","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/comments?post=230"}],"version-history":[{"count":0,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/posts\/230\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/media?parent=230"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/categories?post=230"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlinthewild.co.za\/index.php\/wp-json\/wp\/v2\/tags?post=230"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}