写点什么

移动端防截屏录屏技术在百度账户系统实践

作者:百度Geek说
  • 2023-12-26
    上海
  • 本文字数:3461 字

    阅读完需:约 11 分钟

移动端防截屏录屏技术在百度账户系统实践

作者 | Seven


导读

在移动端应用的开发过程中,保护用户隐私和应用内敏感信息安全是一个不可忽视的课题。随着诈骗手段的升级,“共享屏幕”被诈骗分子频频使用,因为密码被泄露而导致受害者财物受损的事情层出不穷。只要开启了“共享屏幕”--本质上是一种录屏,密码、验证码等重要信息就会有被泄露的可能。防止截屏和录屏成为了一个重要的安全措施,特别是对于金融、医疗、企业和高安全要求的应用。本文将介绍一些在 iOS 和 Android 平台上实现防截屏和录屏的常见策略和方法,以及在百度账户系统上的实践。


全文 4431 字,预计阅读时间 12 分钟。

01 技术研究

1.1 Android 平台防截屏策略

Android 平台提供了一个更直接的方式来防止应用内容被截屏或录屏。Google 自 Android 4.2(API level 17)引入 FLAG_SECURE,用于将窗口内容标记为安全,禁止在屏幕截图中和非安全的显示器被输出。


/** Window flag: treat the content of the window as secure, preventing * it from appearing in screenshots or from being viewed on non-secure * displays. * * <p>See {@link android.view.Display#FLAG_SECURE} for more details about * secure surfaces and secure displays. */public static final int FLAG_SECURE             = 0x00002000;
复制代码


可以在 Activity 中,通过 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE) 来设置。当截屏的时候,系统会弹出一个 Toast 提示“禁止屏幕抓取”;当录屏的时候,当前设备显示正常且能正常操作,看似能够正常录制,但是保存后的视频,都是一片黑色,并没有 APP 的相关界面。

探究:FLAG_SECURE 是如何产生作用的

在 Android 图形系统上,一个 Activity 对应创建一个 Surface,每个 Surface 对应 SurfaceFlinger 中的一个 Layer。SurfaceFlinger 负责管理、合成所有图层,最终显示在屏幕上。


我们通过 Android 的 源码 SurfaceFlinger.cpp 和 Layer.cpp 中,可以看到,activity 中设置 FLAG_SECURE 后,显示的 Surface 都是属于 SECURE 状态,会阻止屏幕内容被捕获。


// Call this before holding mStateLock to avoid any deadlocking.bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();{       ...    if (!canCaptureBlackoutContent &&        parent->getDrawingState().flags & layer_state_t::eLayerSecure) {        ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");        return PERMISSION_DENIED;    }    ...}
复制代码

1.2 iOS 平台的防截屏录屏方案

在 iOS 平台,系统并没有直接提供 API,去防止被截屏或录屏。在 iOS13 之前,主要是通过监听通知,然后采取一些措施。


在 iOS7 上,当用户进行截屏时,系统会发送一个 UIApplicationUserDidTakeScreenshotNotification 通知。尽管我们不能阻止截屏的发生,但可以使用这一通知来采取某些措施,如模糊屏幕、显示警告或者销毁显示的敏感内容。


// This notification is posted after the user takes a screenshot (for example by pressing both the home and lock screen buttons)UIKIT_EXTERN NSNotificationName const UIApplicationUserDidTakeScreenshotNotification API_AVAILABLE(ios(7.0));
复制代码


在 iOS11 上,系统新增了 UIScreen 的 API 用以告知应用当前屏幕正在录屏。当 UIScreen.isCaptured 为 true 时,表示当前屏幕正在被录制、镜像或被 Airplay 发送。当录屏状态发生变化时,UIKit 会发送 UIScreenCapturedDidChangeNotification 的通知。


// Object is the UIScreen which changed. [object isCaptured] is the new value of captured property.UIKIT_EXTERN NSNotificationName const UIScreenCapturedDidChangeNotification API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(visionos);
复制代码


在 iOS13 上,UITextField 在设置 secureTextEntry 为 true 时,系统在截屏和录屏时,UITextField 所在的内容会被系统渲染为空白区域。我们可以利用这一特性,把需要视图添加到 UITextField 的子视图上(实际是私有类 UITextLayoutCanvasView)来达到防止截屏和录屏的效果。


具体操作:


1、初始化一个 textField,并获取其子视图 UITextLayoutCanvasView,下面称为 textCanvasView


2、将 textCanvasView 添加到控制器的 view 上,作为防护的底层视图


3、将所需防护的 view 添加 textCanvasView 上


4、通过事件触发,开启或关闭 textField 的 secureTextEntry 属性; 相当于开启或关闭防截屏录屏


其中将防护的 view 添加到 textCanvasView 上,而非添加到 textField 上。因为在密码模式时,这个 view 会在截屏或者录屏时隐藏,同时也可以有效避免触摸事件的冲突。另外,textFiled 的 secureTextEntry 属性没有 iOS 系统版本限制,在低版本系统上也可以设置,只是在 iOS13 及后续版本上,才具备防止截屏和录屏的特性。



另一台手机录制



当前设备录制


在上面视频中红色背景为 textCanvasView,上面添加了需要防护的视图,输入密码后面的 textfield 已开启 secureTextEntry。


可以看到,未开启防护时,截屏和录屏的时候,输入密码的 textfield 内容为空白;开启防护后,textCanvasView 及需要防护的视图均已变为空白。

02 百度账户系统应用实践

在账号登录页,账密登录输入密码时,以及修改密码时需要设置防止截屏或录屏。



因为前端本身无法感知到系统的截屏或录屏事件,且不同的前端页面对于防护的需求也有不同,所以设计由前端来控制防护的开关,在 Android 和 iOS 上分端实现具体的防护功能。

2.1 前端应用实践

当进入到账密登录页面或修改页面时,FE 通过端方法控制打开防护,退出页面时,再由端方法来关闭防护。


双端 SDK 定义的一个端方法名称为 xxx_forbid_record,其中可以通过参数控制是开启或者关闭。


FE 在使用时,可以直接通过 window.location.href 来调用起拼接的端方法字符串 xxx://xxx_forbid_record/{"status":"1"},表示要开启防护要禁止截屏和录屏。双端 SDK 分别在系统的回调中进行拦截,解析端方法,转化为调用对应原生方法。

2.2 Android 实现

在基类 Activity 中初始化 webview 时,去设置防截屏回调,可以通过参数控制 开启或关闭"禁止截屏录屏"功能。


在 FE 调用时,通过拦截端方法,触发“防截屏回调”,进行实际控制。


如果是开启,则给 window 添加 FLAG_SCCURE 标志;如果是关闭,则通过 clearFlags 方法清除 FLAG_SCCURE 标志。


调用端方法开启防护的时候,当前设备实际会提示“该应用不允许屏幕截图”,且不会产生屏幕的实际截图。


录屏时,当前屏幕仍然正常显示和操作,但在录屏生成的视频中,开启防截屏的过程整个屏幕会变成黑色,关闭后防截屏后可以正常显示。



△截屏效果

2.3 iOS 实现

在 百度账号 SDK 中,因为通过 textfield 特性来实现放截屏录屏并不是苹果系统公开的正式 API,从稳定性角度考虑,当前仅是监听了截屏和录屏的通知,通过增加弹窗,提示录屏或截屏风险。


具体实现为:


1、在 webivewController 中,监听系统截屏通知 UIApplicationUserDidTakeScreenshotNotification,如果是 iOS 11 及以上系统,则同时监听录屏通知 UIScreenCapturedDidChangeNotification。


2、区分录屏 或 截屏场景,进行提示。


3、FE 开启或关闭,SDK 中拦截的端方法实现中,设置本地的标识为开启或关闭。


当 FE 开启防截屏录屏后,SDK 拦截端方法后会首先通过 [UIScreen mainScreen].isCaptured 方法,判断当前是否已经录屏。如果是,则直接弹窗提示。


当收到系统截屏或录屏的通知时,sdk 会判断满足以下两个条件都满足才会进行提示:


1)本地的标识为开启


2)当前页面正在展示


当前页面正在展示上通过 view.window 对象存在,以及 控制器的 isViewLoaded 来判断;增加此条件的判断原因是,从登录页可以打开另外一个其他的页面,在该新页面开启截屏或录屏时,登录页虽然没有显示出来,但仍会接收通知。如果新页面是不需要开启防截屏录屏,那么登录页在收到相关通知后,仅通过本地标识来判断,就出弹出不符合预期的弹窗。


在 百度账号 SDK 中,当进入密码登录页时,进行截屏和录屏效果如下。



截屏提示



录屏提示

03 总结

防截屏录屏功能是移动应用安全的一个关键组成部分,特别是对于处理敏感数据的应用而言。iOS 虽然未和 Android 一样有系统提供直接的 API,但上述策略和技术可以显著降低信息泄露的风险。开发者在设计应用时,需要权衡用户体验和安全需求,实施适合自己应用场景的防截屏录屏方案。


——END——


推荐阅读


AI Native工程化:百度App AI互动技术实践


揭开事件循环的神秘面纱


百度搜索展现服务重构:进步与优化


百度APP iOS端包体积50M优化实践(七)编译器优化


百度搜索内容HTAP表格存储系统

发布于: 刚刚阅读数: 5
用户头像

百度Geek说

关注

百度官方技术账号 2021-01-22 加入

关注我们,带你了解更多百度技术干货。

评论

发布
暂无评论
移动端防截屏录屏技术在百度账户系统实践_移动端_百度Geek说_InfoQ写作社区