Skip to content

第十九章:安全性與資料保護 (Security & Data Protection)

19.1 引言:安全性的重要性

安全性漏洞可能導致:

  • 資料外洩:客戶資料被竊取,面臨法律訴訟與罰款。
  • 服務中斷:DDoS 攻擊導致服務無法使用。
  • 聲譽損害:客戶失去信任。

根據 OWASP (Open Web Application Security Project),我們將探討最常見的安全威脅及其防範方法。


19.2 授權 (Authorization)

授權決定了「已驗證的使用者」是否有權執行某個操作。

1. 基於權限的授權

ABP 提供了強大的權限系統。

定義權限

csharp
public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
    public override void Define(IPermissionDefinitionContext context)
    {
        var bookStoreGroup = context.AddGroup("BookStore", L("Permission:BookStore"));

        var booksPermission = bookStoreGroup.AddPermission(
            "BookStore.Books",
            L("Permission:Books")
        );

        booksPermission.AddChild("BookStore.Books.Create", L("Permission:Create"));
        booksPermission.AddChild("BookStore.Books.Edit", L("Permission:Edit"));
        booksPermission.AddChild("BookStore.Books.Delete", L("Permission:Delete"));
    }
}

使用權限

csharp
public class BookAppService : ApplicationService
{
    [Authorize("BookStore.Books.Create")]
    public async Task<BookDto> CreateAsync(CreateBookDto input)
    {
        var book = new Book(GuidGenerator.Create(), input.Name, input.Price);
        await _bookRepository.InsertAsync(book);
        return ObjectMapper.Map<Book, BookDto>(book);
    }

    [Authorize("BookStore.Books.Delete")]
    public async Task DeleteAsync(Guid id)
    {
        await _bookRepository.DeleteAsync(id);
    }
}

2. 基於策略的授權 (Policy-Based Authorization)

對於複雜的授權邏輯,使用策略。

csharp
public class MinimumAgeRequirement : IAuthorizationRequirement
{
    public int MinimumAge { get; }
    public MinimumAgeRequirement(int minimumAge) => MinimumAge = minimumAge;
}

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        MinimumAgeRequirement requirement)
    {
        var ageClaim = context.User.FindFirst(c => c.Type == "age");

        if (ageClaim != null && int.Parse(ageClaim.Value) >= requirement.MinimumAge)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

// 註冊
services.AddAuthorization(options =>
{
    options.AddPolicy("Adult", policy =>
        policy.Requirements.Add(new MinimumAgeRequirement(18)));
});

services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();

// 使用
[Authorize(Policy = "Adult")]
public async Task<AdultContentDto> GetAdultContentAsync() { }

19.3 資料加密 (Data Encryption)

1. ASP.NET Core Data Protection API

用於加密敏感資料 (如個人識別資訊)。

配置

csharp
builder.Services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(@"/var/keys"))
    .SetApplicationName("BookStore")
    .ProtectKeysWithCertificate(certificate); // 生產環境使用憑證

使用

csharp
public class UserService : ITransientDependency
{
    private readonly IDataProtectionProvider _dataProtectionProvider;
    private readonly IDataProtector _protector;

    public UserService(IDataProtectionProvider dataProtectionProvider)
    {
        _dataProtectionProvider = dataProtectionProvider;
        _protector = _dataProtectionProvider.CreateProtector("UserService.PersonalData");
    }

    public string EncryptIdCard(string idCard)
    {
        return _protector.Protect(idCard);
    }

    public string DecryptIdCard(string encryptedIdCard)
    {
        return _protector.Unprotect(encryptedIdCard);
    }
}

2. 在實體中自動加密

使用 EF Core 的 Value Converters。

csharp
public class EncryptedStringConverter : ValueConverter<string, string>
{
    public EncryptedStringConverter(IDataProtector protector)
        : base(
            v => protector.Protect(v),
            v => protector.Unprotect(v))
    {
    }
}

// 在 DbContext 中配置
protected override void OnModelCreating(ModelBuilder builder)
{
    var protector = _dataProtectionProvider.CreateProtector("EntityEncryption");

    builder.Entity<User>(b =>
    {
        b.Property(e => e.IdCardNumber)
            .HasConversion(new EncryptedStringConverter(protector));
    });
}

19.4 GDPR 合規 (GDPR Compliance)

GDPR (General Data Protection Regulation) 是歐盟的資料保護法規,但其原則適用於全球。

1. 資料最小化 (Data Minimization)

只收集必要的資料。

csharp
public class UserConsent : Entity<Guid>
{
    public Guid UserId { get; set; }
    public string Purpose { get; set; } // "Marketing", "Analytics"
    public bool Granted { get; set; }
    public DateTime GrantedAt { get; set; }
    public string Version { get; set; } // 隱私政策版本
}

public class ConsentService : ITransientDependency
{
    private readonly IRepository<UserConsent, Guid> _consentRepository;

    public async Task<bool> HasConsentAsync(Guid userId, string purpose)
    {
        return await _consentRepository.AnyAsync(c =>
            c.UserId == userId &&
            c.Purpose == purpose &&
            c.Granted);
    }

    public async Task GrantConsentAsync(Guid userId, string purpose, string version)
    {
        var consent = new UserConsent
        {
            Id = Guid.NewGuid(),
            UserId = userId,
            Purpose = purpose,
            Granted = true,
            GrantedAt = DateTime.UtcNow,
            Version = version
        };

        await _consentRepository.InsertAsync(consent);
    }
}

3. 資料刪除權 (Right to Erasure)

csharp
public class UserDataDeletionService : ITransientDependency
{
    private readonly IRepository<User, Guid> _userRepository;
    private readonly IRepository<Order, Guid> _orderRepository;

    public async Task DeleteUserDataAsync(Guid userId)
    {
        var user = await _userRepository.GetAsync(userId);

        // 匿名化個人資料
        user.Email = $"deleted_{userId}@example.com";
        user.PhoneNumber = null;
        user.IdCardNumber = null;
        user.IsActive = false;

        await _userRepository.UpdateAsync(user);

        // 匿名化訂單資料
        var orders = await _orderRepository.GetListAsync(o => o.CustomerId == userId);
        foreach (var order in orders)
        {
            order.ShippingAddress = null;
            await _orderRepository.UpdateAsync(order);
        }
    }
}

19.5 防範 OWASP Top 10

1. Injection (注入攻擊)

威脅:SQL Injection, NoSQL Injection。 防範:使用參數化查詢 (EF Core 預設)。

csharp
// ❌ 危險
var sql = $"SELECT * FROM Books WHERE Title = '{title}'";
var books = _context.Books.FromSqlRaw(sql).ToList();

// ✅ 安全
var books = await _bookRepository.GetListAsync(b => b.Title == title);

2. Broken Authentication (身分驗證失效)

威脅:弱密碼、Session 劫持。 防範

  • 強制強密碼政策。
  • 使用 HTTPS。
  • 實作 Multi-Factor Authentication (MFA)。
csharp
Configure<IdentityOptions>(options =>
{
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireUppercase = true;
    options.Password.RequireNonAlphanumeric = true;
    options.Password.RequiredLength = 8;

    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
});

3. Sensitive Data Exposure (敏感資料外洩)

威脅:明文儲存密碼、信用卡號。 防範

  • 使用 HTTPS (TLS 1.2+)。
  • 加密敏感欄位 (如前述 Data Protection API)。
  • 不要在日誌中記錄敏感資料。
csharp
// 過濾敏感資料
Configure<AbpAuditingOptions>(options =>
{
    options.IgnoredTypes.Add(typeof(CreditCard));
});

4. XML External Entities (XXE)

威脅:XML 解析器被利用來讀取伺服器檔案。 防範:停用 DTD 處理。

csharp
var settings = new XmlReaderSettings
{
    DtdProcessing = DtdProcessing.Prohibit,
    XmlResolver = null
};

using var reader = XmlReader.Create(stream, settings);

5. Broken Access Control (存取控制失效)

威脅:使用者能存取不屬於他的資料。 防範:在每個操作中驗證權限。

csharp
public async Task<BookDto> GetAsync(Guid id)
{
    var book = await _bookRepository.GetAsync(id);

    // 確保使用者有權存取此書籍
    if (book.OwnerId != CurrentUser.Id && !await IsAdminAsync())
    {
        throw new AbpAuthorizationException();
    }

    return ObjectMapper.Map<Book, BookDto>(book);
}

6. Security Misconfiguration (安全性設定錯誤)

威脅:預設密碼、錯誤訊息洩漏資訊。 防範

  • 移除預設帳號或強制修改密碼。
  • 在生產環境關閉詳細錯誤訊息。
csharp
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

7. Cross-Site Scripting (XSS)

威脅:注入惡意 JavaScript。 防範:Razor 預設會編碼輸出。

html
<!-- ✅ 安全:自動編碼 -->
<p>@Model.UserComment</p>

<!-- ❌ 危險:不編碼 -->
<p>@Html.Raw(Model.UserComment)</p>

8. Insecure Deserialization (不安全的反序列化)

威脅:惡意序列化資料導致 RCE (Remote Code Execution)。 防範:不要反序列化不受信任的資料。

9. Using Components with Known Vulnerabilities

威脅:使用有已知漏洞的 NuGet 套件。 防範:定期更新套件。

bash
dotnet list package --vulnerable
dotnet outdated

10. Insufficient Logging & Monitoring

威脅:攻擊無法被偵測。 防範:記錄所有安全相關事件。

csharp
public async Task<bool> LoginAsync(string username, string password)
{
    try
    {
        var result = await _signInManager.PasswordSignInAsync(username, password, false, true);

        if (result.Succeeded)
        {
            Logger.LogInformation("User {Username} logged in successfully", username);
        }
        else
        {
            Logger.LogWarning("Failed login attempt for user {Username}", username);
        }

        return result.Succeeded;
    }
    catch (Exception ex)
    {
        Logger.LogError(ex, "Login error for user {Username}", username);
        throw;
    }
}

19.6 審計日誌 (Audit Logging)

ABP 自動記錄所有 Application Service 的呼叫。

1. 啟用審計

csharp
Configure<AbpAuditingOptions>(options =>
{
    options.IsEnabled = true;
    options.IsEnabledForGetRequests = true; // 記錄 GET 請求
    options.ApplicationName = "BookStore";
});

2. 查詢審計日誌

csharp
public class AuditLogAppService : ApplicationService
{
    private readonly IAuditLogRepository _auditLogRepository;

    public async Task<List<AuditLogDto>> GetUserAuditLogsAsync(Guid userId, DateTime from, DateTime to)
    {
        var logs = await _auditLogRepository.GetListAsync(
            userId: userId,
            startTime: from,
            endTime: to
        );

        return ObjectMapper.Map<List<AuditLog>, List<AuditLogDto>>(logs);
    }
}

19.7 實戰練習

練習 1:實作權限系統

  1. 定義完整的權限樹 (至少 10 個權限)。
  2. 為不同角色分配權限。
  3. 測試未授權存取會被拒絕。

練習 2:資料加密

  1. User 實體的 IdCardNumber 欄位實作自動加密。
  2. 驗證資料庫中儲存的是密文。

練習 3:GDPR 合規

  1. 實作完整的資料刪除流程。
  2. 實作資料匯出功能 (Right to Data Portability)。

19.8 總結

安全性是一個持續的過程,而非一次性的任務。

  • 授權 確保使用者只能做他們被允許的事。
  • 加密 保護敏感資料。
  • GDPR 合規保護使用者隱私。
  • OWASP Top 10 提供了安全檢查清單。

在下一章,我們將進入 UI 現代化,探討如何整合現代前端框架。


參考資源

Released under the MIT License.