[資安] 批次修改 Google Workspace 所有用戶的雲端硬碟檢視權限

本篇文章更新時間:2025/01/18
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣新台幣 贊助支持。


Google Workspace 作為企業日常工作工具的解決方案是真的很方便。不過一但企業使用人數到達一定規模後,相關控管的需求隨之而來,真的就不能只是用了而已。

現在人都習慣直接開雲端硬碟的檔案來使用,然後分享給外部人士可能也是直接權限全開,只要有連結就看得到內容。

更不用說同個瀏覽器多個 Google 帳號登入的公私帳號混用情況下,有時候還不是用公司的信箱來處理公務。針對這個問題其實也真的不是使用者的錯,這個算是公司層級需要去顧慮的,也是目前 Chrome 也還有的問題(無法同一個瀏覽器指定哪個帳號為角色預設認定)。

總之,接手這樣可能檔案權限各種混亂的情境,第一件事就是要先想辦法全面性的調整。

Google Workspace Admin 的工具中,在 稽核與調查 中可以調到使用者對 Drive 的各種操作紀錄,第一步可以先從這邊來做觀察,與設定報告通知,在第一時間內有人打開檢視權限都可以收到通知,近一步展開調查。

那原本已經權限大開的檔案怎辦?

Admin 這邊並未開放任何可以管理或觀看到使用者信件或檔案的權限,這部分需要透過整合 App 的 全網域委派 來下手了。

前置準備

  1. 需要有 Google Workspace Admin 總管理員權限的賬號
  2. 需要開通 Google Cloud Platform(GCP) 服務與有權限能進一步開通 Drive API 與 Admin API

Google Cloud Platform 端的設定

先在 GCP 上開一個專案,然後到 API 和服務 中開啟 Google Drive APIAdmin SDK API 這兩個。

再來到 憑證 的分頁,建立一個 服務帳戶,然後把 Workspace 管理者的帳號授予權限。

建立過程中會產生一組接下來程式會需要用到的登錄識別檔案,要好好保存不能外流。

建立完成後回到這個服務帳戶的編輯頁面,看到進階設定處點開,會發現一個 網域層級委派 的區塊,先是複製上方提供的 用戶端 ID 然後點擊查看 Workspace 管理控制台,如下圖:

gcp_screent

Google Workspace Admin 端的設定

接著來到 Admin 端介面,要先到 安全性 > API 控制項 > 全網域委派 這裡,新增 API 用戶端,把剛剛複製的 用戶端 ID 貼上去,並把下方的權限授權給這個用戶:

https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/drive.metadata.readonly
https://www.googleapis.com/auth/admin.directory.user.readonly

到這邊就完成接下來開發上需要的存取控制權限了~

撈取全公司 Workspace 使用者的方法

這邊我使用 PHP 開發,需要先行安裝 [Google API Client](composer require google/apiclient) 的函式庫

composer require google/apiclient

然後取的全部使用者的程式碼片段如下:

setSubject('[email protected]'); // 替代此用戶進行操作
$client->setAuthConfig($service_account_file); // 設定服務帳戶金鑰
$client->addScope([Google\Service\Drive::DRIVE, Google\Service\Drive::DRIVE_METADATA_READONLY, Directory::ADMIN_DIRECTORY_USER_READONLY]);
$directoryService = new Directory($client);

$users_emails = [];
$pageToken = null;

do {
    // 呼叫 API 取得用戶清單
    $response = $directoryService->users->listUsers([
        'domain' => 'domain.com', // 替換成你的 Google Workspace 域名
        'pageToken' => $pageToken,
        'maxResults' => 100, // 請求最多也就 100 筆
        'fields' => 'nextPageToken, users(primaryEmail)',
    ]);

    foreach ($response->getUsers() as $user) {
        $users_emails[] = $user->getPrimaryEmail(); // 主電子郵件
    }
    $pageToken = $response->getNextPageToken(); // 下一頁 Token
} while ($pageToken);

print_r($users_emails);

這邊有兩個有趣的地方:

  1. setSubject 方法是一種「選擇替身」的操作。也就是你當前是用哪個帳號來做哪件事。有些時候是管理員才能做的事,你就要帶入管理員帳號。

  2. pageTokennextPageToken 的關係還要靠 fields 欄位。如果回傳的欄位沒有帶入 nextPageToken,那就算有填寫 pageToken 也撈不到 nextPageToken 值!

調整每位使用者雲端硬碟檔案的檢視權限

上方程式碼片段已經取得到每位公司成員的信箱了,再來就是要透過 setSubject 替身方法,來「站在這位使用者」的角度來調整自己的檔案。

就算是使用總管理員的帳號來帶入,Google 還是不允許這帳號去接觸到沒有分享編輯權限的其他人的檔案。

所以就是需要個別將撈取到的使用者做一輪搜尋檔案+修改檔案權限的操作,程式碼片段如下:

foreach ($users_emails as $index => $owner_email) {
    $account = explode('@', $owner_email);
    $client = new Client();
    $client->setSubject($owner_email); // 代替此用戶進行操作
    $client->setAuthConfig($serviceAccountFile); // 設定服務帳戶金鑰
    $client->addScope([Google\Service\Drive::DRIVE, Google\Service\Drive::DRIVE_METADATA_READONLY]);
    // 初始化 Google Drive 服務
    $drive_service = new Drive($client);
    $files = [];
    $pageToken = null;
    do {
        // 呼叫 Google Drive API 列出檔案
        $results = $drive_service->files->listFiles([
            'q' => "(visibility = 'anyoneWithLink' OR visibility='anyoneCanFind') AND 'me' in owners",
            'fields' => 'nextPageToken, files(id, name, mimeType, owners, permissions, modifiedTime)',
            'pageSize' => 100,
            'pageToken' => $pageToken,
        ]);

        foreach ($results->getFiles() as $file) {

            $permissions = $file->getPermissions();
            $permissionDetails = [];

            if ($permissions) {
                foreach ($permissions as $permission) {
                    $permissionDetails[] = [
                        'type' => $permission->getType(),
                        'role' => $permission->getRole(),
                        'emailAddress' => $permission->getEmailAddress() ?? 'N/A',
                        'domain' => $permission->getDomain() ?? 'N/A',
                    ];
                }
            }
            $mimeType = $file->getMimeType();
            $tmp = explode('.', $mimeType);
            $mimeType_patrs = end($tmp);
            $type = 'file';
            if ($mimeType_patrs == 'folder') {
                $type = 'folder';
            }
            $owner = $file->getOwners()[0]->getEmailAddress();
            $log_file = [
                'name' => $file->getName(),
                'id' => $file->getId(),
                'mimeType' => $mimeType,
                'url' => "https://drive.google.com/{$type}/d/{$file->getId()}",
                'owner' => $owner,
                'modifiedTime' => $file->getModifiedTime(),
                'permissions' => $permissionDetails,
            ];

            if (strpos(strtolower($owner), strtolower($owner_email)) !== false) {
                // 更新檔案權限
                // $permissions = $drive_service->permissions->listPermissions($log_file['id'])->getPermissions();
                foreach ($permissions as $permission) {
                    // 如果是公開共享,將其權限刪除
                    if ($permission->getType() === 'anyone') {
                        try {
                            $drive_service->permissions->delete($log_file['id'], $permission->getId());
                            echo "移除公開權限檔案: " . $log_file['name'] . PHP_EOL;
                            // 加新的權限(僅限組織內查看)
                            $newPermission = new Google\Service\Drive\Permission([
                                'type' => 'domain', // 組織內
                                'role' => 'reader', // 只讀
                                'domain' => 'domain.com', // 替換為組織域名
                            ]);
                            try {
                                $drive_service->permissions->create($log_file['id'], $newPermission, [
                                    'sendNotificationEmail' => false, // 禁止發送通知
                                ]);

                                echo "已更新權限檔案: " . $log_file['name'] . PHP_EOL;
                                $files[] = $log_file;
                                file_put_contents(dirname(__FILE__) . '/' . $account[0] . '_modify.log', $log_file['name'] . '|' . $log_file['url'] . '|' . json_encode($permissions) . PHP_EOL, FILE_APPEND | LOCK_EX);
                            } catch (Exception $e) {
                                echo '更新權限失敗:' . $log_file['name'] . ' / ' . $e->getMessage();
                            }

                        } catch (Exception $e) {
                            echo '移除權限失敗: ' . $log_file['name'] . ' / ' . $e->getMessage();
                        }
                    }
                }
            }
        }
        $pageToken = $results->getNextPageToken();
    } while ($pageToken !== null);
    if (!empty($files)) {
        file_put_contents(dirname(__FILE__) . '/' . $account[0] . '_modify_' . date('Y-m-d-H-i-s', time()) . '.json', json_encode($files), FILE_APPEND | LOCK_EX);
    }
}

上述程式操作的重點是:

  1. 撈取當前檢視權限是「公開」的(不限制類型)
  2. 針對這樣的檔案去移除公開權限,並補上「限定組織內部觀看」。

跑完一圈就能全部調整好權限了~

後記

前言有提到可以先設定好稽核的報告,將日後有設定公開的檔案都發通知給指定管理員。

這個通知基本上就可以在這一波掃描修改後發會功用。確實了解到有哪些人注意到了檔案外連公開失效,又還去改變回公開權限的狀況。

針對資安的操作,這都還很淺,有專門做到這類型檢測資料外流的工具 Forcepoint,不過基本使用單位是用 100 人以上來去估,每個不同規模的公司都有不同要解決的情境呀~

至於關於 Google Workspace Admin 的管理這塊,網路上也能找到一些工具,真是哪裡有困難,哪裡就有商機XD

  • GAM 開源指令版管理工具
  • Patronum 商業版管理工具

Share:

作者: Chun

資訊愛好人士。主張「人人都該為了偷懶而進步」。期許自己成為斜槓到變進度條 100% 的年輕人。[///////////____36%_________]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


文章
Filter
Apply Filters
Mastodon