ASP.NET Core 中的欧盟一般数据保护条例 (GDPR) 支持

作者:Rick Anderson

ASP.NET Core 提供 API 和模板,帮助满足欧盟一般数据保护条例 (GDPR) 的部分要求:

  • 项目模板包括扩展点和存根标记,可以将其替换为 privacy 和 cookie 使用策略。
  • Pages/Privacy.cshtml 页面或 Views/Home/Privacy.cshtml 视图提供页面以详细说明站点的 privacy 策略。

若要启用如在生成了应用的当前 ASP.NET Core 模板中的 ASP.NET Core 2.2 模板中发现的默认 cookie 内容,请将以下突出显示的代码添加到 Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    // This lambda determines whether user consent for non-essential 
    // cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;

    options.MinimumSameSitePolicy = SameSiteMode.None;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

在前面的代码中,使用的是 CookiePolicyOptionsUseCookiePolicy

  • 将 cookie 同意部分添加到 _Layout.cshtml 文件:

                @*Previous markup removed for brevity*@
        </header>
        <div class="container">
            <partial name="_CookieConsentPartial" />
            <main role="main" class="pb-3">
                @RenderBody()
            </main>
        </div>
    
        <footer class="border-top footer text-muted">
            <div class="container">
                &copy; 2022 - WebGDPR - <a asp-area="" asp-page="/Privacy">Privacy</a>
            </div>
        </footer>
    
        <script src="~/lib/jquery/dist/jquery.min.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    
        @await RenderSectionAsync("Scripts", required: false)
    </body>
    </html>
    
  • _CookieConsentPartial.cshtml 文件添加项目:

    @using Microsoft.AspNetCore.Http.Features
    
    @{
        var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
        var showBanner = !consentFeature?.CanTrack ?? false;
        var cookieString = consentFeature?.CreateConsentCookie();
    }
    
    @if (showBanner)
    {
        <div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
            Use this space to summarize your privacy and cookie use policy. <a asp-page="/Privacy">Learn More</a>.
            <button type="button" class="accept-policy close" data-bs-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
                <span aria-hidden="true">Accept</span>
            </button>
        </div>
        <script>
            (function () {
                var button = document.querySelector("#cookieConsent button[data-cookie-string]");
                button.addEventListener("click", function (event) {
                    document.cookie = button.dataset.cookieString;
                }, false);
            })();
        </script>
    }
    
  • 选择本文的 ASP.NET Core 2.2 版本,了解 cookie 同意功能。

使用属性“CookiePolicyOptions.ConsentCookieValue”指定用于跟踪用户是否已同意 cookie 使用策略的值:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    options.CheckConsentNeeded = context => true;
    options.MinimumSameSitePolicy = SameSiteMode.None;
    options.ConsentCookieValue = "true";
});

var app = builder.Build();

rest 加密

某些数据库和存储机制允许进行 rest 加密。 rest 加密:

  • 自动加密存储的数据。
  • 无需对访问数据的软件进行配置、编程或其他操作即可进行加密。
  • 最简单且最安全的选项。
  • 允许数据库管理密钥和加密。

例如:

对于不提供内置 rest 加密的数据库,可以使用磁盘加密来提供相同的保护。 例如:

其他资源

  • 项目模板包括扩展点和存根标记,可以将其替换为 privacy 和 cookie 使用策略。
  • cookie 同意功能允许你请求(和跟踪)用户同意存储个人信息。 如果用户不同意数据收集且应用将 CheckConsentNeeded 设置为 true,则不会将非必要的 Cookie 发送到浏览器。
  • Cookie 可以标记为“必要”。 即使用户未同意且已禁用跟踪,也会将必需的 Cookie 发送到浏览器。
  • 禁用跟踪后,TempData 和会话 Cookie 将不起作用。
  • Identity 页面提供下载和删除用户数据的链接。

示例应用允许测试已添加到 ASP.NET Core 2.1 模板中的大多数 GDPR 扩展点和 API。 有关测试说明,请参阅 ReadMe 文件。

查看或下载示例代码如何下载

模板生成代码中的 ASP.NET Core GDPR 支持

使用项目模板创建的 Razor Pages 和 MVC 项目包括以下 GDPR 支持:

  • CookiePolicyOptionsUseCookiePolicyStartup 类中设置。
  • _CookieConsentPartial.cshtml 分部视图。 此文件中包含“接受”按钮。 用户单击“接受”按钮时,即表示同意存储 Cookie。
  • Pages/Privacy.cshtml 页面或 Views/Home/Privacy.cshtml 视图提供页面以详细说明站点的 privacy 策略。 _CookieConsentPartial.cshtml 文件生成指向 Privacy 页的链接。
  • 对于使用个人用户帐户创建的应用,“管理”页面提供了下载和删除个人用户数据的链接。

CookiePolicyOptions 和 UseCookiePolicy

CookiePolicyOptionsStartup.ConfigureServices 中初始化:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services 
    // to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies 
            // is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // If the app uses session state, call AddSession.
        // services.AddSession();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the 
    // HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseAuthentication();

        // If the app uses session state, call Session Middleware after Cookie 
        // Policy Middleware and before MVC Middleware.
        // app.UseSession();

        app.UseMvc();
    }
}

UseCookiePolicyStartup.Configure 中调用:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services 
    // to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies 
            // is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

        // If the app uses session state, call AddSession.
        // services.AddSession();

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

    // This method gets called by the runtime. Use this method to configure the 
    // HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseAuthentication();

        // If the app uses session state, call Session Middleware after Cookie 
        // Policy Middleware and before MVC Middleware.
        // app.UseSession();

        app.UseMvc();
    }
}

_CookieConsentPartial.cshtml 分部视图

_CookieConsentPartial.cshtml 分部视图:

@using Microsoft.AspNetCore.Http.Features

@{
    var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
    var showBanner = !consentFeature?.CanTrack ?? false;
    var cookieString = consentFeature?.CreateConsentCookie();
}

@if (showBanner)
{
    <nav id="cookieConsent" class="navbar navbar-default navbar-fixed-top" role="alert">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#cookieConsent .navbar-collapse">
                    <span class="sr-only">Toggle cookie consent banner</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <span class="navbar-brand"><span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span></span>
            </div>
            <div class="collapse navbar-collapse">
                <p class="navbar-text">
                    Use this space to summarize your privacy and cookie use policy.
                </p>
                <div class="navbar-right">
                    <a asp-page="/Privacy" class="btn btn-info navbar-btn">Learn More</a>
                    <button type="button" class="btn btn-default navbar-btn" data-cookie-string="@cookieString">Accept</button>
                </div>
            </div>
        </div>
    </nav>
    <script>
        (function () {
            document.querySelector("#cookieConsent button[data-cookie-string]").addEventListener("click", function (el) {
                document.cookie = el.target.dataset.cookieString;
                document.querySelector("#cookieConsent").classList.add("hidden");
            }, false);
        })();
    </script>
}

此分部视图:

  • 获取用户的跟踪状态。 如果应用配置为需要同意,则用户必须同意才能跟踪 Cookie。 如果需要同意,则 cookie 同意面板固定在由 _Layout.cshtml 文件创建的导航栏的顶部。
  • 提供 HTML <p> 元素,以汇总 privacy 和 cookie 使用策略。
  • 提供指向 Privacy 页面或视图的链接,可以在其中详细说明站点的 privacy 策略。

必需的 Cookie

如果未同意存储 Cookie,则仅将标记为必需的 Cookie 发送到浏览器。 以下代码可将 cookie 设置为必需:

public IActionResult OnPostCreateEssentialAsync()
{
    HttpContext.Response.Cookies.Append(Constants.EssentialSec, 
        DateTime.Now.Second.ToString(), 
        new CookieOptions() { IsEssential = true });

    ResponseCookies = Response.Headers[HeaderNames.SetCookie].ToString();

    return RedirectToPage("./Index");
}

TempData 提供程序和会话状态 Cookie 不是必需的

TempData 提供程序cookie 不是必需的。 如果禁用跟踪,则 TempData 提供程序不起作用。 若要在禁用跟踪时启用 TempData 提供程序,请在 Startup.ConfigureServices 中将 TempData cookie 标记为必需:

// The TempData provider cookie is not essential. Make it essential
// so TempData is functional when tracking is disabled.
services.Configure<CookieTempDataProviderOptions>(options => {
    options.Cookie.IsEssential = true;
});

会话状态 Cookie 不是必需的。 禁用跟踪后,会话状态不起作用。 以下代码可将会话 Cookie 设置为必需:

services.AddSession(options =>
{
    options.Cookie.IsEssential = true;
});

个人数据

使用个人用户帐户创建的 ASP.NET Core 应用包含用于下载和删除个人数据的代码。

选择用户名,然后选择“个人数据”:

管理个人数据页面

注意:

  • 请参阅基架 Identity,了解如何生成 Account/Manage 代码。
  • 删除”和“下载”链接仅对默认 identity 数据起作用。 创建自定义用户数据的应用必须扩展为删除/下载自定义用户数据。 有关详细信息,请参阅添加、下载和删除自定义用户数据到 Identity
  • 通过因外键引起的级联删除行为删除用户时,为用户存储在 Identity 数据库表 AspNetUserTokens 中的已保存令牌将被删除。
  • 在接受 cookie 策略之前,Facebook 和 Google 等外部提供程序身份验证不可用。

rest 加密

某些数据库和存储机制允许进行 rest 加密。 rest 加密:

  • 自动加密存储的数据。
  • 无需对访问数据的软件进行配置、编程或其他操作即可进行加密。
  • 最简单且最安全的选项。
  • 允许数据库管理密钥和加密。

例如:

对于不提供内置 rest 加密的数据库,可以使用磁盘加密来提供相同的保护。 例如:

其他资源

  • 项目模板包括扩展点和存根标记,可以将其替换为 privacy 和 cookie 使用策略。
  • Pages/Privacy.cshtml 页面或 Views/Home/Privacy.cshtml 视图提供页面以详细说明站点的 privacy 策略。

若要在 ASP.NET Core 模板生成的应用中启用与当前 ASP.NET Core 2.2 模板中的默认 cookie 同意功能类似的功能,请执行以下操作:

  • using Microsoft.AspNetCore.Http 添加到 using 指令列表中。

  • CookiePolicyOptions 添加到 Startup.ConfigureServicesUseCookiePolicy 添加到 Startup.Configure

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public IConfiguration Configuration { get; }
    
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential 
                // cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                // requires using Microsoft.AspNetCore.Http;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });
    
            services.AddRazorPages();
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }
    
            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();
    
            app.UseRouting();
    
            app.UseAuthorization();
    
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapRazorPages();
            });
        }
    }
    
  • 将 cookie 同意部分添加到 _Layout.cshtml 文件:

            @*Previous markup removed for brevity*@
        </header>
        <div class="container">
            <partial name="_CookieConsentPartial" />
            <main role="main" class="pb-3">
                @RenderBody()
            </main>
        </div>
    
        <footer class="border-top footer text-muted">
            <div class="container">
                &copy; 2019 - RPCC - <a asp-area="" asp-page="/Privacy">Privacy</a>
            </div>
        </footer>
    
        <script src="~/lib/jquery/dist/jquery.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    
        @RenderSection("Scripts", required: false)
    </body>
    </html>
    
    
  • _CookieConsentPartial.cshtml 文件添加到项目:

    @using Microsoft.AspNetCore.Http.Features
    
    @{
        var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
        var showBanner = !consentFeature?.CanTrack ?? false;
        var cookieString = consentFeature?.CreateConsentCookie();
    }
    
    @if (showBanner)
    {
        <div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
            Use this space to summarize your privacy and cookie use policy. <a asp-page="/Privacy">Learn More</a>.
            <button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
                <span aria-hidden="true">Accept</span>
            </button>
        </div>
        <script>
            (function () {
                var button = document.querySelector("#cookieConsent button[data-cookie-string]");
                button.addEventListener("click", function (event) {
                    document.cookie = button.dataset.cookieString;
                }, false);
            })();
        </script>
    }
    
  • 选择本文的 ASP.NET Core 2.2 版本,了解 cookie 同意功能。

  • 项目模板包括扩展点和存根标记,可以将其替换为 privacy 和 cookie 使用策略。
  • Pages/Privacy.cshtml 页面或 Views/Home/Privacy.cshtml 视图提供页面以详细说明站点的 privacy 策略。

若要启用如在生成了应用的当前 ASP.NET Core 模板中的 ASP.NET Core 2.2 模板中发现的默认 cookie 内容,请将以下突出显示的代码添加到 Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<CookiePolicyOptions>(options =>
{
    // This lambda determines whether user consent for non-essential 
    // cookies is needed for a given request.
    options.CheckConsentNeeded = context => true;

    options.MinimumSameSitePolicy = SameSiteMode.None;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

在前面的代码中,使用的是 CookiePolicyOptionsUseCookiePolicy

  • 将 cookie 同意部分添加到 _Layout.cshtml 文件:

                @*Previous markup removed for brevity*@
        </header>
        <div class="container">
            <partial name="_CookieConsentPartial" />
            <main role="main" class="pb-3">
                @RenderBody()
            </main>
        </div>
    
        <footer class="border-top footer text-muted">
            <div class="container">
                &copy; 2022 - WebGDPR - <a asp-area="" asp-page="/Privacy">Privacy</a>
            </div>
        </footer>
    
        <script src="~/lib/jquery/dist/jquery.min.js"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    
        @await RenderSectionAsync("Scripts", required: false)
    </body>
    </html>
    
  • _CookieConsentPartial.cshtml 文件添加项目:

    @using Microsoft.AspNetCore.Http.Features
    
    @{
        var consentFeature = Context.Features.Get<ITrackingConsentFeature>();
        var showBanner = !consentFeature?.CanTrack ?? false;
        var cookieString = consentFeature?.CreateConsentCookie();
    }
    
    @if (showBanner)
    {
        <div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
            Use this space to summarize your privacy and cookie use policy. <a asp-page="/Privacy">Learn More</a>.
            <button type="button" class="accept-policy close" data-bs-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
                <span aria-hidden="true">Accept</span>
            </button>
        </div>
        <script>
            (function () {
                var button = document.querySelector("#cookieConsent button[data-cookie-string]");
                button.addEventListener("click", function (event) {
                    document.cookie = button.dataset.cookieString;
                }, false);
            })();
        </script>
    }
    
  • 选择本文的 ASP.NET Core 2.2 版本,了解 cookie 同意功能。

rest 加密

某些数据库和存储机制允许进行 rest 加密。 rest 加密:

  • 自动加密存储的数据。
  • 无需对访问数据的软件进行配置、编程或其他操作即可进行加密。
  • 最简单且最安全的选项。
  • 允许数据库管理密钥和加密。

例如:

对于不提供内置 rest 加密的数据库,可以使用磁盘加密来提供相同的保护。 例如:

其他资源