由于网络应用程序和应用程序编程接口(API)是我们数字基础设施不可或缺的一部分,确保它们的安全性变得前所未有的重要。在数据泄露和网络攻击日益频发的当下,遵循保障应用程序安全的最佳实践至关重要。.NET 框架为开发人员提供了一套强大的工具,用于构建安全、健壮的网络应用程序和 API。本文探讨了.NET 中的关键安全实践,涵盖身份验证、授权、身份管理以及数据加密等方面,并为每个方面都提供了实用的代码示例。
身份验证与授权
保障网络应用程序和 API 的安全,首先要确保只有经过身份验证和授权的用户才能访问敏感资源。.NET 提供了多种方式来实现可靠的身份验证和授权。
JWT 身份验证
JSON 网络令牌(JSON Web Tokens,简称 JWT)通常用于对 API 请求进行身份验证。JWT 允许安全地传输用户信息,确保只有经过身份验证的用户才能访问特定端点。
示例:JWT 配置 以下示例展示了如何在 Program.cs
文件中配置 JWT 身份验证。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://authserver.com"; // 外部身份验证提供程序的 URL
options.Audience = "your_api"; // JWT 中预期的受众
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero // 令牌过期容差
};
});
services.AddAuthorization(options =>
{
options.AddPolicy("Admin", policy => policy.RequireRole("Admin"));
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
身份验证设置: ConfigureServices
方法注册了 JWT 承载身份验证方案。它设置了外部提供程序的 URL(Authority
),指定了令牌预期的受众(Audience
),并定义了令牌验证参数,例如验证颁发者、受众以及令牌过期情况,且不设置时钟偏差(时间容差)。
授权设置: AddAuthorization
方法配置了一项策略,要求用户具备“Admin”角色才能访问特定资源。
控制器与中间件: AddControllers
调用用于注册控制器,在 Configure
方法中,UseAuthentication
和 UseAuthorization
被添加到请求处理管道中,以确保强制执行身份验证和授权操作。最后,应用程序使用 MapControllers
来映射控制器端点。
OAuth2 和 OpenID Connect
OAuth2 和 OpenID Connect 被广泛用于管理用户身份验证和访问委托。在构建需要第三方集成或单点登录(Single Sign-On,简称 SSO)功能的应用程序时,这些协议至关重要。
在 Program.cs
中配置 OAuth2 和 OpenID Connect,以允许用户通过外部身份提供程序(例如谷歌、脸书)进行身份验证:
示例:OpenID Connect 配置 以下代码为一个 ASP.NET Core 应用程序配置了基于 Cookie 的身份验证和 OpenID Connect 身份验证。
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddOpenIdConnect(options =>
{
options.Authority = "https://identityprovider.com"; // OpenID Connect 提供程序的 URL
options.ClientId = "your_client_id";
options.ClientSecret = "your_client_secret";
options.ResponseType = "code";
options.SaveTokens = true;
});
}
身份验证设置: 在 ConfigureServices
方法中,定义了身份验证方案:
DefaultAuthenticateScheme
和DefaultSignInScheme
被设置为基于 Cookie 的身份验证方案,这意味着将使用 Cookie 来进行身份验证并存储用户会话信息。DefaultChallengeScheme
被设置为 OpenID Connect,因此当需要进行身份验证时,应用程序将重定向到 OpenID Connect 提供程序进行登录。
OpenID Connect 设置: OpenID Connect 的设置指定了以下内容:
Authority
:OpenID Connect 提供程序的 URL(例如,像 Azure Active Directory 或谷歌这样的身份提供程序的网址)。ClientId
和ClientSecret
:这些是应用程序用于向提供程序进行身份验证的凭据。ResponseType
:被设置为“code”,意味着应用程序将使用授权码流程来进行身份验证。SaveTokens
:被设置为true
,这样身份验证令牌(如访问令牌和刷新令牌)会被保存以供后续使用。
高级身份管理与 IdentityServer
对于更复杂的身份验证和授权场景,IdentityServer 或 ASP.NET Core Identity 必不可少。IdentityServer 为管理用户身份验证和 API 访问提供了一个健壮的框架,支持 OAuth2、OpenID Connect 等多种协议。
IdentityServer4 针对 OAuth2 和 OpenID Connect 的设置
IdentityServer4 是一个强大的框架,用于处理 OAuth2 流程,包括客户端凭据、授权码以及隐式授权等类型。它使你能够高效地管理客户端应用程序和用户身份。
示例:在 Identity Server 中配置客户端和 API 作用域 以下代码定义了在身份服务器(如 IdentityServer4)中客户端和 API 作用域的配置,用于处理 OpenID Connect 和 OAuth 2.0 身份验证。
public static class Config
{
public static IEnumerable<Client> Clients =>
new Client[]
{
new Client
{
ClientId = "client",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
RedirectUris = { "https://localhost:5001/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:5001/signout-callback-oidc" },
AllowedScopes = { "openid", "profile", "api1" }
}
};
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[]
{
new ApiScope("api1", "My API")
};
}
客户端配置: Clients
属性返回一个客户端数组。在此示例中,定义了一个客户端:
ClientId
:客户端的唯一标识符为“client”。ClientSecrets
:客户端使用一个经过 SHA-256 哈希处理的密钥(secret)向身份服务器进行身份验证。AllowedGrantTypes
:客户端被允许使用授权码流程(GrantTypes.Code
),这是一种通过交换授权码来获取令牌的安全流程。RedirectUris
:身份验证完成后,客户端将被重定向到该 URI(https://localhost:5001/signin-oidc
)。PostLogoutRedirectUris
:用户注销后,将被重定向到该 URI(https://localhost:5001/signout-callback-oidc
)。AllowedScopes
:客户端被允许请求访问“openid”、“profile”和“api1”这些作用域,其中包括用户的 OpenID Connect 身份、个人资料数据以及对某个 API 的访问权限。
API 作用域配置: ApiScopes
属性定义了可用的 API 作用域。在此示例中: 定义了一个名为“api1”且描述为“My API”的 API 作用域。该作用域控制着客户端可以请求访问的 API 资源。
ASP.NET Core Identity
如果你需要对用户管理进行更细粒度的控制,ASP.NET Core Identity 是管理用户、角色和声明的首选解决方案。
ASP.NET Core Identity 可与 IdentityServer 结合使用,以应对复杂场景,例如集成外部身份验证提供程序、多因素身份验证(Multi-factor Authentication,简称 MFA)等情况。
以下代码为一个 ASP.NET Core 应用程序配置了身份和授权,设置了用户身份验证以及基于角色的访问控制。
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin"));
});
}
身份设置: AddIdentity<ApplicationUser, IdentityRole>()
方法将 ASP.NET Core Identity 服务添加到应用程序中:
ApplicationUser
:一个自定义用户类(大概是继承自内置的IdentityUser
类),它代表系统中的用户。IdentityRole
:代表系统中的角色(例如“Admin”“User”等)。AddEntityFrameworkStores<ApplicationDbContext>()
:配置 Identity 使用带有ApplicationDbContext
的实体框架,以便将用户和角色数据存储在数据库中。AddDefaultTokenProviders()
:添加默认的令牌提供程序,用于生成在密码重置、电子邮件确认等操作中使用的令牌。
授权设置: AddAuthorization
方法定义了一个自定义授权策略: 创建了一个名为“AdminOnly”的策略,要求用户具备“Admin”角色才能访问受此策略保护的资源。
###.NET 中的数据加密 加密敏感数据是保障网络应用程序安全的核心部分。在.NET 中,有内置的加密库可帮助保护传输中和存储状态下的数据安全。
加密传输中的数据(HTTPS)
对于传输中的数据,务必确保你的网络应用程序使用 HTTPS 来加密客户端与服务器之间的通信。
示例:在 ASP.NET Core 中强制使用 HTTPS 要强制使用 HTTPS,你可以配置应用程序将所有 HTTP 请求重定向到 HTTPS:
public void Configure(IApplicationBuilder app)
{
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
加密存储状态下的数据(AES)
对于加密存储在数据库或文件中的敏感数据,高级加密标准(Advanced Encryption Standard,简称 AES)是一种广泛使用且安全可靠的加密算法。.NET 提供了 System.Security.Cryptography
命名空间来处理加密操作。
示例:配置 AES 加密敏感数据 在此示例中,使用 AES 来加密敏感数据。对于存储加密密钥,可使用像 Azure Key Vault 这样的安全密钥管理解决方案来管理密钥和机密信息。
using (Aes aesAlg = Aes.Create())
{
aesAlg.Key = Encoding.UTF8.GetBytes("a very secure key!");
aesAlg.IV = Encoding.UTF8.GetBytes("initialization vct");
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
swEncrypt.Write("sensitive data to encrypt");
}
}
byte[] encrypted = msEncrypt.ToArray();
}
}
AES 算法创建: Aes.Create()
方法创建了一个 AES 加密算法的实例(aesAlg
),它将用于加密过程。
密钥和初始化向量(IV)设置:
aesAlg.Key
:加密密钥通过字符串“a very secure key!”的字节来设置。该密钥对于加密以及后续解密数据至关重要。aesAlg.IV
:初始化向量(IV)通过字符串“initialization vct”的字节来设置。IV 为加密过程增加了随机性,确保相同数据多次加密会产生不同的输出结果。
加密器创建: CreateEncryptor
方法使用提供的密钥和 IV 创建了一个加密器对象(ICryptoTransform encryptor
)。
用于加密数据的内存流: 创建了一个 MemoryStream
(msEncrypt
),用于在写入加密数据时将其临时保存在内存中。
加密用的加密流: 创建了一个 CryptoStream
(csEncrypt
),它将内存流和加密器连接起来。使用 CryptoStreamMode.Write
模式将加密后的数据写入流中。
用于写入数据的流写入器: 创建了一个 StreamWriter
(swEncrypt
),用于将明文(“sensitive data to encrypt”)写入 CryptoStream
,在此处数据将被加密。
加密过程: 敏感数据通过 StreamWriter
写入,经 CryptoStream
加密,最终存储在 MemoryStream
中。
获取加密数据: 加密过程完成后,通过将 MemoryStream
的内容转换为字节数组(msEncrypt.ToArray()
)来获取加密后的数据。
安全保障是一项需要持续投入精力的工作,它要求注重细节并使用合适的工具。通过实施诸如 JWT、OAuth2 和 OpenID Connect 等可靠的身份验证和授权机制,并利用像 IdentityServer 和 ASP.NET Core Identity 这样强大的框架,你可以确保你的网络应用程序和 API 是安全的,并且只有授权用户才能访问。此外,采用数据加密的最佳实践(无论是针对传输中的数据还是存储状态下的数据)有助于保护敏感数据,并确保符合行业标准。
如果你喜欢我的文章,请给我一个赞!谢谢