博客 / 詳情

返回

移動端防截屏錄屏技術在百度賬户系統實踐

作者 | 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表格存儲系統

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.