Shadow IT: Phát hiện ứng dụng SaaS 

Mở Enterprise applications của một tenant SMB bất kỳ, bạn sẽ thường thấy vài chục ứng dụng mà IT chưa từng nghe tên: công cụ thiết kế, quản lý dự án, ký điện tử, ghi chú cuộc họp bằng AI, tiện ích “dọn hộp thư“. Mỗi ứng dụng xuất hiện vì một nhân viên bấm Sign in with Microsoft rồi Accept. Một số được cấp quyền Mail.Read hoặc Files.ReadWrite.All và vẫn giữ quyền đó tới hôm nay, kể cả khi nhân viên đã nghỉ việc.

Giải pháp đầy đủ cho shadow IT là Defender for Cloud Apps (cloud discovery, app governance), có trong Microsoft 365 E5, không có trong Business Premium. Nhưng hai nguồn dữ liệu sẵn có đã đủ để làm phần quan trọng nhất. Entra ID biết mọi ứng dụng đăng nhập bằng tài khoản công ty và quyền của từng ứng dụng. Defender (Advanced Hunting trên máy P2, indicators trên mọi máy) biết máy công ty đang kết nối tới dịch vụ nào.

Bài này mình sẽ hướng dẫn bạn xuất danh sách ứng dụng OAuth kèm quyền, xếp hạng rủi ro, thu hồi ứng dụng nguy hiểm, tìm SaaS không dùng SSO qua Advanced Hunting, và khóa đường consent để danh sách không phình lại.

Điều kiện cần

Yêu cầuChi tiết
LicenseMicrosoft 365 Business Premium (Entra ID P1, Defender for Business); Defender for Endpoint P2 cho phần Advanced Hunting. Defender for Cloud Apps cần E5 hoặc mua riêng
QuyềnCloud Application Administrator (xem, thu hồi app); Security Administrator (indicators); Global Reader để chỉ xem

Bước 1: xuất danh sách ứng dụng OAuth và quyền

Mục đích là có bảng “ứng dụng nào, ai cấp, quyền gì” để đánh giá.

Connect-MgGraph -Scopes "Application.Read.All","Directory.Read.All","AuditLog.Read.All"

# Quyền delegated mà user đã cấp cho từng ứng dụng
$grants = Get-MgOauth2PermissionGrant -All
$report = foreach ($g in $grants) {
    $sp = Get-MgServicePrincipal -ServicePrincipalId $g.ClientId
    [PSCustomObject]@{
        App          = $sp.DisplayName
        Publisher    = $sp.PublisherName
        Verified     = [bool]$sp.VerifiedPublisher.DisplayName
        ConsentType  = $g.ConsentType          # AllPrincipals = admin consent, Principal = 1 user
        User         = if ($g.PrincipalId) { (Get-MgUser -UserId $g.PrincipalId).UserPrincipalName } else { "Tất cả" }
        Scopes       = $g.Scope.Trim()
    }
}
$report | Export-Csv .\oauth-apps.csv -NoTypeInformation -Encoding UTF8
$report | Group-Object App | Sort-Object Count -Descending | Select-Object Count, Name -First 20

Ngoài ra xem trên portal: Entra admin center → Enterprise applications → All applications → lọc Application type: Enterprise Applications, cột Created on.

Bước 2: xếp hạng rủi ro

Mục đích là xử lý 5-10 ứng dụng nguy hiểm nhất trước, không cần duyệt hết.

MứcDấu hiệu trong ScopesVí dụ
CaoMail.ReadWrite, Mail.Send, Files.ReadWrite.All, Sites.ReadWrite.All, Directory.ReadWrite.All, full_access_as_userTiện ích “dọn hộp thư”, công cụ đồng bộ file bên thứ ba
Trung bìnhMail.Read, Files.Read.All, Calendars.ReadWrite, Contacts.ReadGhi chú cuộc họp, CRM nhỏ
Thấpopenid, profile, email, User.Read, offline_accessChỉ dùng để đăng nhập

Cộng thêm điểm rủi ro nếu: publisher không verified, chỉ 1 user dùng và user đó đã nghỉ, app không có đăng nhập trong 90 ngày.

# Lần đăng nhập gần nhất của từng service principal (Entra ID P1)
Get-MgBetaReportServicePrincipalSignInActivity -All |
    Select-Object AppId, @{n='LastSignIn';e={$_.LastSignInActivity.LastSignInDateTime}} |
    Export-Csv .\app-last-signin.csv -NoTypeInformation -Encoding UTF8

Từ thực tế: Ứng dụng mức Cao hay gặp nhất ở SMB không phải phần mềm độc hại, mà là công cụ hợp pháp được dùng thử một lần rồi bỏ: tiện ích chữ ký email, công cụ gửi email hàng loạt, ứng dụng quét danh thiếp. Chúng vẫn giữ Mail.Send của user nhiều năm. Nếu nhà cung cấp đó bị tấn công, kẻ gian có quyền gửi email bằng hộp thư của nhân viên bạn.

Bước 3: thu hồi ứng dụng nguy hiểm

Mục đích là gỡ quyền mà không làm gián đoạn công việc đang dùng thật.

  1. Hỏi user đã cấp quyền: còn dùng không, dùng làm gì
  2. Không dùng nữa: Enterprise applications → [app] → Properties → Enabled for users to sign-in?: No (tắt trước 7 ngày, nếu không ai phàn nàn thì xóa)
  3. Gỡ quyền:
# Gỡ toàn bộ delegated permission grant của một app (lấy ServicePrincipalId từ bước 1)
$spId = "00000000-0000-0000-0000-000000000000"
Get-MgOauth2PermissionGrant -Filter "clientId eq '$spId'" | ForEach-Object {
    Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $_.Id
}
  1. Còn dùng và cần thiết: chuyển sang admin consent với quyền tối thiểu, ghi vào danh sách ứng dụng được duyệt

Bước 4: tìm SaaS không đăng nhập bằng Microsoft

Mục đích là thấy cả dịch vụ nhân viên đăng ký bằng email và mật khẩu riêng, Entra ID không biết tới.

Trên máy dùng MDE P2:

// Top domain bên ngoài được truy cập từ trình duyệt trong 30 ngày, loại trừ Microsoft
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where InitiatingProcessFileName in~ ("msedge.exe", "chrome.exe", "firefox.exe")
| where isnotempty(RemoteUrl)
| extend Domain = tostring(split(RemoteUrl, "/")[0])
| extend RootDomain = strcat(tostring(split(Domain, ".")[-2]), ".", tostring(split(Domain, ".")[-1]))
| where RootDomain !in ("microsoft.com", "office.com", "office.net", "live.com", "windows.net",
                         "microsoftonline.com", "sharepoint.com", "bing.com", "msn.com", "khongkho.com")
| summarize Users = dcount(InitiatingProcessAccountName), Devices = dcount(DeviceName), Connections = count() by RootDomain
| where Users >= 2
| order by Users desc
| take 50

Lưu ý: Query này chỉ thấy 15 máy P2, nhưng đó là máy của ban giám đốc, kế toán, admin, nơi rủi ro dữ liệu cao nhất. Với các máy còn lại, khảo sát trực tiếp các trưởng phòng.

Bước 5: chặn dịch vụ lưu trữ và chuyển file không được duyệt

Mục đích là chặn đường dữ liệu rời công ty qua dịch vụ lưu trữ cá nhân, sau khi đã thống nhất với các phòng.

  1. Defender portal → Settings → Endpoints → Indicators → URLs/Domains → Add item
  2. Thêm các domain lưu trữ, chuyển file không được duyệt với Action: Audit 7 ngày (chỉ ghi log, đo ai đang dùng), sau đó Warn 14 ngày, rồi mới Block
  3. Description: Dùng OneDrive/SharePoint của công ty để chia sẻ file

Kết quả kỳ vọng: mở domain trên máy đã onboard hiện trang cảnh báo.

Bước 6: khóa đường consent và review hằng quý

Mục đích là danh sách không phình lại sau khi đã dọn.

  1. Xác nhận cấu hình bài 1: User consent settings chỉ cho verified publisher, quyền thấp; admin consent workflow bật
  2. Enterprise applications → Consent and permissions → Permission classifications: chỉ phân loại Low cho openid, profile, email, User.Read, offline_access
  3. Đặt lịch chạy lại script bước 1 mỗi quý, so sánh với danh sách được duyệt

Lỗi thường gặp

LỗiNguyên nhânCách sửa
Script chạy rất chậmGọi Get-MgUser cho từng grantCache user vào hashtable, hoặc chạy ngoài giờ
Tắt app làm gián đoạn phòng banKhông hỏi trướcLuôn hỏi user cấp quyền, tắt trước khi xóa
Advanced Hunting nhiều domain rácCDN, quảng cáoThêm điều kiện Users >= 3, lọc bằng mắt
Nhân viên vẫn dùng dịch vụ bị chặn trên điện thoạiIndicator chỉ áp máy onboardApp protection (bài 12), chính sách và đào tạo

Tổng kết

Thành phầnĐã làm
Danh sáchMọi OAuth app, người cấp, quyền, lần đăng nhập cuối
Đánh giáXếp hạng Cao / Trung bình / Thấp
Thu hồiTắt đăng nhập 7 ngày, gỡ permission grant
SaaS ngoài SSOAdvanced Hunting top domain trên máy P2
ChặnIndicator Warn → Block cho lưu trữ file không duyệt
Duy trìPermission classifications, review hằng quý

Tài liệu tham khảo

Bạn tìm được bao nhiêu ứng dụng OAuth trong tenant, và có cái nào làm bạn bất ngờ? Chia sẽ trong comment nhé.