RSS 2.0 Feed
Security
摘要:【原文地址】Tip/Trick: Enabling SSL on IIS 7.0 Using Self-Signed Certificates 【原文发表日期】 Friday, April 06, 2007 12:31 AM SSL允许浏览器与web服务器在一个安全的通道上交换信息,以防范窃听,篡改和消息伪造。你应该总是在登录页面(用户在上面输入用户名和密码),以及网站上其他所有安全敏感的网页上使用SSL,譬如,那些显示财务或个人信息的帐号网页。 在Windows早期的IIS版本上配置SSL很痛苦,搞清楚如何安装和管理证书,然后如何将证书与一个网站相关联,我敢说是大多数web开发人员并不知道怎么做的事情。 好消息是,IIS 7.0使配置和启用SSL成为小菜一碟。IIS 7.0现在对创建“自签证书(Self Signed Certificates)”也有内置的支持,自签证书允许你轻松地创建测试或个人证书,然后你可以用之来为开发或测试目的对一个网站快速启用SSL。 使用IIS 7.0的话,你可以在30秒内对一个现有的网站完成启用SSL。下面的教程示范该怎么来做。 第一步:创建一个新网站 我们先使用新的IIS 7.0管理工具创建一个新的网站。这个管理工具是对以前IIS管理工具的完全重写的结果(是使用Windows Forms全部用托管代码写成的),提供了对web特性更逻辑的组织。它对所有的ASP.NET和IIS设置提供了一个GUI管理体验:   要在机器上创建一个新的网站,在左手的树形视图窗口里右击“网站(Web Sites)”节点,选择“添加网站(Add Web Site)”上下文菜单选项。输入适当的细节创建一个新的网站: Windows Vista上IIS7的一个很棒的特性是,你现在可以在本机上拥有的网站数目不再受限制(早期Windows客户机上IIS版本只允许一个网站)。早期Windows客户机IIS版本的10个并发请求的限制在IIS 7.0上也不再存在。 我们完成上面的步骤后,在我们的IIS web服务器上就有一个崭新的网站在运行了。 第二步:创建一个新的自签证书 在把SSL规则绑定到我们的新网站之前,我们首先需要引入和建立一个安全证书来用于SSL绑定。 在IIS 7.0中,可以这么来管理证书,点击左手树形视图管理器里的根机器节点(root machine node),然后在右边的特性视窗里选择“服务器证书(Server Certificates)”图案: 这会列出在机器上注册了的所有证书,并允许你引入或者创建新的证书。 我也可以去象Verisign这样的证书机构购买一个证书,然后用这个管理界面来引入。或者,我也可以创建一个“自签证书”,这是个测试证书,我可以在开发期间用来测试我的网站。可以这么做,在管理工具的右手边点击“创建自签证书(Create Self-Signed Certificate)”链接: 给证书输入一个名字 (譬如:“test”),点击OK. 然后IIS7就会自动为你创建一个自签加密证书(self-signed crypto certificate),同时与机器注册该证书: 第三步: 为我们的网站启用HTTPS绑定 要给我们在前面创建的网站启用SSL,在左手边的树形视图窗口里选择网站节点,然后在屏幕右手边的“操作(actions)”视窗里点击“绑定(Bindings)”链接: 这会调出一个对话框,上面列出了将访问者(traffic)导向该网站的所有的绑定规则 (即,该网站的主机头(host-header)/IP地址/端口组合): 要给网站启用SSL,我们要点击“添加(Add)”按钮。这会调出一个“添加绑定(add binding)”对话框,我们可以用来添加HTTPS协议支持。我们可以从对话框上的SSL证书下拉框里选择我们先前创建的自签证书, 这么做表明在SSL上给内容加密时,我们要使用那个证书: Click ok, and we now have SSL enabled for......[阅读全文]

posted @ | Feedback (4) | Filed Under [ ASP.NET IIS7 Tips and Tricks Security ]

摘要:【原文地址】JSON Hijacking and How ASP.NET AJAX 1.0 Avoids these Attacks【原文发表日期】 Wednesday, April 04, 2007 11:39 AM 最近,由安全研究人员发表的一些报告描述了一些方法,可以被黑客通过利用为绝大多数流行的AJAX框架所用的JSON线上格式来试着利用(exploit)浏览器中的跨域脚本。具体来说,这些攻击使用通过 HTML <script src=""> 包含(include)元素来调用的HTTP GET请求来绕过由浏览器强制执行的“同源策略(same origin policy)”(同源策略限制了象XmlHttpRequest这样的JavaScript对象只能调用当前页面来自的同一域上的URL),然后寻找利用(exploit)JSON负载内容的方法。 ASP.NET AJAX 1.0 包括了许多默认设置和内置特性,可以防范它免受这些类型的JSON劫持攻击。下面是它如何缓和这些攻击的一些细节: ASP.NET AJAX Web方法在默认情形下是禁止HTTP GET请求的 通过浏览器中的HTML <script src=""> 元素来装载的脚本文件只能通过HTTP GET动词请求来获取。 在默认情形下, ASP.NET AJAX的web服务层不允许web方法通过HTTP GET 动词来调用。譬如,假如一个开发人员编写了象下面这样的web服务方法: [WebMethod]public StockQuote[] GetQuotes(string symbol) {} ASP.NET只允许上面的GetQuotes方法通过HTTP POST动词来调用,会拒绝通过HTTP GET动词调用该方法的任何尝试。 要使一个ASP.NET AJAX web方法可以通过HTTP GET来访问,开发人员必须明确地使用ASP.NET的ScriptMethod 特性来标记每个web方法(同时设置UseHttpGet属性为true): [WebMethod] [ScriptMethod(UseHttpGet=true)] public StockQuote[] GetQuotes(string symbol) { }  虽然这类改动很容易做,但它要求一个开发人员有意识地启用web服务的GET调用。ASP.NET AJAX web服务绝不会故意地启用GET,ASP.NET AJAX文档明确地指出了许多理由(URL篡改的危险是其中一个理由),不赞成启用GET来调用web服务端点。 注: ASP.NET AJAX UpdatePanel 控件,以及随ASP.NET AJAX 1.0一起发布的其他服务器控件,在做异步postback时,并不使用HTTP GET,而是使用HTTP POST。 ASP.NET AJAX Content-Type 头信息的验证 我们有一个由ASP.NET强制执行的针对基于GET和POST的ASP.NET AJAX web方法的内置的验证保护层,不管用了哪个HTTP动词,ASP.NET总是要求HTTP Content-Type头信息是被设置为 application/json 这个值的。假如这个content type头信息并没有被发送过来,那么ASP.NET AJAX就会在服务器端拒绝这个请求。 用前面的股票报价方法的例子,一个ASP.NET AJAX GET调用的跟踪输出必须看上去象下面这样: GET /StockService/Stock.asmx/GetQuotes?symbol=%22msft%22 HTTP/1.1 Accept: */* Accept-Language: en-us,fr;q=0.5 Referer: http://xxxxxx/StockService/test.aspx Content-Type: application/json; charset=utf-8 UA-CPU: x86 Accept-Encoding: gzip, deflate User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2) Host: xxxxxx Proxy-Connection: Keep-Alive  注意,即使上面只是个GET请求,客户端ASP.NET AJAX JSON层还是会插入一个Content-Type HTTP头的,告诉服务器把这个请求当作是个AJAX web服务请求。ASP.NET AJAX 1.0的服务器端web服务层总是检查这个特定的content type,如果没找到的话,它就会拒绝这个请求。......[阅读全文]

posted @ | Feedback (3) | Filed Under [ ASP.NET .NET Atlas Security ]

摘要:【原文地址】Tip/Trick: Integrating ASP.NET Security with Classic ASP and Non-ASP.NET URLs 【原文发表日期】 Sunday, March 04, 2007 6:17 PM 别人经常问我的一个问题是,“我怎么能把ASP.NET安全与经典ASP和其他非ASP.NET URLs集成起来?” 具体地来说,他们想知道他们是否能把ASP.NET中的表单认证,基于角色的安全, 以及URL授权等特性与经典ASP,PHP,JSP,.HTM, .JPG以及其他的非ASP.NET URLs集成起来。 好消息是,在今天的ASP.NET 2.0和IIS 6.0中,这非常容易,到IIS 7.0时段时,这将会更加容易。下面的博客帖子将示范如何把ASP.NET的表单认证和登录/成员特性与经典ASP和静态的.HTML文件集成起来。 想了解如何实现这个功能(以及如何把象基于ASP.NET角色的授权与经典ASP应用集成)的更详细的按部就班的示范的话,请阅读Stefan Schackow的精彩好书《ASP.NET 2.0 安全, 成员和角色管理(ASP.NET 2.0 Security, Membership, and Role Management)》中的第六章。 IIS 6.0的通配符映射一些背景知识 Windows Server 2003中的IIS 6.0中添加了对一个被称之为“通配符映射(wildcard mappings)”的ISAPI特性的支持。通配符映射提供了一个方式来配置IIS,使得进入服务器的所有请求首先被转到一个或多个ISAPI扩展作处理。IIS 6.0中的通配符映射一个非常酷的事情是,在处理通配符扩展的ISAPI扩展结束之后,它能使得IIS把请求的控制传递到IIS中通常处理该请求的扩展或内部处理器那里去。 ASP.NET 2.0包括了对利用这个通配符映射特性的内置支持。这允许你在现有的处理非ASP.NET URL(譬如,.asp, .php 或 .htm请求)的ISAPI扩展执行之前和之后运行ASP.NET编码或者你自己的自定义编码。 我们可以使用这个特性来启用一堆酷的集成特性,包括ASP.NET认证和授权特性,来为web服务器上的所有URLs设置安全。 如何配置IIS 6.0通配符映射 为这个例子起见,我将在IIS 6.0管理工具里创建一个新的IIS应用,叫做“wildcardtest”。它指向一个将含有default.aspx, login.aspx, test.asp 和 test.htm几个文件的目录(这后面2个文件代表了通常不由ASP.NET处理的资源): 在默认情形下,当一个对.aspx网页的URL请求到达该应用时,ASP.NET ISAPI 将处理这个请求。在默认情形下,当一个对test.asp的URL请求到达该应用时,经典的ASP ISAPI将处理这个请求,没有ASP.NET编码会运行的。当一个对test.htm的URL请求到达该应用时,IIS6会在内部处理这个请求,同样地,没有ASP.NET编码会运行的。 我们将通过对该应用启用通配符映射来改变这种情形,配置ASP.NET在到达该服务器的所有请求之前和之后运行些编码。想这么做的话,在IIS管理工具里右击当前应用,选择其上的“属性”上下文菜单选项。这会打开应用的属性对话框: 然后,你可以点击“配置(configuration)”按钮,打开该应用的URL映射规则页: 注意,这个对话框的上方列出了默认的ISAPI扩展名映射(每个URL扩展名都映射到了负责处理该扩展名的ISAPI)。对话框的下方列出了“通配应用映射(wildcard application map)”规则。我们可以点击“添加”按钮来给ASP.NET ISAPI添加一个应用的通配符映射,将其指向一个硬盘上的ASP.NET 2.0 ISAPI扩展: 非常重要的事项:确认你不选“核实该文件是存在的(Verify this file exists)”复选框。如果你不这么做的话,象WebResource.axd和其他被ASP.NET处理的但并没有对应物理文件的ASP.NET URL资源会停止工作,这会导致你的网页出错。 接下来,点击OK按钮接受变动,关闭所有的对话框。至此,你就配置了ASP.NET能在每个进入该应用的请求之前和之后运行编码。 对非ASP.NET资源启用表单认证和Url授权 一旦我们完成上面的步骤,把ASP.NET 2.0注册成进入我们IIS应用的所有URLs的通配符映射之后,我们就可以使用标准的ASP.NET认证和授权技术来鉴定我们应用中的用户,准许或拒绝他们的访问。 譬如,我们可以加一个web.config文件到我们的应用中,为该应用启用ASP.NET的表单认证特性,然后建立2个URL授权规则,拒绝“匿名”用户对test.asp和test.htm的访问: <?xml version="1.0"?><configuration>    <system.web>        <authentication mode="Forms" />    </system.web>    <location path="test.asp">        <system.web>            <authorization>                <deny users="?"/>                <allow users="*"/>            </authorization>        </system.web>            </location>    <location path="test.htm">        <system.web>            <authorization>                <deny users="?"/>                <allow users="*"/>            </authorization>        </system.web>            </location></configuration> 现在,当我试图访问"test.asp"或者 "test.htm"时,ASP.NET认证和授权系统会先执行,检查我是否已经通过表单认证登录进当前的应用,如果还没有登录的话,会转向到该应用的login.aspx网页让我来登录:......[阅读全文]

posted @ | Feedback (9) | Filed Under [ ASP.NET IIS7 Tips and Tricks Security ]

摘要:【原文地址】 Common Gotcha: Don't forget to when adding providers 【原文发表日期】 Monday, November 20, 2006 11:22 PM 最近,我帮了几个人,他们在如何在web.config文件里添加新的成员(Membership),角色(Role)和用户信息(Profile)提供器(provider)上遇上了问题。如果你会在你的web.config文件里添加提供器声明的话,请继续读下去,了解一下如何避免一个常见的问题。 症状: 你要配置ASP.NET 2.0来在远程SQL数据库里存储你的成员/角色管理/用户信息数据。为达成这个目的,你首先使用aspnet_regsql.exe工具在数据库里生成了合适的数据定义。你决定不在你的web.config文件里覆盖"LocalSqlServer"这个连接字符串,而是象下面这样,在你的web.config文件里注册一个新的提供器 (注:下面这个注册有个bug,所以别拷贝/粘贴):       <membership>            <providers>                <add name="AspNetSqlMembershipProvider"                    type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"                    connectionStringName="MyDatabase"                    enablePasswordRetrieval="false"                    enablePasswordReset="true"                    requiresQuestionAndAnswer="true"                    requiresUniqueEmail="false"                    passwordFormat="Hashed"                    maxInvalidPasswordAttempts="5"                    minRequiredPasswordLength="7"                    minRequiredNonalphanumericCharacters="1"                    passwordAttemptWindow="10"                    passwordStrengthRegularExpression=""                     applicationName="/"                 />            </providers>      </membership> 在注册上面这个提供器时,你很小心地明确设置了applicationName属性,因此避免了另外一个非常常见的问题。 但,当你在一个没有SQL Express的机器上运行你的应用时,你看到了有点奇怪的行为。你也许会得到象这样的出错信息: An error has occurred while establishing a connection to the server.  When connecting to SQL Server 2005, this failure may be caused by the fact that under the default settings SQL Server does not allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified) (在建立到服务器的连接时发生了错误。 当连接到 SQL Server 2005时,连接失败可能是因为在默认设置下 SQL Server 不允许远程连接这个事实导致的。(提供器:SQL网络接口,错误:26 - 查找指定服务/实例时出错)) 你也许会发现web管理工具在连接到你的数据库时也有问题,或者你用它创建的角色/用户没有在上面配置的数据库里正确地存储下来。 问题的起因: 上面这个问题的根本原因取决于新的提供器是如何在web.config 文件注册的。 web.config 文件里的......[阅读全文]

posted @ | Feedback (2) | Filed Under [ ASP.NET .NET Tips and Tricks Security ]

摘要:【原文地址】Tip/Trick: Source/Documentation for Simple ASP.NET 2.0 SQL Providers Published 【原文发表日期】 Friday, October 13, 2006 9:36 PM ASP.NET 2.0中一个最受欢迎的特性是在内置的ASP.NET应用服务API中引进了“提供器模型(provider model)”。提供器模型确保象成员(Membership),角色(Roles),用户信息(Profiles),Health Monitoring,会话状态(Session State),和站点导航(Site Navigation)这样的服务的存储和实现是可以扩展的,允许开发人员很轻松地接入另外的实现,如果他们需要的话。 今年早些时候,我在博客里宣布,我们在MSDN上发布了内置的ASP.NET 2.0提供器的源码,同时还发布了超过130页的内容翔实的文档,这些文档对这些提供器的实现和行为做了介绍。如果你想改编现有的提供器(虽然这些提供器之特性涵盖广泛而且深入)为你所用,那么你会发现这些白皮书和源码是值得一看的好资源。但直接研读内置的富有特性并且优化过的提供器的源码的一个缺点是,这些源码也许比你想要的更大,更复杂,而且使用的数据库定义与你要的数据库结构之间也不相对应。 Michal Valasek今天早些时候给我发了一个邮件,告诉我他在CodePlex发起了一个非常酷的项目,该项目提供了针对ASP.NET成员,角色和用户信息API的一套简化的SQL提供器的实现。该实现使用了非常直接了当的数据库定义,可以很容易地将其改编为你的应用所用或与你现有的数据表集成。你可以在这里下载它们的源码。我绝对建议你去看一下,并且将这个项目的网址收藏,因为它们为编写定制的提供器提供了一个非常好的开端。 想进一步了解ASP.NET提供器模型的话,我也建议你看一下Paul Wilson做的一个非常棒的编码营( Code-Camp)讲座,他提供了一个用他的ORMapper实现的提供器,你可以在这里下载与该讲座相关的资源。你也可以在我的ASP.NET安全资源网页上找到其他非SQL服务器的提供器实现,包括针对MySql,SqlLite,Access的提供器等等。 希望本文对你有所帮助, Scott 标签:ASP.NET, Security, Tips and Tricks...[阅读全文]

posted @ | Feedback (5) | Filed Under [ ASP.NET Tips and Tricks Security ]

摘要:【原文地址】Tip/Trick: Adding Authorization Rules to Business and Data Layers using PrincipalPermissionAttributes 【原文发表日期】 Wednesday, October 04, 2006 8:50 AM 今夏早些时候,我写了2篇在ASP.NET中使用Windows认证的教程:《在内网(Intranet) ASP.NET Web应用中启用Windows认证》和《在ASP.NET 中使用Windows认证和SQL服务器实现基于角色的安全机制》。我也贴出了Scott Mitchell著的非常棒的《ASP.NET 2.0之安全,成员和角色》系列教程的连接,该教程讨论了如何在面向Internet的web应用中使用表单认证和ASP.NET中新的成员和角色API。 这些教程讨论的是如何在你的网站上实现认证(authentication),即识别来访的用户是谁的过程。它们也示范了如何在你的网站上实现基于角色的管理,允许你将单独的用户从逻辑上分组成为较高层次的角色或组别,譬如,“管理员(admins)”, “朋友(friends)”,“订阅者(subscribers)”等等。这些教程也示范了如何实现授权规则来准予或拒绝用户或角色访问一个网站内的单独页面或URL。(上面提到的角色教程也示范了如何根据来访的用户的权限来显示/隐藏导航菜单节点。) 给业务和数据层添加安全授权规则 当你在一个ASP.NET应用中认证一个用户之后,通过认证的用户的身份(identity)将在服务器端处理用户请求的整个过程中自动流动(flow)。这意味着,你不需要从一个方法到另一个方法,或从一个类到另一个类,手工传递用户的身份(identity)。这使得在你整个应用中实现安全授权规则极其容易。 .NET中一个少为人知的特性是,在生成一个类的实例对象,或者访问一个对象的方法或属性(property)之前,能够让CLR自动根据这个身份信息来给用户授权的能力。这使得给你的业务和数据层添加安全授权规则极其容易,不必写太多编码。 你要做的就是使用System.Security.Permission命名空间下的PrincipalPermissionAttribute,在适当的类或类的成员上标记这个属性即可。譬如: using System;using System.Security.Permissions;[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]public class EmployeeManager{    [PrincipalPermission(SecurityAction.Demand, Role = "Manager")]    public Employee LookupEmployee(int employeeID)    {       // todo    }    [PrincipalPermission(SecurityAction.Demand, Role = "HR")]    public void AddEmployee(Employee e)    {       // todo    }} 在上面的例子中,我给EmployeeManager类添加了一个PrincipalPermission属性。这么做的效果是,我要求在处理一个用户的web请求时,在实例化这个类之前,这个用户必须先通过认证(即先登录),Authenticated=true这要求强迫系统这么做。然后,我在LookupEmployee和AddEmployee方法上另加了2个安全要求。对于 LookupEmployee 方法,我要求通过认证的用户要调用这个方法的话,必须属于“经理(Manager)”这个角色。对于 AddEmploye 方法,我要求通过认证的用户要调用这个方法来给系统添加一个新的雇员的话,必须属于“人事部(HR)”这个角色。 这样,假如我偶然地在UI层引人了安全漏洞,有一些编码路径允许一个不是经理或不属于人事部的雇员导致这些方法被调用,那么我的业务层会自动防范这样的事情发生,并且抛出一个安全异常来。 并不局囿于任何特定的认证模式。它可以与表单认证,Windows认证,Passport认证,或者你想发明的任何定制的认证模式一起合作使用。它也可以和我想用的任何角色机制一起使用,这样,如果你建立或接入你自己的ASP.NET角色提供器的话,它自动会工作的。 PrincipalPermissionAttribute类是在标准的CLR mscorlib 程序集中实现的,这个程序集是所有的 .NET项目编译时都需要引用的。所以它不是特定于ASP.NET的,它可以在任何应用类型下使用,包括Windows和控制台程序。这个事实,除了使它更加有用外,也使得单元测试使用它的业务/数据层库项目更加容易。 在页面和控件里使用PrincipalPermissionAttribute PrincipalPermissionAttribute可用在一个应用的任何类上。所以,除了在你的业务和数据层使用该属性外,你也可以在ASP.NET页面或者用户控件里使用该属性。譬如,想限制你的“MyPage”页面只能被拥有Manager角色的用户访问的话,你可以在该页的后台编码( code-behind)添加一个 PrincipalPermission属性(下面以VB编码为例): Imports System.Security.Permissions<PrincipalPermission(SecurityAction.Demand, Authenticated:=True, Role:="Manager")> _Partial Class MyPage    Inherits System.Web.UI.PageEnd Class ASP.NET安全方面的更多信息 想进一步了解ASP.NET安全的话,我建议你看一下我的ASP.NET安全资源列单以及我的ASP.NET技巧和诀窍网页。 现在外面有2本专门的有关ASP.NET 2.0安全的书:Stefan Schackow的《Professional ASP.NET 2.0 Security, Membership and Role Management》一书以及本星期才出版的Dominick Baier的新书《Developing More Secure Microsoft ASP.NET 2.0 Applications》,Dominick Baier还著有一个非常棒的博客: http://www.leastprivilege.com。 希望本文对你有所帮助, Scott 标签:ASP.NET, .NET, Security, Tips and Tricks  (思归译) ...[阅读全文]

posted @ | Feedback (10) | Filed Under [ ASP.NET .NET Tips and Tricks Security ]

摘要:【原文地址】Tip/Trick: Guard Against SQL Injection Attacks 【原文发表日期】 Saturday, September 30, 2006 9:11 AM SQL注入攻击是非常令人讨厌的安全漏洞,是所有的web开发人员,不管是什么平台,技术,还是数据层,需要确信他们理解和防止的东西。不幸的是,开发人员往往不集中花点时间在这上面,以至他们的应用,更糟糕的是,他们的客户极其容易受到攻击。 Michael Sutton 最近发表了一篇非常发人深省的帖子,讲述在公共网上这问题是多么地普遍。他用Google的Search API建了一个C#的客户端程序,寻找那些易受SQL 注入攻击的网站。其步骤很简单: 寻找那些带查询字符串的网站(例如,查询那些在URL里带有 "id=" 的URL) 给这些确定为动态的网站发送一个请求,改变其中的id=语句,带一个额外的单引号,来试图取消其中的SQL语句(例如,如 id=6' ) 分析返回的回复,在其中查找象“SQL” 和“query”这样的词,这往往表示应用返回了详细的错误消息(这本身也是很糟糕的) 检查错误消息是否表示发送到SQL服务器的参数没有被正确加码(encoded),如果如此,那么表示可对该网站进行SQL注入攻击 对通过Google搜寻找到的1000个网站的随机取样测试,他检测到其中的11.3%有易受SQL注入攻击的可能。这非常,非常地可怕。这意味着黑客可以远程利用那些应用里的数据,获取任何没有hashed或加密的密码或信用卡数据,甚至有以管理员身份登陆进这些应用的可能。这不仅对开发网站的开发人员来说很糟糕,而且对使用网站的消费者或用户来说更糟糕,因为他们给网站提供了数据,想着网站是安全的呢。 那么SQL注入攻击到底是什么玩意? 有几种情形使得SQL注入攻击成为可能。最常见的原因是,你动态地构造了SQL语句,却没有使用正确地加了码(encoded)的参数。譬如,考虑这个SQL查询的编码,其目的是根据由查询字符串提供的社会保险号码(social security number)来查询作者(Authors): Dim SSN as StringDim SqlQuery as StringSSN = Request.QueryString("SSN")SqlQuery = "SELECT au_lname, au_fname FROM authors WHERE au_id = '" + SSN + "'" 如果你有象上面这个片断一样的SQL编码,那么你的整个数据库和应用可以远程地被黑掉。怎么会呢?在普通情形下,用户会使用一个社会保险号码来访问这个网站,编码是象这样执行的: ' URL to the page containing the above codehttp://mysite.com/listauthordetails.aspx?SSN=172-32-9999' SQL Query executed against the database SELECT au_lname, au_fname FROM authors WHERE au_id = '172-32-9999' 这是开发人员预期的做法,通过社会保险号码来查询数据库中作者的信息。但因为参数值没有被正确地加码,黑客可以很容易地修改查询字符串的值,在要执行的值后面嵌入附加的SQL语句 。譬如, ' URL to the page containing the above codehttp://mysite.com/listauthordetails.aspx?SSN=172-32-9999';DROP DATABASE pubs --' SQL Query executed against the database SELECT au_lname, au_fname FROM authors WHERE au_id = '';DROP DATABASE pubs -- 注意到没有,我可以在SSN查询字符串值的后面添加“ ';DROP DATABASE pubs -- ”,通过 “;”字符来终止当前的SQL语句,然后添加了我自己的恶意的SQL语句,然后把语句的其他部分用“--”字符串注释掉。因为我们是手工在编码里构造SQL语句,我们最后把这个字符串传给了数据库,数据库会先对authors表进行查询,然后把我们的pubs数据库删除。“砰(bang)”的一声,数据库就没了! 万一你认为匿名黑客删除你的数据库的结果很坏,但不幸的是,实际上,这在SQL注入攻击所涉及的情形中算是比较好的。一个黑客可以不单纯摧毁数据,而是使用上面这个编码的弱点,执行一个JOIN语句,来获取你数据库里的所有数据,显示在页面上,允许他们获取用户名,密码,信用卡号码等等。他们也可以添加 UPDATE/INSERT 语句改变产品的价格,添加新的管理员账号,真的搞砸你(screw up your life)呢。想象一下,到月底检查库存时,发现你库房里的实际产品数与你的帐目系统(accounting system)汇报的数目有所不同。。。 那该如何保护你自己? SQL注入攻击是你需要担心的事情,不管你用什么web编程技术,再说所有的web框架都需要担心这个的。你需要遵循几条非常基本的规则: 1) 在构造动态SQL语句时,一定要使用类安全(type-safe)的参数加码机制。大多数的数据API,包括ADO和ADO.NET,有这样的支持,允许你指定所提供的参数的确切类型(譬如,字符串,整数,日期等),可以保证这些参数被恰当地escaped/encoded了,来避免黑客利用它们。一定要从始到终地使用这些特性。 例如,在ADO.NET里对动态SQL,你可以象下面这样重写上述的语句,使之安全: Dim SSN as String = Request.QueryString("SSN")Dim cmd As new SqlCommand("SELECT au_lname, au_fname FROM authors WHERE au_id = @au_id")Dim param = new SqlParameter("au_id", SqlDbType.VarChar)param.Value = SSNcmd.Parameters.Add(param) 这将防止有人试图偷偷注入另外的SQL表达式(因为ADO.NET知道对au_id的字符串值进行加码),以及避免其他数据问题(譬如不正确地转换数值类型等)。注意,VS 2005内置的TableAdapter/DataSet设计器自动使用这个机制,ASP.NET 2.0数据源控件也是如此。 一个常见的错误知觉(misperception)是,假如你使用了存储过程或ORM,你就完全不受SQL注入攻击之害了。这是不正确的,你还是需要确定在给存储过程传递数据时你很谨慎,或在用ORM来定制一个查询时,你的做法是安全的。 2) 在部署你的应用前,始终要做安全审评(security review)。建立一个正式的安全过程(formal security process),在每次你做更新时,对所有的编码做审评。后面一点特别重要。很多次我听说开发队伍在正式上线(going live)前会做很详细的安全审评,然后在几周或几个月之后他们做一些很小的更新时,他们会跳过安全审评这关,推说,“就是一个小小的更新,我们以后再做编码审评好了”。请始终坚持做安全审评。 3) 千万别把敏感性数据在数据库里以明文存放。我个人的意见是,密码应该总是在单向(one-way )hashed过后再存放,我甚至不喜欢将它们在加密后存放。在默认设置下,ASP.NET 2.0 Membership API 自动为你这么做,还同时实现了安全的SALT 随机化行为(SALT randomization behavior)。如果你决定建立自己的成员数据库,我建议你查看一下我们在这里发表的我们自己的Membership provider的源码。同时也确定对你的数据库里的信用卡和其他的私有数据进行了加密。这样即使你的数据库被人入侵(compromised)了的话,起码你的客户的私有数据不会被人利用。 4) 确认你编写了自