核心思想:分层防御

网站权限设置不是单一操作,而是一个“纵深防御”体系,每个层面都有其职责,共同确保网站的安全。

asp.net 网站权限设置
(图片来源网络,侵删)
  1. 操作系统层面:最底层,控制文件和进程的访问权限。
  2. IIS 服务器层面:Web 服务器层面,控制匿名访问、身份验证方式、URL 授权等。
  3. 应用程序代码层面:最高层,实现业务逻辑级别的权限控制(用户A只能编辑自己的文章)。

操作系统权限

这是基础,如果这里没做好,上层的安全措施可能会被绕过。

应用程序池标识

你的 ASP.NET 应用程序运行在某个“应用程序池”中,这个应用程序池有一个“进程标识”(Process Identity),决定了它以哪个用户的身份在操作系统上运行。

  • 默认设置:通常是 NETWORK SERVICE,这是一个受限账户,比 SYSTEMAdministrator 安全得多。
  • 最佳实践
    • 不要将应用程序池标识设置为 SYSTEM 或管理员账户,除非有特殊且必要的原因。
    • 为每个网站创建专用用户:如果多个网站共享一个服务器,为每个网站的应用程序池创建一个独立的、低权限的 Windows 用户,这样可以隔离风险,一个网站被攻破,不会影响到其他网站。
    • 权限分配:为这个专用用户分配最小的必要权限,只给它读取网站程序文件和写入 App_Data 文件夹的权限,而不要给整个 C: 盘的写入权限。

文件和文件夹权限

在 Windows 资源管理器中,右键点击网站文件夹 -> 属性 -> 安全 选项卡。

  • 网站根目录 (e.g., C:\inetpub\wwwroot\MyWebApp)
    • IIS_IUSRS:必须拥有 读取 和执行列出文件夹内容读取 权限,这是 IIS 用来执行你的网站代码所必需的。
    • 应用程序池用户:如果你为网站创建了专用用户,则该用户需要上述权限。
    • SYSTEMAdministrators:拥有完全控制权,方便管理和维护。
    • Users:通常需要读取权限,但需要根据具体情况评估。
  • App_Data 文件夹
    • 这个文件夹通常用于存放数据库文件(.mdf, .dbf)或敏感数据。
    • 移除 EveryoneUsers 的所有权限
    • 只授予 应用程序池用户SYSTEM 完全控制 权限,确保你的网站代码能读写,但其他任何人都不能访问。
  • Web.config 文件
    • 这是一个非常敏感的文件,包含数据库连接字符串、加密密钥等。
    • 只授予 应用程序池用户SYSTEM 读取 权限,其他用户(包括 IIS_IUSRS)都不需要读取权限。

IIS 服务器权限

在 IIS 管理器中进行配置。

asp.net 网站权限设置
(图片来源网络,侵删)

身份验证

在 IIS 管理器中,选择你的网站 -> IIS -> 身份验证

  • 匿名身份验证
    • 作用:允许任何用户访问网站,无需登录。
    • 如何工作:它会使用一个固定的账户(默认是 IUSR)来访问服务器资源。
    • 配置
      • 对于公开网站:必须启用。
      • 对于内部网站:可以禁用。
      • 最佳实践:不要将匿名账户设置为高权限账户(如管理员),让它保持默认的 IUSR 或映射到你之前创建的专用低权限用户。
  • Windows 身份验证
    • 作用:使用 Windows 用户账户进行登录验证。
    • 类型:有“Negotiate”(Kerberos)和“NTLM”两种,前者更安全,性能也更好。
    • 适用场景:企业内部网,用户已经在同一个 Windows 域中,可以使用域账户登录。
    • 配置:在启用此选项时,通常会禁用匿名身份验证
  • ASP.NET Core 模拟
    • 在 IIS 中,你可以选择是否“模拟”。
    • 如果选择“模拟”,ASP.NET 应用程序将以你配置的身份(匿名用户或 Windows 用户)的身份运行,去访问操作系统文件。
    • 如果不选择“模拟”(默认),那么应用程序将以应用程序池的身份运行。
    • 建议:通常不启用模拟,让应用程序以应用程序池的身份运行,权限管理更清晰。

授权

在 IIS 管理器中,选择你的网站 -> 功能视图 -> 授权规则

  • 作用:基于 URL 路径控制哪些用户或角色可以访问哪些页面或文件夹。
  • 示例
    • 你可以创建一条规则,拒绝所有匿名用户访问 Admin 文件夹。
    • 你可以创建一条规则,只允许 Administrators 角色访问 /Dashboard.aspx 页面。
  • 使用方法:点击“添加授权规则”,可以选择“允许”或“拒绝”,然后指定用户/角色或匿名用户。

应用程序代码层面

这是最灵活、最精细的控制方式。

ASP.NET Forms Authentication (Web Forms / MVC 早期版本)

这是经典的基于 Cookie 的身份验证方式。

  • 配置 Web.config
    • <system.web> 节点下配置:
      <authentication mode="Forms">
        <forms loginUrl="~/Account/Login.aspx" timeout="30" slidingExpiration="true" />
      </authentication>
    • loginUrl:未登录用户被重定向到的登录页。
    • <authorization> 节点:在页面或文件夹级别进行授权。
      <!-- 允许所有人访问 -->
      <allow users="*" />
      <!-- 拒绝匿名用户访问 -->
      <deny users="?" />
      <!-- 拒绝特定用户 -->
      <deny users="SomeBadUser" />
      <!-- 允许特定角色 -->
      <allow roles="Admin, Manager" />
      <!-- 拒除特定角色 -->
      <deny roles="Guest" />
  • 登录逻辑
    • 在登录页面,验证用户名和密码。
    • 验证成功后,调用 FormsAuthentication.SetAuthCookie(username, rememberMe) 来创建身份验证票证(Cookie)。
  • 检查登录状态
    • 在页面的代码中,使用 Page.User.Identity.IsAuthenticated 来判断用户是否已登录。

ASP.NET Identity (ASP.NET MVC / Core 推荐方案)

这是现代的、基于角色的成员资格提供程序,更强大、更灵活。

  • 核心概念

    • 用户IdentityUser 类,包含用户名、密码、邮箱等。
    • 角色IdentityRole 类,如 "Admin", "User", "Editor"。
    • 用户-角色关系:一个用户可以属于多个角色。
  • 配置

    • 通过 NuGet 安装 Microsoft.AspNetCore.Identity.EntityFrameworkCore 等包。
    • Startup.cs (或 Program.cs in .NET 6+) 中配置服务和中间件。
  • 授权方式

    • 特性授权:在 Controller 或 Action 方法上使用特性,这是最简洁的方式。

      // 要求用户已登录
      [Authorize]
      public IActionResult Profile() { ... }
      // 要求用户属于 "Admin" 角色
      [Authorize(Roles = "Admin")]
      public IActionResult Dashboard() { ... }
      // 要求用户是特定用户名
      [Authorize(Policy = "CanEditOnlyOwnProfile")]
      public IActionResult EditProfile() { ... }
    • 基于策略的授权:更复杂、更灵活的授权方式,你可以定义一个策略,然后在代码中检查该策略。“用户必须年满18岁”或“用户必须通过双重验证”。

      // 在 Startup.ConfigureServices 中定义策略
      services.AddAuthorization(options =>
      {
          options.AddPolicy("RequireAdminRole", policy => 
              policy.RequireRole("Admin"));
      });
      // 在 Controller 中使用
      [Authorize(Policy = "RequireAdminRole")]
      public IActionResult AdminOnlyArea() { ... }
    • 资源授权:在 Action 方法内部进行授权检查,适用于复杂的业务逻辑。

      public async Task<IActionResult> EditArticle(int id)
      {
          var article = await _context.Articles.FindAsync(id);
          if (article == null)
          {
              return NotFound();
          }
          // 检查当前用户是否是文章作者或管理员
          if (User.IsInRole("Admin") || User.FindFirstValue(ClaimTypes.NameIdentifier) == article.AuthorId)
          {
              return View(article);
          }
          return Forbid(); // 返回 403 Forbidden
      }

总结与最佳实践清单

  1. 从操作系统开始

    • [ ] 使用低权限的应用程序池标识(NETWORK SERVICE 或专用用户)。
    • [ ] 严格设置文件和文件夹权限,特别是 App_DataWeb.config
  2. 配置 IIS

    • [ ] 根据网站类型(公开/内部)正确配置匿名和 Windows 身份验证。
    • [ ] 使用 IIS 的 URL 授权功能对敏感目录(如 /Admin)进行粗粒度访问控制。
  3. 编写代码进行精细控制

    • [ ] 对于新项目,优先使用 ASP.NET Identity
    • [ ] 在 Controller 上使用 [Authorize] 特性保护需要登录的页面。
    • [ ] 使用 [Authorize(Roles = "...")] 来基于角色控制访问。
    • [ ] 对于复杂业务逻辑(如“只能修改自己的数据”),使用基于策略的授权或资源授权。
    • [ ] 永远不要在代码中硬编码用户名或密码,使用 Identity 或其他安全的认证库。
    • [ ] 对密码进行哈希处理(Identity 会自动处理)。
    • [ ] 使用 HTTPS 来保护传输中的身份验证 Cookie 和敏感数据。

通过遵循以上三个层面的设置,你可以构建一个既安全又灵活的 ASP.NET 网站权限系统。