动易安全开发手册[zt]
目录
一、 输入验证
1. 什么是输入
输入是编译时以外的全部数据交换。WEB应用程序从各种来源获取输入,例如所有用户发送的,或者应用程序运行的往返数据(用户提交的数据、视图状态、cookie、查询字符串参数等),以及后台数据(数据库、配置数据和其他数据来源)。所有输入的数据都会在某种情况下影响请求的处理。[1]
2. 输入验证的必要性
为什么输入验证如此重要?第一个原因非常明显:用户都不希望使用虚假的数据。应用程序会处理这些数据,根据它们得出结果,并最终存储到后台数据存储中。网络上的其他应用程序有可能在某种情况下需要这些数据,这些程序可能依赖于数据的正确性。(如果这些数据没有经过验证,就有可能会带来麻烦。)[1]
一切从外部获取的数据都可能是恶意的,如果缺少对数据的验证,将会带来很多安全问题。如EMAIL 验证、用户名验证等。如:缺少对EMAIL的长度验证,在存储EMAIL时将出现数据库溢出错误。缺少对EMAIL的格式验证,在发送邮件时将会给程序带来错误等。
3. 输入验证技术
3.1 主要防御方式
防御手段一:验证控件验证
保护级别:★★★★☆
描述:
对于表现层, 可以利用验证控件,对用户输入的数据进行类型、大小、范围的验证。
验证控件必须做到在客户端和服务端同时验证,客户端的验证可以减轻对服务端请求的次数和用户操作的方便性。服务端验证确保数据的正确性,同时也防止用户伪造请求绕过客户端的验证。
优点: 验证简单有效,可重复使用,通常应用于客户端验证较多。
缺点: 验证不完整,有些验证用户可以绕过。
应用举例:
动易SiteFactory系统中,除了使用VS自带的验证控件外,还扩展了和增加了部份验证控件,在PowerEasy.Framework.Controls 命名空间下,可以看到扩展的RequiredFieldValidator 控件,邮箱验证控件EmailValidator等。具体可以查看文件夹 Core Items 中PowerEasy.Framework.Controls项目下的ExtendedValidator文件夹。这些控件一般使用在用户输入的验证,如注册时用户名的验证:
<pe:RequiredFieldValidator ID="ReqTxtUserName" runat="server" ControlToValidate="TxtUserName"
SetFocusOnError="false" ErrorMessage="用户名不能为空" Display="None"></pe:RequiredFieldValidator>
防御手段二:业务逻辑层验证
保护级别:★★★★☆
描述:
关键的地方(涉及到点数、金钱、权限)根据情况还需要在业务层或者数据访问层进行验证,以保证数据的合法性。对于HTML代码输入的地方,输入时一定要进行HTML格式化处理,否则有可能会引起全局显示错误。如输入:<!-- (html注释代码)等。
优点:验证的最后防线,确保数据正确。
应用举例:
动易SiteFactory系统中,在服务端的验证可以用到数据验证类,在命名空间PowerEasy.Framework.Common下的 DataValidator 类里的相关函数。如:IsNumber(数字)、IsIP(IP验证)、IsEmail(邮箱格式验证)等。这些验证函数通常应用在紧接着的客户端验证,或处理重要数据时的验证。如:发送邮箱时 SendEMail(string email)函数里的在发送邮件前验证邮箱是否正确:DataValidator.IsEmail(email)。
防御手段三: 黑名单
保护级别:★★★
描述:
黑名单是看来最简单的途径,不过同时也是最不可靠(有可能让用户绕过)。但在一些地方也是能起到作用的。
优点:应用简单,快捷。
缺点:不完全可靠,忘记验证的几率高。
应用举例:
动易SiteFactory系统中,黑名单的应用有如:过滤系统标签的输入,先将数据库中所有系统标签转换成别的代替符,标签解释完成后再转换成原字符。函数:PELabelEncode(string value),PELabelDecode(string value)。又如:系统的过滤函数RemoveXSS也是黑名单的一种利用。适当利用黑名单验证可以直接过滤掉大部份恶意代码。
防御手段四:白名单
保护级别:★★★★★
描述:
白名单是开发人员定义的合法条件集合,集合以外的任何情况都被视为非法。白名单可能是允许的字符集合,合法文件名称列表,或者只是可以接受的数据类型列表。它与黑名单完全相反。由于它把忘记验证的几率降到最小,而且更容易实现,扩展性更强,所以白名单更加强大。开发人员在验证数据时应该始终使用白名单方法。
优点:可靠性高,扩展性强。
缺点:应用范围较小,通常应用于内容确定的地方。
应用举例:
动易SiteFactory系统中白名单的应用有(只列出部份):数据类型转换:DataConverter 类 CDate CLng 等;
允许上传文件类型:m_FileExtArr = "gif|png|jpeg|jpg|gif|bmp|fla|swf";
允许使用个别js:AllowString.xml 名件中的白名单;
允许文件接收参数类型:QueryStrings.config。
白名单一般应用在那些比较确定的输入类型。
3.2 辅助防御方式
除了使用上述技术验证输入外,还可以使用以下防御方式确保输入的正确性。
防御手段一:过滤技术
保护级别:★★★★
描述:
过滤技术是通过特定过滤函数,把不允许的数据内容过滤掉,这种方法能确保数据的正确性,但同时也存在一些过滤不严和过滤太严的问题,总体来说,这也算是增强系统安全性的一种很有用的方法。
优点:应用范围较广,有一定可靠性。
缺点:函数设计考滤烦多,容易忘记需要过滤的内容。
应用举例:
动易SiteFactory系统中,有多处使用过滤方法,这些过滤函数一般是放在命名空间PowerEasy.Framework.Common下的DataSecurity类和StringHelper类。如:FilterBadChar 函数、FilterSqlKeyword 函数 、RemoveXss 函数等应用。这些函数常用在内容过滤的地方,如RemoveXss函数主要用于跨站脚本的过滤。
防御手段二:强制转换技术
保护级别:★★★★
描述:
除了过滤外,有时也需要强制转换,以确保数据正确和程序的正确运行。如数据层中的强制转换就是一个很好的例子,程序运行到数据层,如果没有对数据进行强制转换,程序的出错将暴出系统错误信息或系统的其他机密信息,更重要的是没有了友好的错误提示。
优点:是系统输入的最后一道防线,比较安全。
缺点:容晚转换出错,要带出错处理过程。
应用举例:
动易SiteFactory系统中,强制转换函数一般放在命名空间PowerEasy.Framework.Common下的DataConverter类里,如:CDate(object input)、CLng(object input)等,还有一些强制转换防出错的函数,在命名空间PowerEasy.SqlServerDal中的DBHelper类,如:ToNumber 函数、ToValidId 函数、CLng函数等。经过这双重保护,确保进入数据库的数据正确性。
防御手段三:输出编码
保护级别:★★★
描述:
输出编码也是一种有效的防止HTML注入(XSS攻击等)的解决方案,具体技术下一章详细说明。
优点:实现简单有效。
缺点:只针对特定输出。
防御手段四:数据库约束验证
保护级别:★★★
描述:
数据库约束是为了保证数据的完整性而实现的一套机制,通过设计数据库约束,可以限制某些重要字段的数据输入,如: 非空约束,数据类型约束等。大大增强了系统数据的正确性。
应用举例:
动易SiteFactory系统中,在数据库设计方面就考滤到了数据库约束验证,因此在数据设计时,就把数据类型都设计好,那些字段允许空,那些不允许都作好了规定。
二、 输出编码
1. 输出的种类
输出编码是转换输入数据为输出格式的过程序,输出格式不包含,或者只是有选择性的包含允许的特殊字符。
输出的种类有:
1)支持HTML代码的输出
2)不支技HTML代码的输出
3)URL的输出
4)页面内容的输出(Keywords、Description等)
5)js脚本的输出
6)style样式的输出
7)xml数据的输出
8)服务控件的输出
2. 输出编码的必要性
输出编码能有效地防止HTML注入(跨站脚本XSS攻击)等,也能确保输出内容的完整性和正确性。
3. 输出编码
防御手段一:过滤
保护级别:★★★☆
描述:
对于支持HTML代码的输出,输出前要确保代码中不含有跨站攻击脚本才能输出。通过编写过滤函数,进行强制过滤。
优点:支持HTML,有交防止主流XSS攻击。
缺点:有可能出错,函数设计难度大。
应用举例:
动易SiteFactory系统中,目前而言,主要采用函数RemoveXss进行处理,由于RemoveXss并非十分完善,有待更好的过滤方案。但函数能防止目前主流的XSS攻击。所以在支持HTML代码的输出,一定要通过这个函数进行过滤(也可以输入到数据库前过滤)。
防御手段二:HTML编码
保护级别:★★★★★
描述:
对于不支持HTML的输出,在输出到页面前要进行Server.HtmlEncode编码,部分服务器控件或者XSLT转换本身就支持Server.HtmlEncode编码,可不必进行重复编码。
优点:非常可靠。
缺点:不支持HTML输出。
应用举例:
动易SiteFactory系统中,命名空间PowerEasy.Framework.Common中的DataSecurity类中有自定义的编码函数:HtmlDecode和HtmlDecode,这些函数更容易地控制编码的输出。函数主要用在那些不支持Html的输出。
防御手段三:URL编码
保护级别:★★★★★
描述:
对于URL的输出,要对输出URL进行Server.UrlEncode处理。
如:<img src="输出内容" border="0" alt="logo" /> 的输出
要确保输出内容的url编码正确,不允许“ “ “ 的输出。
优点:可靠性高。
缺点:应用范围少。
应用举例:
动易SiteFactory系统中,命名空间PowerEasy.Framework.Common中的DataSecurity类中有自定义的URL编码函数UrlEncode和UrlEncode来控制所有URL的输出,以确保输出的准确性。
防御手段四:转换特殊符号的编码形式
保护级别:★★★★★
描述:
对于页面内容的输出,要确保输出的正确性和允许输出的数据。
如:页面 <meta content="输出内容" name="Keywords" /> 的输出。
要确保输出内容中不包含特殊符号:“ “ “ 输出前要转换特殊符号的编码形式,将“ “ “ 转为 " 同样的输出有 title="" 的输出等。
对于js脚本的输出,要确保输出代码中不包含跨站脚本,注意“‘ ”和“”“的输出,以免被组合成危险的js代码,还要注意对转义符号的输出“\”。
如:图片模块,图片地址的输出。
又例如下面例子,变量a 和 b 是由用户输入,如果用户输入a=“\” ,b=“;alert(/xss/);//”,输入结果后如下:
<script>
a="\";b=";alert(/xxs/);//"
<script>
注意,这就成了 a=“\”;b=” ;alert(/xss/) 后面的注释了。。
对于style样式的输出,要确保样式的正确性,目前系统主要应用到标题颜色的输出,如果增加其他样式的输出,要确保样式的安全性才能输出,也要注入转义符“\”的输入。
对于xml数据的输出,要确保数据中是否有XML不允许的字符,要对特殊字符进行转换才能输出。目前系统中还存在一些地方存在这样的问题。如:标签的数据源,输出时没有对特殊符号进行处理,造成输出出错。留言标题中出现“<” 等。
优点:防止因殊符号而出现错误,或跨站。
缺点:检查难度大。
应用举例:
动易SiteFactory系统中,命名空间PowerEasy.Framework.Common中的DataSecurity类中有自定义的编码函数XmlEncode等来控制所有输出,以确保输出的准确性。防止Html注入的出现。
防御手段五:其他要注意的地方
保护级别:★★★★
描述:
对于服务器控件的输出,要注意输出的环境,对于不同的输出环境进行不同的处理,如url编码,html编码等。
除上述输出外,还有一些特殊的输出形式,应尽量避免使用,或者处理编码后再使用。如:
Response.Write(name.Text);
Response.Write(Request.Form["name"]);
QueryString Response.Write(Request.QueryString["name"]);
Cookies Response.Write(Request.Cookies["name"].Values["name"]);
直接输出 <%=myVariable %>
4. 常用测试输出方法
常用的测试输出语句有:
<script>alert('hello');</script>。
1.jpg" onmouseover="alert('xss')
"></a><script>alert(‘xss’);</script>
http://xxx';alert('xss');var/ a='a
‘”>xss&<
对输出数据到输出数据的对比,看是否出现问题。
三、 防止SQL注入
1. 什么是SQL注入
所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。通过递交参数构造巧妙的SQL语句,从而成功获取想要的数据。
2. SQL注入的种类
从具体而言,SQL注入可分为五大类,分别是:数字型注入、字符型注入、搜索型注入(like)、in型的注入、句语连接型注入。
从应用来说,要特别注意IP、搜索、批量删除、从数据库转到数据库等地方的SQL注入。
3. 如何防止SQL注入
3.1 SQL注入产生的原因
看下面检查登陆的SQL语句:
SqlCommand cmd = new SqlCommand("SELECT * FROM PE_USERS WHERE UserName = '"
+ UserName + "' AND UserPassword = '" + PassWord + "'", conn);
由于没有对UserName和PassWord进行任何验证,如果UserName=” admin’ OR 1=1--“
所执行的SQL语句就成了:
SELECT * FROM PE_USERS WHERE UserName=’admin’ OR 1=1—‘ AND UserPassword=’’
这就造成了SQL注入,条件永远为真,也就不用密码也能登陆成功。
3.2主要防御方式
防御手段一:参数化查询
保护级别:★★★★★
描述:
使用参数化查询的好处:可以防止sql注入式攻击,提高程序执行效率。
例如:
const string strSql = "SELECT * FROM [PE_Users] WHERE UserName = @UserName";
Parameters parms = new Parameters("@UserName", DbType.String, userName);
中有一个参数@UserName, 使用Prarmeter对象,通过它把参数添加到Command对象上,这样就获得参数化查询。
如上述语句,ADO.NET 会向SQL Server 发送下面的SQL语句:
Exec sp_executesql N ‘select * from [pe_users] where username=@username ‘,N ‘@username nvarchar(20) ‘,@username=N ‘name’
SQL Server 把@username 替换成字符串”name”,然后再执行查询.
假设有下面的输入:
‘ union select @@version,null,null—
生成的SQL语句如下所示:
Exec sp_executesql N ‘select * from [pe_users] where username=@username ‘,N ‘@username nvarchar(20) ‘,@username=N ‘’’ union select @@version,null,null--’
可以看到ADO.NET转义了输入。
public SqlParameter Add(string parameterName, SqlDbType sqlDbType, int size);
DbTye或SqlDbType可以是多种数据类型。
可根据你的数据类型来选择。
在某些地方,也可似指定参数的长度:int size。这样也能有效防止数据库溢出和SQL注入的可能性。
优点:有效地防止了SQL注入的产生。
缺点:有些地方不能应用,如 in 。
应用举例:
动易SiteFactory系统中,对于比较固定的地方,我们采用比较安全的存储过程来实现。系统中所有SQL语句,能用参数化查询的所有部份都使用了参数化查询。所有操作数据库的地方,都能在命名空间 PowerEasy.SqlServerDal下找到。
防御手段二:过滤与转换
保护级别:★★★★
描述:
对于数据型要强制转换成数字Clng,对于字符型,要通过函数过滤。如:
private string SafeSqlLiteral(string inputSQL)
{
return inputSQL.Replace("'", "''");
}
对于搜索的地方LIKE 子句,要注意,如果要使用 LIKE 子句,还必须对通配符字符进行转义:
s = s.Replace("[", "[[]");
s = s.Replace("%", "[%]");
s = s.Replace("_", "[_]");
对于in类型,要转换成规格的数字串或字符串。
要尽量少用语句连接形式写SQL语句,要用到的地方要确保连接语句的安全性,或在白名单内,或限制很短的长度,以防止SQL语句构造的危险。
优点:有效地防止了SQL注入,实现简单。
缺点:容易遗漏,对于某些地方还是不能过滤,如 order by + 变量
应用举例:
动易SiteFactory系统中,对于不能使用参数化查询的部份,我们使用过滤函数处理,过滤函数在命名空间PowerEasy.Framework.Common中的DataSecurity类下,如:FilterBadChar函数。这函数主要用于业务逻辑层的过滤,对于数据库,我们还使用了强制转换函数,在命名空间 PowerEasy.SqlServerDal 下的 DBHelper 类 ,如:ToValidId 函数等,主要用于数据库无出错的处理操作。
防御手段三:白名单
保护级别:★★★★
描述:
对于一些已知的参数范围,可用白名单的形式处理,能有交防止SQL注入和查询出错,如:order by +列名,列名以参数形式传入时,可制定一个白名单,先判断一下参数是否在白名单内,再进行查询,否则出错处理。
优点:安全可靠
缺点:应用范围小
3.3 辅助防御方式
防御手段一:严格过滤
保护级别:★★★☆
描述:
对于不能参数化查询或者无法限制变量类型和范围的情况,使用过滤的手段来处理。对于数据库中读取的数量要进入查询语句,在不确定数据是否安全的情况下,要对其进入过滤。这种SQL注入比较隐蔽,所以要特别注意。
优点:能用于不能参数化而又难过滤的地方,如 order by +变量
缺点: 过滤过于严格。
应用举例:
动易SiteFactory系统中,对于不能使用参数化查询的部份,我们使用过滤函数处理,过滤函数在命名空间PowerEasy.Framework.Common中的DataSecurity类下,如:FilterBadChar函数。
防御手段二:限定URL传递参数的数据类型和范围
保护级别:★★★
描述:
限定URL的传递参数类型、数量、范围等来防止通过构造URL进行恶意攻击。参见MSDN杂志
优点:在一定的程序上有效地防止通过URL方式的注入。
缺点:容易遗忘正常需要的参数。
应用举例:
动易SiteFactory系统中,需要在Config\QueryStrings.config配置文件中增加相应的配置项来控制URL的参数传入,有效控制每个页面的参数数量和参数类型。
防御手段三:全局过滤SQL关键字过滤
保护级别:★★★
描述:
在某些地方进行全局过滤SQL关键字过滤,如对标签的解释。(可能存在过滤不完全和限制程序开发的问题)
优点:能用于不能参数化而又难过滤的地方,如 table的连接。
缺点: 过滤过于严格。
应用举例:
动易SiteFactory系统中,对于不能使用参数化查询的部份,我们使用过滤函数处理,过滤函数在命名空间PowerEasy.Framework.Common中的DataSecurity类下,如:FilterSqlKeyword函数,主要应用在标签参数的传入的地方。
更多关于SQL注入,可参考这篇文章:
http://www.microsoft.com/taiwan/msdn/columns/huang_jhong_cheng/LVSS.htm
四、 跨站脚本攻击
1. 什么是跨站脚本攻击
跨站脚本攻击(通常简写为XSS)是指攻击者利用网站程序对用户输入过滤不足,输入可以显示在页面上对其他用户造成影响的HTML代码,从而盗取用户资料、利用用户身份进行某种动作或者对访问者进行病毒侵害的一种攻击方式。
2. 跨站脚本攻击的危害
入侵者便通过技术手段在某个页面里插入一个恶意HTML代码,例如记录论坛保存的用户信息(Cookie),由于Cookie保存了完整的用户名和密码资料,用户就会遭受安全损失。如这句简单的Java脚本就能轻易获取用户信息:alert(document.cookie),它会弹出一个包含用户信息的消息框。入侵者运用脚本就能把用户信息发送到他们自己的记录页面中,稍做分析便获取了用户的敏感信息。
跨站脚本攻击的危险,在如今WEB安全越来越得到重视,他的危险性也越来越大。有效防止跨站脚本攻击,是WEB程序是否安全的一个重要标准。
3. 如何防止跨站脚本攻击
3.1 主要防御方式
防御手段一:编码输出
保护级别:★★★★★
描述:
对于不支持HTML代码的地方,可用编码输出。如:Server.UrlEncode等方法编码输出。
优点:安全可靠。
缺点:不支持HTML代码。
应用举例:
动易SiteFactory系统中,命名空间PowerEasy.Framework.Common中的DataSecurity类中有自定义的编码函数:HtmlDecode和HtmlDecode,这些函数更容易地控制编码的输出。函数主要用在那些不支持Html的输出。
防御手段二:使用UBB编码
保护级别:★★★★
描述:
UBB代码是HTML的一个变种,是Ultimate Bulletin Board (国外的一个BBS程序)采用的一种特殊的TAG。它能有效的限制HTML代码的使用,增强系统输出的安全性。
优点是:简单,容易实现,利用白名单形式,易于控制。
缺点是:只支持小量特定html代码,编辑器功能小。
3.2 辅助防御方式
防御手段一: iframe security="restricted"
保护级别:★★★★
描述:
通过设置iframe security="restricted",能有效防止iframe类的攻击(对IE有效).
优点:有效防止iframe的攻击。
防御手段二: HttpOnly
保护级别:★★★★
描述:
设置Cookie的HttpOnly属性,有效地防止Cookie通过脚本泄密(IE6 SP1以上、Firefox 3)。
优点:有效保护了用户Cookie信息。
应用举例:
动易SiteFactory系统中,所有登陆验证的地方,验证成功后设置authCookie.HttpOnly = true, 设置Cookie的HttpOnly属性,这些都应用于用户登陆成功的地方。
防御手段三: 字符过滤
保护级别:★★★★
描述:
通过函数进行过滤,能有效防止常见脚站脚本的跨站攻击。主要过滤常见恶意脚本代码,如:
<applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base>
OnX事件代码、Javascript、Vbscript和Style中的expression、behaviour、script、position等。
但过滤可能存在不完全的情况。建立自己的XSS攻击库,方便测试和收集新的攻击方式,使过滤函数更加完善。
优点:支持HTML,有效防止大部份攻击代码。
缺点:可能存在过滤不全的情况。
应用举例:
动易SiteFactory系统中,目前而言,主要采用函数RemoveXss进行处理,由于RemoveXss并非十分完善,有待更好的过滤方案。但函数能防止目前主流的XSS攻击。所以在支持HTML代码的输出,一定要通过这个函数进行过滤(也可以输入到数据库前过滤)。
4.XSS漏洞另一个攻击趋势
1)攻击的本质:
实际上这是一小段JAVASCRIPT,我们只是通过漏洞把这段JS感染到每一个用户的浏览器,但是他不再受系统的限制,任何一个有漏洞的浏览器访问了类似页面都会受到攻击。
2)传播的途径:
从传播方式上来说它和传统的网页木马攻击方式没有区别,由于这种攻击对于HTTP请求包括AJAX都没有域的限制,能使用浏览器本地保存的COOKIE,所以可以劫持用户所有WEB应用的身份,它完全能够让已感染主机配合任何网站的应用做蠕虫式的传播。
3)攻击的危害:
我们可以像传统的僵尸网络一样控制大量的浏览器肉鸡,控制浏览器做任意的访问行为和动作。同时也能针对单个用户做渗透攻击,劫持他所有WEB应用的身份,读取运行本地的任意敏感文件。
4)攻击的展望:
当Active X等溢出漏洞不再风光的时候,以后利用XSS漏洞针对浏览器进行劫持攻击将是一个大的趋势。
跨站脚本攻击,在web2.0时代的现在,越发体现出他的危险性,软件的漏洞加速了xss攻击的危险和加剧了这样攻击的利用。浏览器的漏洞也成为了现今热门的话题:
更多关于XSS攻击的文章请看:
http://www.80sec.com/
http://huaidan.org/
五、 跨站请求伪造
1. 什么是跨站请求伪造
CSRF(Cross-site request forgery跨站请求伪造,也被称成为“one click attack”或者session riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
2. 跨站请求伪造的危害
不要低估了CSRF危害性和攻击能力!可以说,跨站请求伪造是跨站脚本攻击的一种深入利用,它的危害性更大。如:给自己提升权限,增加管理员等。可以通过网上的一个案例说明这种攻击的危害:
Bob在自己的电脑上刚刚查看完自己的银行A账户余额,然后比较无聊就跑到一个公开的BBS上灌水,当他看到一篇“银行A的内部照片”的帖子,很有兴趣的打开这个帖子想看看自己信任的银行A的内部图片是啥样子的,殊不知,这其实是一个attacker精心设计的骗局。在这个帖子中确实有几个图片,看上去真的像是银行A的照片,但是其中有个图片没显示出来,Bob以为是自己网速太慢,导致这个图片没有加载进来,也没在意。只是对这些并不是十分满意的照片摇摇头,就关了这个帖子。几天后,Bob猛然发现自己在银行A的账户上少了1000元,到底是怎么了?
设想一下,Alice编写了一个在Bob的银行站点上进行取款的form提交的链接,并将此链接作为图片tag。如果Bob的银行在cookie中保存他的授权信息,并且此cookie没有过期,那么当Bob的浏览器尝试装载图片时将提交这个取款form和他的cookie,这样在没经Bob同意的情况下便授权了这次事务。
3. 如何防止跨站请求伪造
3.1主要防御方式
防御手段一:ViewStateUserKey(对应Post方式)
保护级别:★★★★
描述:
ViewStateUserKey 是 Page 类的一个字符串属性,设置Page.ViewStateUserKey 属性,防止出现跨站请求伪造攻击。如果攻击者使用视图状态创建预先填充的 Web 页(.htm 或 .aspx),则发生跨站请求伪造攻击。视图状态可根据攻击者先前创建的页面生成。例如,包含 100 种商品的购物车页面。攻击者可引诱信任用户浏览该页,然后将该页发送至视图状态有效的服务器。服务器不知道该视图状态是由攻击者生成的。由于视图状态的有效性,再加上页面在用户安全上下文中执行,因此视图状态验证和 MAC 无法对付这种攻击。为 Page.ViewStateUserKey 属性设置唯一适合的值,然后作为防止跨站请求伪造攻击的对策。对于每个用户而言,这个值必须唯一。通常,它是用户名或标识符。当攻击者创建视图状态时,常将 ViewStateUserKey 属性初始化为自己的用户名。当用户向服务器提交页面时,便使用攻击者的用户名对该页进行初始化。因此,视图状态 MAC 检查将失败,同时出现异常状况。
优点:有效防止POST方式的跨站请求伪造。
应用举例:
动易SiteFactory系统中,在后台操作等重要部份,都设置了ViewStateUserKey验证。主要在管理页基类AdminPage 类下设置了ViewStateUserKey属性。
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (HttpContext.Current.Session != null)
{
ViewStateUserKey = Session.SessionID;
if (!IsValidSecurityCode)
{
WriteErrMsg("页面安全码校验失败!");
}
}
this.CheckPagePermission(); // 检查页面权限
}
防御手段二:追加安全验证码(对应Get方式)
保护级别:★★★★
描述:
通过对链接追加安全验证码(HMACSHA1)防止跨站请求伪造。通过将正常请求的页面+私钥+用户SessionID进行哈希加密,通过URL传递到操作页面,保证来访页面是指定用户通过指定操作链接来的,从而防止了请求伪造,增加了安全性。
优点:有效防止GET方式的跨站请求伪造。
3.2辅助防御方式
防御手段一:验证直接地址链接和外站链接
保护级别:★★★
描述:
禁止通过地址栏直接访问或者通过外部链接访问后台管理页面。
优点:简单的防止用户直接对页面请求造成的管理操作。
缺点:不完全安全,以另一种方式可达到目的。
应用举例:
动易SiteFactory系统中,可以通过Security.config 的noCheckUrlReferrer 配置,设定可以直接访问的页面。新增功能或者新增页面需要根据情况配置Config\Security.config文件。
六、 越权操作
1. 什么是越权操作
越权操作是指对系统进行超越自己权限的操作。每种会员用户都有设置自己特定的权限,如果操作越出了自己权限范围,就是越权操作。
2. 越权操作的危害
越权操作危害性视越权情况而定,如查看收费文章,修改别人的文章,删除系统的文章资料等操作,有一定的危害性。
3. 如何防止越权操作
对于涉及到用户和管理员的操作,首先必须检查操作的合法性。对于合法的操作,还需要检查操作的数据是否是属于操作者本人。特别对会员的自身操作,如删除自己的文章等操作,要检查数据是否属于操作者本人,是否有权限执行操作。操作时对身份的验证一定要引用系统服务端的,不要用用户可修改的数据进行验证。如:隐藏的TextBox,Label,Cookie等。
应用举例:
动易SiteFactory系统中,对于每一操作,都会用命名空间下PowerEasy.AccessManage 的 UserPermissions 类相应函数判断用户是否有权限进行操作。
七、 IO操作安全
对上传文件的实际类型进行检查,并删除黑名单中列出类型的文件。上传采用白名单验证,确保上传文件类型的正确性,也防止上传系统可执行文件,对系统造成危险。如:asp,aspx,php等木马程序。所有的IO操作都要进行权限判断、类型检查,避免恶意用户上传木马文件或者删除、篡改系统文件。特别对于模板操作,文件夹的建立,建立前检查文件夹名和文件名是否合法,注意建立这样 asp.asp 的文件夹(win2003文件夹漏洞)。文件下载频道要注意下载文件类型的检查,防止输入“\..\web.config ”形式的地址,以下载本站源文件。浏览文件时注意允许浏览文件的路径,是否允许用户输入,如果允许,还需要过滤“..”等危险字符,特别注意名件重命名的地方,重命名时最好不要让用户更改文件后辍的权限。
应用举例:
动易SiteFactory系统中,对于文件的操作主要在后台模板标签管理那里,对于文件路径的输入,除了不能让用户修改外,还过滤了“..”等危险字符。对于文件的命名使文件后辍固定而不能被修改。
八、 缓存泄漏
1.什么是缓存泄漏
数据的缓存功能是十分重要的,我们可以把一些在相对一段时间内不发生改变的数据放在缓存中,这样,就不必要每次去读取数据库,当下次再需要这些数据时,可以直接从缓存中取得,大大增强了效率。
但缓存的命名设计和缓存的实现如果处理的不好,就会出现缓存泄漏。什么是缓存泄漏?缓存泄漏是指用户通过某种手段,利用程序缓存命名漏洞,读取自己没有权限得到的缓存内容。看下面例子:
//对标签进行缓存
string labelcacheid = SiteCacheKey.LabelTransformCacheData + labelname + "_" + labelinfo.OriginalData["cacheid"];
int catchftime = DataConverter.CLng(labelinfo.OriginalData["cachetime"]);
if (catchftime > 0 && SiteCache.Get(labelcacheid) != null)
{
labelinfo = (LabelInfo)SiteCache.Get(labelcacheid);
}
else
{
处理。。。。
}
可以从上面看出,cacheid是由用户自定义的输入,如果用户构造自己不能访问的缓存内容名称,就可以读取其缓存内容了。
2.防御方法
缓存命名最好不要有用户输入的部份,若有用户输入的部份,即要先检查用户权限再访问缓存。缓存命名的前辍要分好类别,重要数据缓存要用特殊命名。
应用举例:
动易SiteFactory系统中,对于缓存的命名很有讲究:
CK_System_Int_缓存内容
CK_System_String_缓存内容
CK_CommonModel_Int_缓存内容
CK_CommonModel_String_缓存内容
CK_Contents_NodeList_ALL
CK_CommonModel_ModelInfo_ModelId_5
缓存都分有特殊的前辍,防止缓存欺骗。
九、 系统加密
系统的信息加密对系统的安全性非常重要,做好系统的加密工作,有利于确保整个系统的安全。
1. 主要防御方式
防御手段一:完善加密体系
保护级别:★★★★
描述:
一个完善的加密体系,有利于确保密码的安全性和信息的完整性。
用户密码可用哈希加密或采用混合方式加密,检查密码强度,记录密码更新频率并进行提示。重要的帐号登录处需要设置验证码以防止暴力破解,并且密码要定期更新。
结合数据完整性验证,使得用户密码只能在特定程序中才有效。这样能有效地防止非法手段更改用户密码,有完善的加密程序和数据完整性检查,即使被得到数据库操作权限也不能得到应用程序的管理权限。
优点:有效确保用户信息的安全。
缺点:增加密码管理的难度。
应用举例:
动易SiteFactory系统中,用户密码采用MD5加密,采用密码强度检测,都有采用验证码保护,对于特殊的地方,有考虑采用数据完整性的检查,防止非正常程序操作对数据库的更改,这将在后面版本里出现。
防御手段二:连接字符串加密
保护级别:★★★
描述:
可对连接字符串进行加密(加密文件ConnectionStrings.config),防此用户非法得到数据库连接密码。
优点:能简单保护数据库。
应用举例:
动易SiteFactory系统中,对连接字符串的加密是可选的,可以根据自己的情况,选择是否对数据库连接字符串进行加密。
防御手段三:密码保存位置不同
保护级别:★★★★
描述:
对于重要的系统入口,可有多个密码,如:管理员密码,管理认证码。分别把他们放在不同地方:数据库与文件中。大大增强系统的安全性。
优点:多重密码保护系统。
应用举例:
动易SiteFactory系统中,后台管理认证码就是这一个应用,即使非法用户有数据库操作权限,不知道后台管理认证码也是不能进入系统后台的,这大大增强了系统的安全性。
防御手段四:保护ViewState
保护级别:★★★
描述:
对重要的视图数据进行加密处理,默认情况下,视图状态是以明文传输的,而且有可能暴露信息。使用类似于ViewState Decoder(http://www.pluralsight.com/)的工具,就能重新解码域的值。所以重要数据最好不要保存到ViewState里,或加密处理。
防御手段五:强命名加密程序集
保护级别:★★★★
描述:
使用强名称对程序集进行签名将向包含程序集清单的文件添加公钥加密。强名称签名帮助验证名称的唯一性,避免名称欺骗。强命名程序集可以防止程序集被篡改,强命名的程序集可以部署到GAC(Global Assembly Cache)中,共享多个版本的程序集。
应用举例:
动易SiteFactory系统就是采用了这种手段来防止程序集被篡改。
十、 信息泄露
如果攻击者通过探测 Web 页来找寻引起异常的各种情况,则出现信息泄漏攻击。对于攻击者而言,这是一种颇有成效的攻击方法。因为异常细节信息常以 HTML 的形式返回并显示在浏览器中。这可能会泄漏很有用的信息,如堆栈跟踪。堆栈跟踪包含数据库连接字符串、数据库名、数据库方案信息、SQL 语句以及操作系统和平台版本。
防御手段:错误或异常信息处理
保护级别:★★★★
描述:
利用web.config中配置的自定义错误页和全局的异常处理,屏蔽异常出现时暴露的敏感信息。捕获系统的所有出现异常的地方,做到友好的错误提示信息,不要暴露敏感信息。
优点:友好提示,隐藏出错信息。
防御手段:安全入口尽量进行模糊提示
保护级别:★★★
描述:
对于用户登陆的地方,在验证时尽量模糊提示。如:当登陆出错时都一致提示(用户名或密码不正确!)能有效增加密码暴破的难度。
防御手段:动态表单(防ARP嗅探)
保护级别:★★★
描述:
网络窃听、ARP嗅探存在于网络的任何地方,如何保护WEB程序,确保密码不被捕获或增加被捕获的难度?考虑了常用ARP嗅探软件的嗅探原理(软件自动从用户预先设置好的要获取的表单字段信息,有选择性地获取与用户名,密码字段有关的数据包)。
web程序的ARP嗅探技术也在发展中,同一服务器的网站也不能被免,如:WebSniff 1.0,user权限的aspx rawsocket sniff,可用于smtp,http,ftp敏感信息获取。http://www.cncert.net/DOWN/sinff/2008-7-29/163.html
如果采用动态表单,就增加了ARP嗅探软件捕获密码的难度,因些重要登陆信息都采用随机表单形式,大大保护了数据包被截取的难度。
优点:简单而有效地实现了防ARP嗅探。
应用举例:
动易SiteFactory系统中,在后台登陆部份就是采用了这种方法,简单而有效地防止ARP嗅探,这可能是动易SiteFactory系统首创的一种方法。
十一、 日志和监测
做好系统的日志监测,记录好后台管理操作和异常情况,有利于监测系统未知漏洞,通过操作日志,还能找出系统出错或对某些重要操作的管理员、操作时间、IP等信息。有效地预防,检测,增强系统的安全性。
应用举例:
动易SiteFactory系统中,对重要的日志都进入了记录,如:登陆日志、系统错误日志、数据库错误日志等。
十二、 Web.config的安全配置
1.authentication节点
<system.web>
<!--配置 ASP.NET 使用的安全身份验证模式,以标识传入的用户。-->
<authentication mode="Forms">
<forms loginUrl="~/User/Login.aspx" name=".ASPXAUTH" defaultUrl="User/Default.aspx" timeout="30" path="/"/>
</authentication>
基于窗体(Forms)的身份验证配置站点,当没有登陆的用户访问需要身份验证的网页,网页自动跳转到登陆网页。其中元素loginUrl表示登陆网页的名称,name表示Cookie名称
2.authorization 节点
<!--配置 Web 应用程序的授权,以控制客户端对 URL 资源的访问。-->
<authorization>
<allow users="*"/>
<deny users="?"/>
</authorization>
allow 向授权规则映射添加一个规则,该规则允许对资源进行访问。
deny 向授权规则映射添加一条拒绝对资源的访问的授权规则。
users="*" 是指任何用户 users="?" 是指经身份验证的用户
注意: 运行时,授权模块从最本地的配置文件开始,循环访问 allow 和 deny 元素,直到它找到适合特定用户帐户的第一个访问规则。然后,该授权模块根据找到的第一个访问规则是 allow 还是 deny 规则来允许或拒绝对 URL 资源的访问。默认的授权规则为 <allow users="*"/>。因此,默认情况下允许访问,除非另外配置。
如果在根目录下的web.config配置太繁琐,可以配置到相应目录下,例如User目录下的web.config文件
3.customErrors 节点
<customErrors mode="Off">
</customErrors>
<customErrors defaultRedirect="url" mode="On|Off|RemoteOnly">
<error. . ./>
</customErrors>
defaultRedirect 可选的属性。指定出错时将浏览器定向到的默认 URL。如果未指定该属性,则显示一般性错误。
Mode 必选的属性。指定是启用或禁用自定义错误,还是仅向远程客户端显示自定义错误。
此属性可以为下列值之一。
值 说明
On 指定启用自定义错误。如果未指定 defaultRedirect,用户将看到一般性错误。
Off 指定禁用自定义错误。这允许显示标准的详细错误。
RemoteOnly 指定仅向远程客户端显示自定义错误并且向本地主机显示 ASP.NET 错误。这是默认值。
默认值为 RemoteOnly。
error 可选的元素。指定给定 HTTP 状态代码的自定义错误页。错误标记可以出现多次。子标记的每一次出现均定义一个自定义错误条件。
例如:
<customErrors mode="RemoteOnly" defaultRedirect="~/Prompt/GenericError.htm">
<error statusCode="403" redirect="~/Prompt/NoAccess.htm"/>
<error statusCode="404" redirect="~/Prompt/FileNotFound.htm"/>
<error statusCode="500" redirect="~/Prompt/GenericError.htm"/>
</customErrors>
这里可以让用户自定义出错页。
4.pages 节点
<!--全局定义页特定配置设置,如配置文件范围内的页和控件的 ASP.NET 指令。-->
<pages validateRequest="true" styleSheetTheme="UserDefaultTheme">
validateRequest="true"
该值确定 ASP.NET 是否针对危险值检查来自浏览器的输入。如果 ASP.NET 针对危险值检查来自浏览器的输入,则为 true;否则为 false。默认值为 true。
这个功能是为了防止跨站脚本等危险代码。使全局默认为true。只有小数页面,如搜索页面
Search.aspx 设为 : ValidateRequest="false" 。为了可以搜索类似<div> 等内容,如果只是文字性的输入,可修改页 search.aspx 的设置,以增强系统安全性。
十三、 综合实例讲解
本综合实例,资料是从网上搜集和个人发现,只讲漏洞的存在性和修改方法,与开发语言无关。
实例1: 创力CMS注册验证漏洞
漏洞文件:user/Reg.asp 注册页面。
Sub Reg_Post() ‘46行 开始
if NameLen > MaxLen or NameLen < MiniLen then '84行
ErrMsg=ObjErr.selectSingleNode("NameLen").text
ErrMsg=Replace(ErrMsg,"{$MaxLen}",MaxLen)
ErrMsg=Replace(ErrMsg,"{$MiniLen}",MiniLen)
Call Cl.OutErr(0,ErrMsg)
else
if Instr(UserName,chr(32))>0 or Instr(UserName,",")>0 or Instr(UserName,chr(34))>0 or Instr(UserName,chr(9))>0 or Instr(UserName,"")>0 then
Call Cl.OutErr(0,ObjErr.selectSingleNode("NameChar").text)
end if
end If
只对用户名进行长度检查,和检查 chr(32) 空格 , chr(34) " chr(9) tab
但没对chr(39) ‘ 进行过滤,而程序很多地方调用到用户名,造成多处SQL注入漏洞。
解决方法:加强输入验证,过滤重要字符。
实例 2: DedeCms跨站漏洞
可以从上面看出,程序没有对用户输入的“’“进行编码处理输出,因此造成页面编码乱,造成html注入漏洞。
解决方法:根据环境要求,进行编码输出。
实例 3: Discuz!NT 2.5 SQL注入漏洞
漏洞文件:
showuser.aspx
漏洞主要函数:
GetUserList(int pagesize, int pageindex, string orderby, string ordertype)
漏洞分析:
public DataTable GetUserList(int pagesize, int pageindex, string orderby, string ordertype)
{
string[] array = new string[] { "username", "credits", "posts", "admin", "lastactivity", "joindate", "oltime" };
switch (Array.IndexOf<string>(array, orderby))
{
case 0:
orderby = string.Format("ORDER BY [{0}users].[username] {1},[{0}users].[uid] {1}", BaseConfigs.GetTablePrefix, ordertype);
break;
case 1:
orderby = string.Format("ORDER BY [{0}users].[credits] {1},[{0}users].[uid] {1}", BaseConfigs.GetTablePrefix, ordertype);
break;
……
}
DbParameter[] commandParameters = new DbParameter[] { DbHelper.MakeInParam("@pagesize", DbType.Double, 4, pagesize), DbHelper.MakeInParam("@pageindex", DbType.Double, 4, pageindex), DbHelper.MakeInParam("@orderby", DbType.AnsiStringFixedLength, 0x3e8, orderby) };
return DbHelper.ExecuteDataset(4, BaseConfigs.GetTablePrefix + "getuserlist", commandParameters).Tables[0];
}
从上面可以看出,ordertype没有过滤就直接进入了SQL查询,
ordertype 就是SQL注入的地方,从那里我们可以加入任何SQL语句。如:
省略..........
出现:
“/”应用程序中的服务器错误。
________________________________________
第 12 行: ',[dnt_users].[uid] asc' 附近有语法错误。
说明: 执行当前 Web 请求期间,出现未处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。
异常详细信息: System.Data.SqlClient.SqlException: 第 12 行: ',[dnt_users].[uid] asc' 附近有语法错误。
解决方法:对ordertype进行过滤,或用白名单形式处理。
实例 4: 存储过程注入举例
存储过程也可能存在SQL注入,由于存储过程中存在用于字符串连接的 + 号连接SQL语句,这就造成SQL注入的可能性.
CREATE PROCEDURE [dbo].[PR_UserManage_Users_BatchMove]
(
@UserType int = 1,
@GroupId NVarChar(500) ='',
@UserId NVarChar(4000) = '',
@UserName NVarChar(255) = '',
@StartUserId int = 0,
@EndUserId int = 0,
@BatchUserGroupId NVarChar(500) =''
)
AS
BEGIN
SET NOCOUNT OFF
If (@UserType = 1)
BEGIN
EXEC('Update PE_Users set GroupID= ' + @GroupId +' Where UserID in (' + @UserId + ')')
END
Else If(@UserType = 2)
BEGIN
EXEC('Update PE_Users set GroupID= ' + @GroupId +' Where UserName in (''' + @UserName + ''')')
END
Else If(@UserType = 3)
BEGIN
EXEC('Update PE_Users set GroupID= ' + @GroupId +' Where UserId between ' + @StartUserId + ' and ' + @EndUserId)
END
Else If(@UserType = 4)
BEGIN
EXEC('Update PE_Users set GroupID= ' + @GroupId +' Where GroupID in (' + @BatchUserGroupId + ')')
END
END
可以看出,在用户名的地方,没有过滤直接放入查询,造成in 类型的SQL注入漏洞。
解决方法:调用时要对参数进行过滤
实例 5: YXBBS任意文件下载漏洞
漏洞文件: ViewFile.asp
Function ChkFile(FileName)
Dim Temp,FileType,F
ChkFile=false
FileType=Lcase(Split(FileName,".")(ubound(Split(FileName,"."))))
Temp="|asp|aspx|cgi|php|cdx|cer|asa|"
If Instr(Temp,"|"&FileType&"|")>0 Then ChkFile=True
F=Replace(Request("FileName"),".","")
If instr(1,F,chr(39))>0 or instr(1,F,chr(34))>0 or instr(1,F,chr(59))>0 then ChkFile=True
End Function
可以从上面代码中看出,代码是使用黑名单形式,如果名称中等于列表中的就不能下载,但如果用户输入conn.asp%20(%20是指空格)这样就能绕黑名单验证,下载了conn.asp名件。
解决方法:使用白名单验证。
实例 6: 风讯任意文件浏览漏洞
漏洞文件:http://nt.demo.foosun.net/configuration/system/selectPath.aspx
如图:
图1
查看源码:
string Path = this.str_FilePath + base.Request.Form["Path"];
构造提交表单:
<form action="http://nt.demo.foosun.net/configuration/system/selectPath.aspx" method=POST >
<input type="text" name="path"/>
<input type=submit />
</form>
图 2
可以看出,系统没有对“..”进行进滤,于是就造成了这个漏洞。
解决方法:过滤 “..” 。
实例 7: KesionCMS浏览任意目录,删除任意目录和文件漏洞
漏洞文件:
Kesion.WebFilesCls.asp
漏洞描述:
<%
webDir=KS.Setting(3)
TopDir=Replace(WebDir&Topdir,"//","/")
action=LCase(Trim(KS.G("action")))
CurrentDir=Trim(Replace(KS.G("CurrentDir"),"../",""))
CurrentPage=KS.ChkClng(KS.G("page"))
if CurrentDir<>"" then
CurrentDir=Replace(CurrentDir & "/","//","/")
end if
Set Fso=Server.CreateObject(Trim(KS.Setting(99)))
Select Case action
可以看出,上面只过滤“../ ”
但可以这样绕过 “…/./” 过滤后就成了“../”。
解决方法:过滤 “..”
实例 8: 博客园CuteEditor文件管理漏洞
CuteEditor编辑品中的插入图片的都有对以上传的文件进行操作,但也没有限制性对“..”的使用,这样就可以让用户复制或移动任意文件到系统任意目录。
造成的危害有:
用户上传任意图片,复盖博客园中任何图片(有写权限目录)。
用户上传任意js,复盖博客园中任何js等。
解决方法:过滤“..”
参考资料
[1].开发更安全的ASP.NET2.0应用程序,[美]Dominick Baier 著,华中宇 田亮君 陈文 译.人民邮电出版社.2008.7
http://www.microsoft.com/taiwan/msdn/columns/huang_jhong_cheng/LVSS.htm
http://technet.microsoft.com/zh-cn/library/ms161953.aspx
http://www.microsoft.com/china/technet/security/guidance/secmod94.mspx
http://www.microsoft.com/china/technet/security/guidance/secmod83.mspx