All about Security - SQL Injection

最近做个一个有关ORACLE数据库安全的网上研讨。我们有1300多位参与者,反馈相当丰富。

I recently did a web seminar on Oracle Database Security (you can see a 
replay of it here
).  We had over 1,300 live attendees (glad I couldn't see you all - that would be scary) and the feedback was pretty good.

我们也接到了一些问题,好吧,事实上,很多问题。我打算在这里一点一点处理他们。我将以我最感兴趣的问题--”SQL注入“开始。我将主要在本文介绍SQL注入的核心概念,让后对ORACLE 数据库防火墙(对于检测和阻止SQL注入很有用的工具)做一番介绍。

We also received a few questions, well, actually - a lot of questions.  I'm going to try to tackle them here bit by bit.  I'm going to start with my favorite topic - questions centered around SQL Injection.  I'll center on the core concepts around SQL Injection in this article and then do a followup article regarding the Oracle Database Firewall - a tool useful for detecting and blocking SQL Injection attacks.

陈述中,我讨论了SQL注入式何等的阴险和难于侦测。事实上,我之前写过一篇文章。。。


During the presentation - I talked about how insidious SQL Injection is - and how hard it can be to detect. In fact, I've written about this before, 
in this article
.  The interesting thing about that article on injecting is the very last part of it, the section on "selective system grants".  If you read that small section you'll see a comment 
"Note: Revised content—to prevent SQL injection— for this procedure submitted by Roy Jorgensen."
.  What that means is - the original article I submitted had a SQL Injection bug in it - right after I just spent pages going over SQL Injection!  That wasn't too embarrassing was it (it was).  But it does point out how easy it is for a SQL Injection bug to sneak into code - even when the coder knows full well what SQL Injection is and how it happens!

总之,研讨会中我讲了关于我使用的幻灯片--一个存储过程,里面含有SQL注入BUG。我问观众,许多开发员和DBA们都告诉我该段代码如何被SQL注入。。。我告诉他们正确
答案:如果我把这段代码放到我的模式并且授予你执行的权限,你就能等通过它得到我拥有的任何表!


Anyway, during the web seminar I talked about a slide I use - with a full stored procedure on it - that contains a SQL Injection bug.  I ask the audience, usually full of developers and DBAs to tell me how the code can be SQL Injected..  I tell them right out - this code can be injected and if I were to put it in my schema and grant you execute on it - you could use this to read pretty much any table I own.



此刻,我通常听蟋蟀,没有手,没有志愿者(啥意思?)。下面是幻灯片:


I usually hear crickets at this point in time, no hands, no volunteers.  Here is the slide:




create or replace procedure inj(p_date in date)
as
l_rec all_users%rowtype;
c sys_refcursor;
l_query long;
begin
l_query := '
select *
from all_users
where created = ''' ||p_date ||''''; --2次隐式转换 dbms_output.put_line(l_query);
open c for l_query; for i in 1 .. 5
loop
fetch c into l_rec;
exit when c%notfound;
dbms_output.put_line(l_rec.username || '.....');
end loop;
end;
/

Note that the input to this procedure is a binary Oracle date - it is fixed length, 7 bytes of data - the century, year, month, day, hour, minute and second.   The input is not a string, the input cannot contain things like "or 1=1" - typical SQL Injection attack strings.  It can only contain an Oracle date.  So - the question is - how can I 'trick' this stored procedure into showing me anything I want to see in the schema that owns the procedure (thus bypassing any and all security the application tier might have put in place - there are no restrictions on what I can and cannot see now).




Before we get there - let's talk about the bit of code that will be problematic - that is line 10.  As noted there is a double implicit conversion going on there.  That line of code is really:






Where created = to_date( to_char( p_date ) );


There is an implicit to_char on the date field in order to concatenate it to the query string.  Then, at runtime there is an implicit to_date on the string we concatenated in so we can compare it to a date.  This is a very common thing I see in code all of the time (implicit conversions) - but it is pure evil.  Not only will we discover it is the cause of a SQL Injection issue - but here it is a logic bomb as well.

First of all - by default - that to_date( to_char() ) conversion will have a side effect of effectively truncating the time component from the date field.  That is evil.  If you wanted to truncate the time off - please use TRUNC() on the date - it is much faster, more efficient, and expresses clearly that you intend to truncate the time component.  To_date(to_char()) does none of that.  Secondly - the conversion by default will also lose the century.  If you were trying to look for things created during the war of 1812 - you would lose, you cannot search for 1812 - it would become 2012 (well, right now as I write this it would be 2012 - in 38 years it will become 2112 and you won't be able to search for 2012 anymore...).



Also consider that I said "by default".  By default the NLS_DATE_FORMAT is DD-MON-RR (currrently, it has been different in the past!).  What happens to this code when someone decides to change it?  Your application might well start querying up entirely different data!

So, the implicit conversion by itself is bad - but the real issue is the SQL Injection flaw.  If you just run this procedure, by default - it certainly looks OK:

ops$tkyte%ORA11GR2> exec inj( sysdate )

        select *
          from all_users
         where created = '02-FEB-12'

PL/SQL procedure successfully completed.


that looks OK - seems pretty safe - 
until, until someone who has read the documentation comes along.  They might run your code like this:

ops$tkyte%ORA11GR2> alter session set
  2  nls_date_format = 'dd-mon-yyyy"'' or ''a'' = ''a"';

Session altered.

ops$tkyte%ORA11GR2> exec inj( sysdate )

        select *
          from all_users
         where created = '02-feb-2012' or 'a' = 'a'
A.....
EBRAPP.....
EBRTBLS.....
UTIL.....
USER2.....

PL/SQL procedure successfully completed.


Now that is surprising,  you might not even know you could do that in an NLS_DATE_FORMAT.  It is really hard to protect against something you don't even know 
you can do - isn't it?  I've had people look at that example and scoff at it - saying "so what, they were allowed to see that table".  Ok, take it a step further, I'd like to know what tables you own - so I can start querying them.  I'll just do this:

ops$tkyte%ORA11GR2> alter session set
  2  nls_date_format = '"''union select tname,0,null from tab--"';
Session altered.

ops$tkyte%ORA11GR2> exec inj( null )


Select *
  from all_users
 where created = ''union select tname,0,null from tab--'


....
现在你们看到问题的进展。。。在一个存储过程我发现了SQL注入BUG并解锁了整个模式!
Now you can see where this is going...  I find one SQL Injection bug in one procedure and I've unlocked the entire schema.  
问题来了--我们改如何防护? 做些什么不再受制于SQL注入?
So, the question now comes up - how do I protect myself from this?  What can I do to ensure I'm not subject to SQL Injection in this code?
有2种方式--困难的方式和简单方式
There are two ways - the hard way and the easy way.  
困难的方式:是引入SQL验证代码
The hard way involves writing code to validate everything and having 
serious code reviews of any code that uses string concatenation to build their SQL statements - any code that takes a parameter as input and concatenates it to a SQL query must be read and reviewed by many people - many people who will be super critical of the code.  In this case, the resulting code would have to be:

where created = to_date( ''' || to_char(p_date,'yyyymmddhh24miss') ||''', ''yyyymmddhh24miss'')';   

You need to have a coding standard that says:

  1. You shall never use implicit conversions ever, as in never.
  2. You shall always use an explicit date mask with dates, as in every single time, you will not rely on defaults (because defaults can inject you and because defaults can radically modify your logic unintentionally!)
And now you have to comb through all of your code looking for these bad practices (you should anyway - you have major logic bombs just waiting to explode in your code if you rely on default NLS settings and implicit conversions).

简单的方式:使用绑定变量
The easy way however is the way to go.  The easy way is - just use bind variables!  If you use bind variables, you 
cannot be SQL Injected - this is true for PL/SQL, for Java, for any and all languages.  If you use bind variables you 
cannot be SQL Injected - period.  It is that simple, really and truly.  If the code was:

  7          l_query := '
  8          select *
  9            from all_users
 10           where created = :x';
 11          open c for l_query USING P_DATE;

there is no way the end user can trick that SQL query into becoming anything other than what it is - in fact, for this example, the code should have been:

as
   cursor c is select * from all_users where created = p_date;
begin
   open c;
   ...

and nothing more - it shouldn't have even been using dynamic SQL.  In Java/C#/C++/etc - you would be using dynamic SQL and you should be using bind variables.   So, that answered all of these questions I received:


where can I find an illustration of SQL injection?

can u share the sql injection demo code

Can you share that SQL injection slide?

Can you show a code example of the SQL injection bug that nobody noticed during your presentations?

Can you show us or point us to the site of the example of SQL injection bug?

Is SQL injection all about binding, or is there more?


Another question was:


should application layer deal with the SQL injection attacks prevention as that layer understands what the proper data access patterns look like rather than database?

My response to that is - the application layer should definitely be aware of SQL Injection and use secure coding practices which would include:

always use a bind variable unless you have an excellent technical reason not to - and then you must submit your code for review to at least five people who do not like you - they must be motivated to rip your code apart, critically review it, make fun of it - so they find the bugs.

However - we need to also employ defense in depth - for when the inevitable bug slips through.  When I next write about this - I'll be going over the Oracle Database Firewall - a tool that can provide at least one more layer of defense.

The last question on this topic was: 


What is the dbms_assert PL/SQL package? How does it help prevent SQL injection? Should my organization be using it?

For that - I'll just forward you onto an excellent paper on this subject written by Bryn Llewellyn.  You can 
find that paper here.

Oracle SQL 注入攻击的更多相关文章

  1. SQL注入攻击技巧总结

    0×01 你要知道目前有哪些数据库 微软公司旗下的: Microsoft SQL server 简称 MS-SQL 或者 SQL SERVER (大型数据库操作,功能和性能异常强大)(一般也是ASP或 ...

  2. SQL注入攻击

    SQL注入攻击是黑客对数据库进行攻击的常用手段之一.随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多.但是由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候, ...

  3. 【渗透攻防WEB篇】SQL注入攻击初级

    前言不管用什么语言编写的Web应用,它们都用一个共同点,具有交互性并且多数是数据库驱动.在网络中,数据库驱动的Web应用随处可见,由此而存在的SQL注入是影响企业运营且最具破坏性的漏洞之一,这里我想问 ...

  4. 【web渗透技术】渗透攻防Web篇-SQL注入攻击初级

    [web渗透技术]渗透攻防Web篇-SQL注入攻击初级 前言不管用什么语言编写的Web应用,它们都用一个共同点,具有交互性并且多数是数据库驱动.在网络中,数据库驱动的Web应用随处可见,由此而存在的S ...

  5. 使用SQLMAP对网站和数据库进行SQL注入攻击

    from:http://www.blackmoreops.com/2014/05/07/use-sqlmap-sql-injection-hack-website-database/ 0x00 背景介 ...

  6. 2017-2018-2 20179205《网络攻防技术与实践》第十一周作业 SQL注入攻击与实践

    <网络攻防技术与实践>第十一周作业 SQL注入攻击与实践 1.研究缓冲区溢出的原理,至少针对两种数据库进行差异化研究 缓冲区溢出原理   在计算机内部,输入数据通常被存放在一个临时空间内, ...

  7. 网站如何防止sql注入攻击的解决办法

    首先我们来了解下什么是SQL注入,SQL注入简单来讲就是将一些非法参数插入到网站数据库中去,执行一些sql命令,比如查询数据库的账号密码,数据库的版本,数据库服务器的IP等等的一些操作,sql注入是目 ...

  8. 2017-2018-2 20179204《网络攻防实践》第十一周学习总结 SQL注入攻击与实践

    第1节 研究缓冲区溢出的原理,至少针对两种数据库进行差异化研究 1.1 原理 在计算机内部,输入数据通常被存放在一个临时空间内,这个临时存放的空间就被称为缓冲区,缓冲区的长度事先已经被程序或者操作系统 ...

  9. 【spring】(填坑)sql注入攻击 - 持久层参数化

    结果   填坑失败,并没有看懂是如何检测sql攻击的. 只能说的是: 建议都使用参数化传递sql语句参数.(所以,用hibernate.mybatis等框架的真不用太担心sql攻击问题.) 前言 本文 ...

  10. JDBC基础:JDBC快速入门,JDBC工具类,SQL注入攻击,JDBC管理事务

    JDBC基础 重难点梳理 一.JDBC快速入门 1.jdbc的概念 JDBC(Java DataBase Connectivity:java数据库连接)是一种用于执行SQL语句的Java API,可以 ...

随机推荐

  1. K8S_IPV6 POD与数据库联通方法以及快速网络调试的一个思路

    K8S_IPV6 POD与数据库联通方法以及快速网络调试的一个思路 背景 前端时间搭建了一套K8S only IPV6 Single Stack的测试环境 因为自己长时间不搞K8S了, 并且IPV6的 ...

  2. [转帖]HBase实战:记一次Safepoint导致长时间STW的踩坑之旅

    https://mp.weixin.qq.com/s/GEwD1B-XqFIudWP_EbGgdQ     ​过 程 记 录 现象:小米有一个比较大的公共离线HBase集群,用户很多,每天有大量的Ma ...

  3. [转帖]Jmeter学习笔记(二十一)——Concurrency Thread Group阶梯式加压测试

    https://www.cnblogs.com/pachongshangdexuebi/p/11739064.html 一.先安装jmeter的插件管理工具 1.下载地址:jmeter-plugins ...

  4. [转帖]linux 内核协议栈 TCP time_wait 原理、配置、副作用

    https://my.oschina.net/u/4087916/blog/3051356   0. 手把手教你做中间件.高性能服务器.分布式存储技术交流群 手把手教你做中间件.高性能服务器.分布式存 ...

  5. [转帖]linux删除文本文件空白行

    linux删除文本文件空白行https://www.zhihu.com/people/chen-kai-84-54-75 sed命令 在Linux中,可以使用sed命令批量删除文本中的空白行.以下是一 ...

  6. Grafana监控java应用以及vCenter的方法

    Grafana监控java应用以及vCenter的方法 背景 最开始弄过vCenter的监控. 但是发现很多地方已经不合适了. 今天看了下jmx监控 java的应用. 顺便监控了下vCenter. 这 ...

  7. awk的简要使用

    原文地址:https://www.lujun9972.win/blog/2020/08/23/在命令行进行简单的统计分析/index.html 目录 使用awk获取最小值.最大值.中位数和平均值 使用 ...

  8. 本地搭建playground

    本文主要是记录我搭建go playground的步骤. 1.安装docker 如果你使用的Ubuntu,docker的安装步骤可以参见这里,这是我之前写的在Ubuntu18.04下安装fabric,其 ...

  9. HTML超链接自定义颜色

    先添加一个css样式 我这里直接内嵌了因为代码量比较少不会影响太大的性能 <style type="text/css"> body {background-color: ...

  10. 深度学习应用篇-计算机视觉-语义分割综述[6]:DeepLab系列简介、DeepLabV3深入解读创新点、训练策略、主要贡献

    深度学习应用篇-计算机视觉-语义分割综述[6]:DeepLab系列简介.DeepLabV3深入解读创新点.训练策略.主要贡献 0.DeepLabV3深入解读 1.DeepLab系列简介 1.1.Dee ...