[转载]SQL Server安全之加密术和SQL注入攻击
<p style="TEXT-INDENT: 2em">信息来源:csdn</p><p style="TEXT-INDENT: 2em">文章作者:lgr0727</p><p style="TEXT-INDENT: 2em">SQL Server上内置了加密术用来保护各种类型的敏感<a class="channel_keylink"><font color="#000000">数据</font></a>。在很多时候,这个加密术对于你来说是完全透明的;当<a class="channel_keylink"><font color="#000000">数据</font></a>被存储时候被加密,它们被使用的时候就会<a class="channel_keylink"><font color="#000000">自动</font></a>加密。在其他的情况下,你可以选择<a class="channel_keylink"><font color="#000000">数据</font></a>是否要被加密。SQL Server可以加密下列这些组件: </p><p style="TEXT-INDENT: 2em">·密码 </p><p style="TEXT-INDENT: 2em">·存储过程,视图,触发器,用户自定义函数,默认值,和规则。 </p><p style="TEXT-INDENT: 2em">·在<a class="channel_keylink"><font color="#000000">服务</font></a>器和用户之间传输的<a class="channel_keylink"><font color="#000000">数据</font></a> </p><p style="TEXT-INDENT: 2em"><b>密码加密术</b> </p><p style="TEXT-INDENT: 2em">SQL Server<a class="channel_keylink"><font color="#000000">自动</font></a>将你分配给登陆和应用角色的密码加密。尽管当你可以从主<a class="channel_keylink"><font color="#000000">数据</font></a>库中直接察看系统表格而不需要密码。你不能给对这种情况作出任何修改,事实上,你根本不能破坏它。 </p><p style="TEXT-INDENT: 2em"><b>定义加密术</b> </p><p style="TEXT-INDENT: 2em">在有些时候,如果对对象进行加密是防止将一些信息分享给他人。例如,一个存储进程可能包含所有者的商业信息,但是这个信息不能和让其他的人看到,即使他们公开的系统表格并可以看到对象的定义。这就是为什么SQL Server允许你在创建一个对象的时候进行加密。为了加密一个存储进程,使用下面形式的CREAT PROCEDURE 语句: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />CREATE PROCEDURE procedurename [;number][@parameter datatype
[VARYING][ = defaultvalue][OUTPUT]]
[, …]
[WITH RECOMPILE | ENCRYPTION | RECOMPILE, ENCRYPTION]</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">我们关心的仅仅是可选的WITH参数。你可以详细说明ARECOMPILE或者ENCRYPTION,或者你可以同时说明它们。ENCRYPTION关键字保护SQL Server它不被公开在进程中。结果,如果ENCRYPTION在激活的时候系统存储进程sp_helptext就会被忽视,这个存储进程将被存储在用户创建进程的文本中。如果你不想要加密,你可以使用ALTER PROCEDURE,忽略WITH ENCRYPTION子句来重新创建一个进程。 </p><p style="TEXT-INDENT: 2em">为了能够使用加密术。用户和<a class="channel_keylink"><font color="#000000">服务</font></a>器都应该使用TCP/IP NetworkLibraries用来连接。运行适当的Network Utility和检查Force protocol encryption,看下表,用户和<a class="channel_keylink"><font color="#000000">服务</font></a>器之间的连接将不会被加密。 </p><p style="TEXT-INDENT: 2em">加密也不能完全自由。当连接确定后,要继续其他的构造,并且用户和<a class="channel_keylink"><font color="#000000">服务</font></a>器必须运行代码来解释加密和解释的包裹。这里将需要一些开销并且当在编译码的时候会使进程慢下来。如果<a class="channel_keylink"><font color="#000000">网络</font></a>包裹在你控制范围之外,使用这种做法是非常好的。 </p><p style="TEXT-INDENT: 2em"><b>加密术中缺少什么?</b> </p><p style="TEXT-INDENT: 2em">你可以注意到在这个列表中缺少一些被加密的东西:你表格中的<a class="channel_keylink"><font color="#000000">数据</font></a>。在你存储<a class="channel_keylink"><font color="#000000">数据</font></a>之前,SQL Server不会提供任何内置的工具来加密你的<a class="channel_keylink"><font color="#000000">数据</font></a>。如果你需要保护存储在SQL Server上的<a class="channel_keylink"><font color="#000000">数据</font></a>,我们给你两条建议:第一,你可以利用GRANT 和DENY关键字来控制你想哪个用户可以在SQL Server中读取的<a class="channel_keylink"><font color="#000000">数据</font></a>。 </p><p style="TEXT-INDENT: 2em">第二.如果你真的想对<a class="channel_keylink"><font color="#000000">数据</font></a>加密,不要设法加密码。你可以利用被测试过的商业产品的算法。 </p><p style="TEXT-INDENT: 2em"><b>SQL 注入攻击</b> </p><p style="TEXT-INDENT: 2em">SQL 注入攻击是一个常规性的攻击,它可以允许一些不法用户检索你的<a class="channel_keylink"><font color="#000000">数据</font></a>,改变<a class="channel_keylink"><font color="#000000">服务</font></a>器的设置,或者在你不小心的时候黑掉你的<a class="channel_keylink"><font color="#000000">服务</font></a>器。SQL 注入攻击不是SQL Server问题,而是不适当的程序。如果你想要运行这些程序的话,你必须明白这冒着一定的风险。 </p><p style="TEXT-INDENT: 2em"><b>测点定位弱点</b> </p><p style="TEXT-INDENT: 2em">SQL 注入的脆弱点发生在程序开发员构造一个WHERE 子句伴随着用户的输入的时候。比如,一个简单的ASP程序允许用户输入一个顾客的ID然后检索公司的全部人员的名字,如果顾客ID如果作为ASP页面的请求串的一部分返回,那么开发员可以编写下面的代码获得<a class="channel_keylink"><font color="#000000">数据</font></a>: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />strConn = "Provider=SQLOLEDB;Data Source=(local);" & _
"Database=Northwind;Integrated Security=SSPI"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConn
strQuery = "SELECT ContactName FROM Customers " & _
“WHERE CustomerID = '" & Request.Form("CustID") & "'"
Set rstResults = cnn.Execute(strQuery)
Response.Write(rstResults.Fields("ContactName").Value)</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">现在你知道什么地方有问题了吧?如果用户知道一个用户的ID,他可以通过检索来获得全部的相应的名字。现在明白了? </p><p style="TEXT-INDENT: 2em"><b>获得额外的<a class="channel_keylink"><font color="#000000">数据</font></a></b> </p><p style="TEXT-INDENT: 2em">当然,对于一个攻击程序,尽管它不知道任何顾客的ID,甚至不用去猜,它也可以获得<a class="channel_keylink"><font color="#000000">数据</font></a>。为了完成这个工作,它将下面的文本输入到应用程序调用顾客ID的textbox中: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />customer ID:
'UNION ALL SELECT ContactName FROM Customers
WHERE CustomerID <>'</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">如果你输入了这个代码,你将会看到返回一个询问语句: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />SELECT ContactName FROM Customers
WHERE CustomerID = ''
UNION ALL SELECT ContactName FROM Customers
WHERE CustomerID <>''</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">通过获得空和非空顾客的ID并集,这个查询语句会返回<a class="channel_keylink"><font color="#000000">数据</font></a>库中所有的相关姓名。事实上,这个UNION<a class="channel_keylink"><font color="#000000">技术</font></a>可以被用来获得你<a class="channel_keylink"><font color="#000000">数据</font></a>库中大多数信息,看看这个CustomerID的值: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />'UNION ALL SELECT FirstName ' ' LastName FROM
Employees WHERE LastName <>'</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">它将SQL语句变成: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />SELECT ContactName FROM Customers
WHERE CustomerID = ''
UNION ALL SELECT FirstName ' ' LastName FROM
Employees WHERE LastName <>''</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">看,那就是攻击程序从你的<a class="channel_keylink"><font color="#000000">数据</font></a>库获得的第一个雇员的名字。 </p><p style="TEXT-INDENT: 2em"><b>更多的攻击程序</b> </p><p style="TEXT-INDENT: 2em">如果SQL注入仅仅只有<a class="channel_keylink"><font color="#000000">数据</font></a>暴光这个弱点就已经够糟糕的了,但是,实际上一个良好的攻击程序可以通过这个弱点获取你<a class="channel_keylink"><font color="#000000">数据</font></a>库中所有的资料。看下面这个例子: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />';DROP TABLE Customers;--</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">SQL语句变成: </p><p style="TEXT-INDENT: 2em" /><center><ccid_nobr /><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code />SELECT ContactName FROM Customers
WHERE CustomerID = ''
; DROP TABLE Customers;-- '</ccid_code /></pre></td></tr></tbody></table></ccid_nobr /></center><p style="TEXT-INDENT: 2em">这个分号使语句和SQL Server隔离,所以,这里实际上是两个语句。第一个语句不存在的名字,第二个则撤消的整个Customers表。两个—SQL Server注释符,它可以使子句不发生语法错误。 </p><p style="TEXT-INDENT: 2em">使用这个<a class="channel_keylink"><font color="#000000">技术</font></a>的变异,一个攻击程序可以在任何SQL语句或者存储过程上运行。通过使用xp_cmdshell扩展存储过程,一个攻击程序同样可以在操作系统命令下运行,显然,这是一个严重的<a class="channel_keylink"><font color="#000000">漏洞</font></a>。 </p><p style="TEXT-INDENT: 2em"><b>保护自己的<a class="channel_keylink"><font color="#000000">数据</font></a>库</b> </p><p style="TEXT-INDENT: 2em">现在,你知道如何防范SQL注入攻击了吗?首先,你不能在用户输入中构造WHERE子句,你应该利用参数来使用存储进程。在最初的ASP页面下,重新写的部分将和刚才我们在表中所看到的东西相似。即使你认为在你的应用程序中没有脆弱点,你应该遵守最小特权原则。使用我们建议的其他安全<a class="channel_keylink"><font color="#000000">技术</font></a>允许你的用户仅仅访问他们能够访问的。在你没有发现你<a class="channel_keylink"><font color="#000000">数据</font></a>库脆弱点的时候,只有这样,不会使你的<a class="channel_keylink"><font color="#000000">数据</font></a>库崩溃。 </p><p style="TEXT-INDENT: 2em"><b>最后的建议</b> </p><p style="TEXT-INDENT: 2em">这就是全部的SQL Server安全系列。也许你现在不是一个全面的专家,但是你已经了解了很多反面。下一步就是你要保护你SQL Server<a class="channel_keylink"><font color="#000000">数据</font></a>,记住你在这里所学到的知识,并利用到你的<a class="channel_keylink"><font color="#000000">数据</font></a>库中保证你的<a class="channel_keylink"><font color="#000000">数据</font></a>不被那些<a class="channel_keylink"><font color="#000000">黑客</font></a>攻击。</p>
页:
[1]