ASP.NET 登录控件使您能够提供一种解决方案,根据用户身份验证、成员资格和角色来控制对网页的访问。登录控件包括:CreateUserWizard 控件、Login 控件、LoginStatus 控件、LoginView 控件、PasswordRecovery 控件和 ChangePassword 控件。
虽然下面的编码和配置最佳实践可以提高应用程序的安全,但您还需要不断地更新 Web 服务器,安装最新的 Microsoft Windows 和 Internet 信息服务 (IIS) 的安全修补程序以及 Microsoft SQL Server 或其他数据源的任何修补程序,这一点也很重要。
通过 Michael Howard 和 David LeBlanc 撰写的 Writing Secure Code(《编写安全代码》)一书以及“Microsoft Patterns and Practices”(Microsoft 的模式与实践)(http://www.microsoft.com/resources/practices/default.mspx) 提供的指导,可以找到有关编写安全代码以及保证应用程序安全的最佳实践的更多详细信息。
一、登录控件的一般安全实践
保护登录控件涉及以下各方面的最佳实践,下文对此进行了简单介绍并提供指向更多信息的链接。
1.1、使用安全套接字层 (SSL) 协议
ASP.NET 登录控件通过 HTTP 以纯文本形式将信息传输到服务器。在处理敏感信息时,强烈推荐您结合使用 HTTPS 协议和安全套接字层 (SSL) 加密。SSL 可防止数据被更改(数据完整性)、保护用户的标识(保密性)并确保数据来源于预期的客户端(身份验证)。
1.2、验证用户输入
切勿认为您从用户那里得到的输入内容是安全的。恶意用户可能从客户端将存在潜在危险的信息发送到您的应用程序。对于登录控件,对用户输入采取防范措施尤为重要,因为输入的信息通常都是敏感信息。
请尽可能使用验证控件来测试有效的用户名和强密码。您可以在不使用验证控件的情况下验证某些用户输入。例如,CreateUserWizard 控件支持必需的验证和比较验证。还可以指定带有 EmailRegularExpression 属性的正则表达式来验证电子邮件地址是否与指定模式匹配,指定带有 PasswordRegularExpression 属性的正则表达式来验证密码是否满足要求。
为了在验证登录控件中的用户输入时获得最大的灵活性,您可以使用模板。请尽可能为控件创建模板、添加个别控件(通常为 TextBox 控件)并添加验证控件,以便将用户的输入内容限制在最小的允许范围内。
说明: 使用验证控件时,除了使用客户端验证外,请始终对服务器代码执行验证。这有助于防止用户通过禁用或更改客户端脚本检查来跳过验证。
1.3、保证视图状态的安全
登录控件可以将信息存储在页的视图状态中,因此保证视图状态的安全是一种最佳安全实践。尽管视图状态数据是以编码格式存储的,但仍可以对其进行查看和篡改。
1.4、保护成员资格
ASP.NET 成员资格提供了用于验证和存储用户凭据的功能。CreateUserWizard、Login、PasswordRecovery 和 ChangePassword 控件使用 ASP.NET 成员资格,使您无需编写任何代码或只需编写很少代码即可创建一个完善的身份验证系统。此外,LoginName、LoginStatus 和 LoginView 控件可用于完善您的解决方案,使它能够处理用户成员资格并控制对网站中各页的访问。
如 MaxInvalidPasswordAttempts 属性中指定的那样,ASP.NET 随附的成员资格提供程序对无效密码或密码提示问题答案的最大尝试次数设有内置阈值。如 PasswordAttemptWindow 属性中指定的那样,ASP.NET 成员资格还使您能够配置在锁定成员资格用户之前允许的无效密码或密码提示问题答案的最大尝试次数的分钟数。默认的密码尝试阈值为 5 次,而默认的密码尝试时限为 10 分钟。在应用程序的 Web.config 文件的 membership 节中设置的阈值可以重写默认提供程序中的阈值。建议在设置这些阈值时尽可能小一些。此外,建议您不要将 RequiresQuestionAndAnswer 属性设置为 false,因为这会使得系统不跟踪无效的密码答案尝试。
1.5、保证电子邮件的安全
CreateUserWizard、ChangePassword 和 PasswordRecovery 控件可以发送包含有关已完成用户事务的详细信息的电子邮件。确保向用户发送的任何电子邮件消息只显示必需的信息。例如,防止非目标收件人从其他电子邮件消息中轻易筛选出电子邮件的主题行。建议您不要在电子邮件中发送密码。考虑使用验证密码事务的其他方法,如发送确认代码和返回 URL,要求用户使用该 URL 完成这一事务。
如果未指定 CreateUserWizard、ChangePassword 和 PasswordRecovery 控件的 MailDefinition 属性,则不会发送电子邮件。如果将这些控件配置为发送电子邮件,则建议您处理邮件错误事件以捕捉任何与 SMTP 相关的错误,从而避免向用户显示不必要的信息。对于 ChangePassword 控件,处理 SendMailError 并将 SendMailErrorEventArgs 对象的 Handled 属性设置为 true。
二、个别控件的安全注意事项
以下各节描述个别登录控件的安全注意事项。
2.1、CreateUserWizard
CreateUserWizard 控件收集来自用户的信息,然后在 ASP.NET 成员资格系统中为该用户创建帐户。您可以通过在 CreateUserWizardStep 和 CompleteWizardStep 步骤的前后添加字段或步骤来扩展 CreateUserWizard 控件,以接受其他信息。如果用户还未完成 CreateUserWizard 控件中的所有步骤就创建帐户,可能出现安全问题。若要防止用户跳过自定义向导步骤,请重写 OnNextButtonClick 方法并执行自定义身份验证。收集到信息后,请使用 MembershipProvider 类的 CreateUser 方法来创建该用户。
如果您正在执行管理任务并使用 CreateUserWizard 来自动创建用户帐户,建议将 AutoGeneratePassword 属性设置为 true 并将 LoginCreatedUser 属性设置为 false。在这种特定的情况下,建议将 DisableCreatedUser 属性设置为 false。
2.2、登录控件
Login 控件是一个由用户名文本框、密码文本框和一个复选框组成的复合控件,其中的复选框表明用户是否希望系统记住该用户以便下次访问该页。RememberMeSet 属性将向用户的浏览器发送身份验证 Cookie,而 DisplayRememberMe 属性则显示一个复选框,该复选框使用户能够控制是否发送持久性 Cookie。避免将 RememberMeSet 设置为 true 和将 DisplayRememberMe 设置为 false,因为虽然发送了Cookie,但用户无法识别它。通常,将 Cookie 存储在用户的计算机上会有一定的风险。Cookie 是另一种形式的用户输入,因此也可能会导致信息泄露和欺骗。
如果您的 Login 控件面向各种最终用户,请考虑对控件编码,这样使用公共计算机的用户可以选择使用非持久性 Cookie(在会话超时后即丢弃该 Cookie)。
2.3、LoginName 控件
LoginName 控件显示用户的登录名,如果应用程序使用 Windows 身份验证,该控件则显示用户的域名和帐户名。请考虑添加一个复选框,使用户能够指定是否显示他们的用户名或帐户信息。例如,公共计算机上的用户可能不希望显示敏感信息。
2.4、LoginView 控件
LoginView 控件使您能够向已登录的用户和未登录的用户(匿名用户)显示不同的信息。请检查使用 AnonymousTemplateLoggedInTemplate 模板显示的内容和使用与 RoleGroups 属性关联的模板显示的任何内容,从而确保用户无法查看他人的模板。具体来说,系统会按照定义模板的顺序来搜索 RoleGroups 属性中的集合。然后向用户显示第一个匹配的角色组模板。如果某个用户是多个角色的成员,则显示与该用户的任何角色匹配的第一个角色组模板。如果有多个模板与单个角色关联,则只使用第一个定义的模板。
2.5、PasswordRecovery 控件
PasswordRecovery 控件使用户能够根据与他们的用户名关联的电子邮件地址来找回其密码。配置 PasswordRecovery 控件时,请遵循下列准则:
·如果发送电子邮件时出现错误,则处理 SendMailError 事件以采取措施。
·使用 MaxInvalidPasswordAttempts 属性设置次数有限的密码提示问题答案尝试,并使用 PasswordAttemptWindow 属性设置时限。
·查看发送到用户电子邮件的所有信息并查看用于传输消息的通道的安全,尤其当密码恢复电子邮件消息包含用户密码时。避免发送明确表明包含敏感信息的电子邮件,如在主题行中包含“密码”等字眼。
2.6、ChangePassword 控件
ChangePassword 控件使用户能够更改他们的密码。配置 ChangePassword 控件时,请遵循下列准则:
·如果发送电子邮件时出现错误,则处理 SendMailError 事件以采取措施。
·使用 MaxInvalidPasswordAttempts 属性设置次数有限的密码提示问题答案尝试,并使用 PasswordAttemptWindow 属性设置时限。
·查看发送到用户电子邮件的所有信息并查看用于传输消息的通道的安全,尤其当配置 ChangePassword 控件使用电子邮件向用户发送新密码时。
·使用 SSL 来确保用户的新密码在回发期间无法读取。
·对于 ChangePassword 控件用作发送给用户的电子邮件正文,限制对该文件的访问。通过 MailDefinition 类的 BodyFileName 属性来定义该文件。