隐私

隐私

您是否正在编写一个处理个人数据(例如姓名、地址和其他可用于识别个人身份的信息)的插件?您需要妥善保管这些数据并保护用户和访问者的隐私。

什么是隐私?

WordPress.org 在欧洲通用数据保护条例出台之前进行了多项改进。这项工作启动后,我们将隐私作为核心 trac 开发的永久重点,这将使我们能够在特定立法之外继续增强隐私和数据保护。

但什么样的问题可能属于“隐私”的定义,我们如何定义它呢?尽管隐私要求在不同国家、文化和法律体系之间存在很大差异,但有一些适用于任何情况的一般原则:

(来源:ISO 29100/隐私框架标准

虽然并非所有这些原则都适用于所有情况和用途,但在开发过程中使用它们可以帮助确保用户信任。

隐私设计

其中许多原则都在“隐私设计”框架中得到体现,该框架指出:

您的插件值得深思的地方

为了帮助您的插件做好准备,我们建议您针对您制作的每个插件检查以下问题列表:

  1. 您的插件如何处理个人数据?使用 wp_add_privacy_policy_content(链接)向您的用户披露以下任何内容:
    • 该插件是否与第三方共享个人数据(例如外部 API/服务器)。如果是,它与哪些第三方共享哪些数据?他们是否有已发布的隐私政策(您可以提供链接)?
    • 该插件是否收集个人数据?如果是,什么数据以及存储在哪里?考虑用户数据/元、选项、帖子元、自定义表、文件等地方。
    • 该插件是否使用其他人收集的个人数据?如果是的话,什么数据?该插件是否将个人数据传递给 SDK?该 SDK 对数据有何作用?
    • 该插件是否直接或间接收集遥测数据?例如,在每次安装时从第三方源加载图像可以间接记录和跟踪所有插件安装的使用数据。
    • 该插件是否将 Javascript 入队、跟踪像素或嵌入来自第三方的 iframe(第三方 JS、跟踪像素和 iframe 可以收集访问者的数据/操作、留下 cookie 等)?
    • 该插件是否在浏览器中存储内容?如果是这样,在哪里以及什么?考虑 cookie、本地存储等。
  2. 如果您的插件收集个人数据......
    • 它提供个人数据导出器吗?
    • 它是否提供个人数据擦除回调?
    • 该插件出于什么原因(如果有)拒绝删除个人数据?(例如订单尚未完成等)——这些也应该披露。
  3. 该插件是否使用错误日志记录?如果可能的话,它是否会避免记录个人数据?您可以使用 wp_privacy_anonymize_data 之类的东西来最大程度地减少记录的个人数据吗?日志条目保留多长时间?谁有权访问它们?
  4. 在 wp-admin 中,访问/查看个人数据需要什么角色/能力?它们足够了吗?
  5. 该插件会在网站前端暴露哪些个人数据?它是否向登录和注销的用户显示?应该是?
  6. 该插件会在 REST API 端点中公开哪些个人数据?它是否向登录和注销的用户显示?需要什么角色/能力才能看到​​它?那些合适吗?
  7. 该插件是否正确删除/清理数据,特别是个人数据:
    • 卸载插件期间?
    • 当相关项目被删除时(例如,从帖子元数据或另一个表中的任何帖子引用行)?
    • 当用户被删除时(例如,从引用表中的行的任何用户中)?
  8. 该插件是否提供控件来减少所需的个人数据量?
  9. 插件是否仅在 SDK 或 API 需要时才与 SDK 或 API 共享个人数据,还是插件也共享可选的个人数据?
  10. 当还安装某些其他插件时,此插件收集或共享的个人数据量是否会发生变化?

外部资源

建议网站隐私政策的文本

每个收集、使用或存储用户数据,或将其传递给外部来源或第三方的插件,都应将一段建议文本添加到隐私政策邮箱中。这最好用 来完成 wp_add_privacy_policy_content( $plugin_name, $policy_text )。这将允许站点管理员将该信息提取到其站点的隐私策略中。

为了使用户更简单,文本应解决默认隐私政策中提供的问题:

虽然并非所有这些问题都适用于所有插件,但我们建议您注意有关数据共享的部分。

代码示例

笔记:建议在 admin_init 操作期间调用 wp_add_privacy_policy_content。在操作挂钩之外调用它可能会导致问题,有关详细信息,请参阅票证#44142。

笔记:可以通过使用专门的.privacy-policy-tutorialCSS 类来提供补充信息。复制该部分内容时,应用了此 CSS 类的 HTML 元素中包含的任何内容都将从剪贴板中省略。


/**
 * Adds a privacy policy statement.
 */
function wporg_add_privacy_policy_content() {
	if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
		return;
	}
	$content = '<p class="privacy-policy-tutorial">' . __( 'Some introductory content for the suggested text.', 'text-domain' ) . '</p>'
			. '<strong class="privacy-policy-tutorial">' . __( 'Suggested Text:', 'my_plugin_textdomain' ) . '</strong> '
			. sprintf(
				__( 'When you leave a comment on this site, we send your name, email address, IP address and comment text to example.com. Example.com does not retain your personal data. The example.com privacy policy is <a href="%1$s" target="_blank">here</a>.', 'text-domain' ),
				'https://example.com/privacy-policy'
			);
	wp_add_privacy_policy_content( 'Example Plugin', wp_kses_post( wpautop( $content, false ) ) );
}

add_action( 'admin_init', 'wporg_add_privacy_policy_content' );

个人数据导出

将个人数据导出器添加到您的插件中

在 WordPress 4.9.6 中,添加了新工具,以便更轻松地遵守欧盟《通用数据保护条例》(简称 GDPR)等法律。添加的工具之一是个人数据导出工具,它支持将给定用户的所有个人数据导出到 ZIP 文件中。除了存储在 WordPress 评论等内容中的个人数据之外,插件还可以连接导出器功能来导出他们收集的个人数据,无论是像 postmeta 还是全新的自定义帖子类型 (CPT)。

所有导出的“关键”是用户的电子邮件地址——选择它是因为它支持导出正式注册用户和未注册用户(例如,注销的评论者)的个人数据。

但是,由于组装个人数据导出可能是一个密集的过程,并且可能包含敏感数据,因此我们不想只生成它并通过电子邮件将其发送给请求者而不确认请求,因此面向管理员的用户界面会启动所有请求让管理员输入提出请求的用户名或电子邮件地址,然后发送一个链接以单击以确认其请求。

确认请求后,管理员可以为用户生成并下载或直接通过电子邮件发送个人数据导出 ZIP 文件,或者在需要时进行导出。在用户收到的 ZIP 文件中,他们会找到一个“迷你网站”,其中包含索引 HTML 页面,其中包含按组组织的个人数据(例如评论组等)。

无论管理员下载个人数据导出 ZIP 文件还是直接将其发送给请求者,个人数据导出的组装方式都是相同的 - 并依赖挂钩“导出器”回调来完成收集所有导出数据的肮脏工作。当管理员单击下载或电子邮件链接时,AJAX 循环就会开始,一次一个地迭代系统中注册的所有导出器。除了内置于核心中的导出器之外,插件还可以注册自己的导出器回调。

导出器回调接口设计得尽可能简单。导出器回调接收我们正在使用的电子邮件地址和页面参数。page 参数(从 1 开始)用于避免插件尝试一次导出其收集的所有个人数据而可能导致超时。一个表现良好的插件会限制它尝试删除每页的数据量(例如 100 个帖子、200 个评论等)

导出器回调会回复该电子邮件地址和页面的任何数据以及是否完成。如果导出器回调报告未完成,则将再次调用它(在单独的请求中),页面参数递增 1。导出器回调应返回用于导出的项目数组。每个项目包含一个
项目所属组的组标识符(例如评论、帖子、订单等)、一个可选的组标签(已翻译)、一个项目标识符(例如 comment-133),然后是一个数组包含要为该项目导出的数据的名称、值对。

值得注意的是,该值可以是媒体路径,在这种情况下,媒体文件的链接将添加到导出中的索引 HTML 页面。

当所有导出器都完成后,WordPress 首先组装一个“索引”HTML 文档,作为导出报告的核心。如果插件报告 WordPress 或其他插件已添加的项目的附加数据,则该项目的所有数据将一起显示。

导出的内容会在服务器上缓存 3 天,然后删除。

一个插件可以注册一个或多个导出器,但大多数插件只需要一个。让我们研究一个假设的插件,它将评论者的位置数据添加到评论中。

首先,我们假设插件已使用“add_comment_meta”使用“latitude”和“longitude”的“meta_key”添加位置数据

该插件需要做的第一件事是创建一个接受电子邮件地址和页面的导出器函数,例如:


/**
 * Export user meta for a user using the supplied email.
 *
 * @param string $email_address   email address to manipulate
 * @param int    $page            pagination
 *
 * @return array
 */
function wporg_export_user_data_by_email( $email_address, $page = 1 ) {
	$number = 500; // Limit us to avoid timing out
	$page   = (int) $page;

	$export_items = array();

	$comments = get_comments(
		array(
			'author_email' => $email_address,
			'number'       => $number,
			'paged'        => $page,
			'order_by'     => 'comment_ID',
			'order'        => 'ASC',
		)
	);

	foreach ( (array) $comments as $comment ) {
		$latitude  = get_comment_meta( $comment->comment_ID, 'latitude', true );
		$longitude = get_comment_meta( $comment->comment_ID, 'longitude', true );

		// Only add location data to the export if it is not empty.
		if ( ! empty( $latitude ) ) {
			// Most item IDs should look like postType-postID. If you don't have a post, comment or other ID to work with,
			// use a unique value to avoid having this item's export combined in the final report with other items
			// of the same id.
			$item_id = "comment-{$comment->comment_ID}";

			// Core group IDs include 'comments', 'posts', etc. But you can add your own group IDs as needed
			$group_id = 'comments';

			// Optional group label. Core provides these for core groups. If you define your own group, the first
			// exporter to include a label will be used as the group label in the final exported report.
			$group_label = __( 'Comments', 'text-domain' );

			// Plugins can add as many items in the item data array as they want.
			$data = array(
				array(
					'name'  => __( 'Commenter Latitude', 'text-domain' ),
					'value' => $latitude,
				),
				array(
					'name'  => __( 'Commenter Longitude', 'text-domain' ),
					'value' => $longitude,
				),
			);

			$export_items[] = array(
				'group_id'    => $group_id,
				'group_label' => $group_label,
				'item_id'     => $item_id,
				'data'        => $data,
			);
		}
	}

	// Tell core if we have more comments to work on still.
	$done = count( $comments ) > $number;
	return array(
		'data' => $export_items,
		'done' => $done,
	);
}

插件需要做的下一件事是通过使用“wp_privacy_personal_data_exporters”过滤器过滤导出器数组来注册回调。

注册时,您为导出提供一个友好的名称(以帮助调试 - 这个友好的名称此时不会向任何人显示)和回调,例如


/**
 * Registers all data exporters.
 *
 * @param array $exporters
 *
 * @return mixed
 */
function wporg_register_user_data_exporters( $exporters ) {
	$exporters['my-plugin-slug'] = array(
		'exporter_friendly_name' => __( 'Comment Location Plugin', 'text-domain' ),
		'callback'               => 'my_plugin_exporter',
	);
	return $exporters;
}

add_filter( 'wp_privacy_personal_data_exporters', 'wporg_register_user_data_exporters' );

这就是全部!您的插件现在将为导出提供数据!

个人数据删除

将个人数据擦除器添加到您的插件中

在 WordPress 4.9.6 中,添加了新工具,以便更轻松地遵守欧盟《通用数据保护条例》(简称 GDPR)等法律。添加的工具之一是个人数据删除工具,它支持删除/匿名化特定用户的个人数据。它不会删除注册的用户帐户 - 这仍然是管理员可以选择是否执行的单独步骤。

除了存储在 WordPress 评论等内容中的个人数据之外,插件还可以连接到橡皮擦功能来删除他们收集的个人数据,无论是在 postmeta 之类的内容中,还是在全新的自定义帖子类型 (CPT) 中。

与导出器一样,所有擦除器的“关键”是用户的电子邮件地址 - 选择此地址是因为它支持擦除正式注册用户和未注册用户(例如,注销的评论者)的个人数据。

但是,由于执行个人数据删除是一个破坏性的过程,我们不想在没有确认请求的情况下就这样做,因此面向管理员的用户界面通过让管理员输入提出请求的用户名或电子邮件地址来启动所有请求然后发送一个链接,单击以确认他们的请求。一旦请求得到确认,管理员就可以开始删除用户的个人数据,或者在需要时强制删除。

擦除个人数据导出的方式与个人数据导出器的方式类似,并且依赖挂钩“擦除器”回调来完成擦除数据的肮脏工作。当管理员单击“删除个人数据”链接时,AJAX 循环就会开始,一次一个地迭代系统中注册的所有橡皮擦。除了核心内置的橡皮擦之外,插件还可以注册自己的橡皮擦回调。

橡皮擦回调接口设计得尽可能简单。橡皮擦回调接收我们正在使用的电子邮件地址以及页面参数。page 参数(从 1 开始)用于避免插件尝试一次性删除其收集的所有个人数据而可能导致超时。一个表现良好的插件会限制它尝试删除每页的数据量(例如 100 个帖子、200 个评论等)

橡皮擦回调会回复是否删除包含个人数据的项目、是否保留任何包含个人数据的项目、向管理员呈现的一系列消息(解释保留项目的原因)以及是否完成。如果橡皮擦回调报告尚未完成,则会再次调用它(在单独的请求中),并且页面参数递增 1。

当所有导出程序完成后,管理用户界面将更新,以显示找到的所有个人数据是否已删除,以及解释为何保留个人数据的任何消息。

让我们研究一个假设的插件,它将评论者位置数据添加到评论中。假设该插件使用ys of和add_comment_meta添加位置数据meta_kelatitudelongitude

该插件需要做的第一件事是创建一个接受电子邮件地址和页面的橡皮擦函数,例如:


/**
 * Removes any stored location data from a user's comment meta for the supplied email address.
 *
 * @param string $email_address   email address to manipulate
 * @param int    $page            pagination
 *
 * @return array
 */
function wporg_remove_location_meta_from_comments_for_email( $email_address, $page = 1 ) {
	$number = 500; // Limit us to avoid timing out
	$page   = (int) $page;

	$comments = get_comments(
		array(
			'author_email' => $email_address,
			'number'       => $number,
			'paged'        => $page,
			'order_by'     => 'comment_ID',
			'order'        => 'ASC',
		)
	);

	$items_removed = false;

	foreach ( (array) $comments as $comment ) {
		$latitude  = get_comment_meta( $comment->comment_ID, 'latitude', true );
		$longitude = get_comment_meta( $comment->comment_ID, 'longitude', true );

		if ( ! empty( $latitude ) ) {
			delete_comment_meta( $comment->comment_ID, 'latitude' );
			$items_removed = true;
		}

		if ( ! empty( $longitude ) ) {
			delete_comment_meta( $comment->comment_ID, 'longitude' );
			$items_removed = true;
		}
	}

	// Tell core if we have more comments to work on still
	$done = count( $comments ) < $number;
	return array(
		'items_removed'  => $items_removed,
		'items_retained' => false, // always false in this example
		'messages'       => array(), // no messages in this example
		'done'           => $done,
	);
}

插件需要做的下一件事是通过使用“wp_privacy_personal_data_erasers”过滤器过滤橡皮擦数组来注册回调

注册时,您为橡皮擦提供一个友好的名称(以帮助调试 - 这个友好的名称此时不会向任何人显示)
和回调,例如


/**
 * Registers all data erasers.
 *
 * @param array $exporters
 *
 * @return mixed
 */
function wporg_register_privacy_erasers( $erasers ) {
	$erasers['my-plugin-slug'] = array(
		'eraser_friendly_name' => __( 'Comment Location Plugin', 'text-domain' ),
		'callback'             => 'wporg_remove_location_meta_from_comments_for_email',
	);
	return $erasers;
}

add_filter( 'wp_privacy_personal_data_erasers', 'wporg_register_privacy_erasers' );

这就是全部!您的插件现在将清理其个人数据!

高级主题

隐私相关选项、挂钩和功能

隐私工具最初是在 WordPress 4.9.6 中引入的。这些工具旨在允许(并鼓励)开发人员将它们用作隐私导出器、隐私擦除器和隐私政策指南的一部分。

从那时起,引入了几个更新的挂钩来扩展可用功能。这些挂钩允许开发人员在导出和删除请求中包含额外的个人数据,并引入隐私政策指南的建议内容。

除了控制这些工具的能力之外,还有几个用于请求和确认电子邮件的新过滤器,可以对这些通知进行更细粒度的控制。

选项

wp_page_for_privacy_policy– 包含站点隐私页面的页面 ID

行动

user_request_action_confirmed– 当用户确认隐私请求时触发

wp_privacy_delete_old_export_files– 用于从个人数据导出文件夹中删除旧导出的预定操作

wp_privacy_personal_data_erased– 最后一个橡皮擦的最后一页完成后触发

wp_privacy_personal_data_export_file– 用于创建个人数据导出文件作为导出流程的一部分

wp_privacy_personal_data_export_file_created– 创建个人数据导出文件后触发

过滤器

privacy_policy_url– 过滤隐私政策页面的 URL。

the_privacy_policy_link– 过滤隐私政策页面链接 HTML。

wp_get_default_privacy_policy_content– 过滤隐私政策指南中建议包含的默认内容。

user_request_action_confirmed_message– 允许修改向用户显示的操作确认消息

user_request_action_description– 过滤用户操作描述。

user_request_action_email_content– 过滤尝试帐户操作时发送的电子邮件文本。

user_request_action_email_headers– 过滤尝试帐户操作时发送的电子邮件的标头。

user_request_action_email_subject– 过滤尝试帐户操作时发送的电子邮件的主题。

user_request_confirmed_email_content– 过滤用户请求确认电子邮件的正文。

user_request_confirmed_email_headers– 过滤用户请求确认电子邮件的标头。

user_request_confirmed_email_subject– 过滤用户请求确认电子邮件的主题。

user_request_confirmed_email_to– 过滤数据请求确认通知的接收者。

user_request_key_expiration– 过滤用户请求的确认密钥的过期时间。

wp_privacy_additional_user_profile_data– 过滤器以扩展隐私导出器的用户配置文件数据。

wp_privacy_export_expiration– 控制允许获取多长时间的导出文件,默认为 3 天

wp_privacy_personal_data_email_content– 允许修改发送给用户的电子邮件及其个人数据导出文件链接

wp_privacy_personal_data_email_headers– 过滤与个人数据导出文件一起发送的电子邮件的标题。

wp_privacy_personal_data_email_subject– 过滤导出请求完成时发送的电子邮件的主题。

wp_privacy_personal_data_email_to– 过滤个人数据导出电子邮件通知的收件人。

笔记:wp_privacy_personal_data_email_to应非常谨慎使用,以避免将数据导出链接发送到错误的收件人电子邮件地址。

wp_privacy_personal_data_erasers– 支持核心和插件个人数据擦除器的注册

wp_privacy_personal_data_erasure_page– 过滤一页个人数据擦除数据。允许除 Ajax 之外的目的地使用擦除响应。

wp_privacy_personal_data_exporters– 支持核心和插件个人数据导出器的注册

wp_privacy_personal_data_export_page– 过滤个人数据导出者数据的页面。用于构建导出报告。允许导出响应由 Ajax 之外的目标使用。

wp_privacy_anonymize_data– 过滤每种类型的匿名数据。

wp_privacy_exports_dir– 过滤用于存储个人数据导出文件的目录。

wp_privacy_exports_url– 过滤用于存储个人数据导出文件的目录的 URL。

user_confirmed_action_email_content– 过滤用户请求确认电子邮件的正文。确认用户请求后,电子邮件将发送给管理员。

user_erasure_fulfillment_email_to– 过滤数据删除完成通知的收件人。

user_erasure_complete_email_subject– 过滤删除请求完成后发送的电子邮件的主题。

user_confirmed_action_email_content– 过滤数据删除完成通知的正文。当管理员满足用户的数据删除请求时,将向用户发送电子邮件。

user_erasure_complete_email_headers– 过滤数据擦除完成通知的标头。

能力

对隐私工具的访问由一些新功能控制。默认情况下,管理员(在非多站点安装上)具有这些功能。这些能力是:

erase_others_personal_data– 确定“工具”下是否提供“删除个人数据”子菜单

export_others_personal_data– 确定“工具”下是否提供“导出个人数据”子菜单

manage_privacy_options– 确定“设置”下的“隐私”子菜单是否可用