跳过主要内容

Capacitor 隐私屏幕:隐藏应用内容

添加一个 Capacitor 隐私屏幕,用于在应用切换器中隐藏应用内容,并阻止截图,具有每屏幕的控制、配置和平台限制。

文章来源

马丁·多纳迪厄

作者

瓦莱里娅

审阅者

乔丹

编辑

Capacitor 隐私屏幕:隐藏应用内容

一个 Capacitor 隐私屏幕会在用户打开应用切换器时隐藏您的应用内容,且在安卓上阻止截图和屏幕录制。没有它,iOS和安卓会在最近的应用列表中保留您的最后屏幕截图,例如银行余额、医疗记录或一次性 code。 @capgo/capacitor-privacy-screen 添加了一个只需一条调用或一条配置标志即可实现的功能,并允许您保护需要保护的屏幕。

应用切换器暴露的内容

当用户离开应用时,两种系统都会捕捉当前屏幕的图像:

  • iOS 在应用失去活跃状态时,会捕捉一个快照并在应用切换器中显示它,应用重新启动时也会捕捉一个快照。
  • Android 在Recents中显示一个实时预览或缓存预览。

任何人看手机都会看到这个快照。同样,任何人在电话中屏幕共享,或者用户记录屏幕以获取支持票时,也会看到这个快照。截图也会同步到云照片库中,这是敏感数据泄露的地方。

哪些应用需要它

应用类型 可能泄露的内容
银行、金融科技、加密 余额、卡号、IBAN、交易
密码管理器、认证器 密码、TOTP验证码、恢复密钥
健康和医疗 诊断、处方、实验室结果
消息 私人对话
人力资源、工资、法律 工资、合同
约会、私人媒体 照片和匹配

安全审计和渗透测试人员经常发现这些类别缺乏应用切换器保护。OWASP MASVS 包括检查 UI 中敏感数据暴露的检查,审计人员测试的就是这一点。

安装

bun add @capgo/capacitor-privacy-screen
bunx cap sync

该插件支持 Capacitor 8.x 版本。

选项 1:在启动应用时保护整个应用

在 capacitor.config.ts. native 插件在加载时读取此选项,甚至在 JavaScript 运行之前,这样即使是第一个快照也被保护:

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.bank',
  appName: 'Example Bank',
  webDir: 'dist',
  plugins: {
    PrivacyScreen: {
      enabled: true,
      android: {
        dimBackground: false,
        privacyModeOnActivityHidden: 'splash',
      },
      ios: {
        blurEffect: 'dark',
      },
    },
  },
};

export default config;

运行 bunx cap sync after changing the config. The enabled 配置选项仅从 Capacitor 配置文件中读取,不是运行时选项。

在

import { PrivacyScreen } from '@capgo/capacitor-privacy-screen';

export async function enterSensitiveScreen() {
  await PrivacyScreen.enable({
    android: { dimBackground: true },
    ios: { blurEffect: 'light' },
  });
}

export async function leaveSensitiveScreen() {
  await PrivacyScreen.disable();
}

const { enabled } = await PrivacyScreen.isEnabled();

. native 插件在加载时读取此选项,甚至在 JavaScript 运行之前,这样即使是第一个快照也被保护:

router.afterEach(async (to) => {
  if (to.meta.sensitive) {
    await PrivacyScreen.enable();
  } else {
    await PrivacyScreen.disable();
  }
});

运行 NavigationEnd subscription. With React Router, a hook in your layout component works. The important thing is that back navigation, deep links and tab switches go through the same logic, otherwise a sensitive screen can end up unprotected.

选项 2:保护特定屏幕

Android

  • 保护使用 WindowManager.LayoutParams.FLAG_SECURE. 当启用时,截图和屏幕录制被阻止,最近预览被隐藏。
  • dimBackground: true 显示一个模糊的覆盖层在应用切换器中。与 false,插件会显示您的启动画面图像(如果可用),否则会模糊。
  • privacyModeOnActivityHidden 控制当您的活动被其他东西隐藏时显示什么,例如系统生物识别提示: 'none' (默认) 'dim' 或 'splash'.
  • The old preventScreenshots 旧 FLAG_SECURE 选项已被弃用并被忽略。 disable() 始终应用于保护时。要允许在一个屏幕上截图,请在 enable() 前面并在

iOS

  • 当应用程序失去活跃状态时,插件会添加一个覆盖层,以便应用程序switcher快照不会显示您的内容。
  • blurEffect: 'light' 或 'dark' 结合生物识别 'none' 使用原生模糊。
  • While enabled, app content is also placed in a secure rendering layer. Treat iOS screenshot blocking as best effort: Apple does not offer an official API to block screenshots, and behavior can change between iOS versions.

Web

The web implementation only tracks the enabled flag so your code runs everywhere. Browsers cannot hide tab previews or block screenshots.

Web实现仅跟踪启用标志,因此您的__CAPGO_KEEP_0__在任何地方都可以运行。浏览器无法隐藏标签预览或阻止截图。

结合生物识别 privacyModeOnActivityHidden 它会在Android生物识别提示期间保持内容被覆盖。

import { App } from '@capacitor/app';
import { NativeBiometric } from '@capgo/capacitor-native-biometric';

// null until the app has really gone to the background
let backgroundedAt: number | null = null;

App.addListener('appStateChange', async ({ isActive }) => {
  if (!isActive) {
    backgroundedAt = Date.now();
    return;
  }
  const away = backgroundedAt === null ? 0 : Date.now() - backgroundedAt;
  backgroundedAt = null;
  if (away > 60_000) {
    await NativeBiometric.verifyIdentity({ reason: 'Confirm it is you' });
  }
});

查看 原生生物识别插件 用于设置和错误处理。

官方插件和Capgo插件

Capacitor团队还发布 @capacitor/privacy-screen 与一个非常相似的API(enable, disable, isEnabled 和相同的平台选项)。Capgo插件保留了API并添加:

  • enabled: true Capacitor配置中,所以保护在任何JavaScript运行之前就处于激活状态。官方插件仅从JavaScript中启用。
  • 在启用时,iOS安全渲染内容,文档作为插件行为的一部分,除此之外,还有应用切换器覆盖层。
  • getPluginVersion() 用于诊断。
  • 一个在浏览器预览中运行相同code的Web实现。

如果您已经使用官方插件,切换主要是导入更改。

影响用户体验的细节

  • 不要在没有理由的情况下阻止截图。 用户会截图收据、确认号码和设置。保护敏感数据的屏幕,而不是整个应用程序,除非您的安全政策要求这样做。
  • 告诉用户原因。 如果有人在安卓上尝试截图并得到一个黑色图像,一个短的说明在帮助中心中可以节省支持票。
  • 测试屏幕共享。 在安卓上,视频通话和 casting 将被阻止,而 FLAG_SECURE 检查可访问性。
  • 屏幕阅读器仍然可以使用 ,但测试TalkBack和VoiceOver也很重要。 FLAG_SECURE测试清单

打开一个敏感屏幕,转到应用程序切换器。内容必须在两个平台上都被隐藏。

  1. 测试清单
  2. On Android,尝试截屏和屏幕录制。两者都必须是黑色或被阻止。
  3. 触发生物识别提示并检查背景。
  4. 从敏感屏幕导航回正常屏幕。保护应该在使用每屏模式时关闭。
  5. 杀死并重新启动应用。配置文件中有 enabled: true 在配置文件中,第一个快照必须是保护的。
  6. 在iPad上测试Split View和Slide Over。应用可能在不活跃时仍可见。

故障排除

快照仍在iOS上显示内容。 您在应用已经切换到后台或仅在某些路由时启用保护。使用配置选项进行全应用保护。

Android上的Recents中显示黑屏而不是启动屏幕。 设置 dimBackground: false 并确保您的启动屏幕资源存在,否则插件会回退到模糊效果。

截图仍然在 Android 上有效。 检查 isEnabled()另一个部分的应用可能会调用 disable() 导航

OTA 更新后保护丧失。 配置值是本机的。如果您更改 plugins.PrivacyScreen 在 capacitor.config.ts,需要重新发布一个商店构建。运行时 enable() 和 disable() context Capgo 实时更新.

A 私有屏幕是移动安全清单上的一个项目。另外,请查看安全存储、证书固定和根检测。 Capgo 有以下插件 SSL固定 和 根和越狱检测,并且我们的文章 苹果的 Capacitor 应用程序隐私规则 涵盖了审查方面。完整的插件选项在 隐私屏幕文档.

为Capacitor应用提供实时更新

当Web层面上的bug出现时,通过Capgo将修复推送给用户,而不是等待几天的App Store审批。用户在后台接收更新,而原生代码仍然遵循正常的审批流程。

最新博客

Capgo 为您提供了创建真正专业的移动应用所需的最佳见解。