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ầu | Chi tiết |
|---|---|
| License | Microsoft 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ền | Cloud 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ức | Dấu hiệu trong Scopes | Ví dụ |
|---|---|---|
| Cao | Mail.ReadWrite, Mail.Send, Files.ReadWrite.All, Sites.ReadWrite.All, Directory.ReadWrite.All, full_access_as_user | Tiện ích “dọn hộp thư”, công cụ đồng bộ file bên thứ ba |
| Trung bình | Mail.Read, Files.Read.All, Calendars.ReadWrite, Contacts.Read | Ghi chú cuộc họp, CRM nhỏ |
| Thấp | openid, profile, email, User.Read, offline_access | Chỉ 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.Sendcủ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.
- Hỏi user đã cấp quyền: còn dùng không, dùng làm gì
- 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)
- 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
}
- 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.
- Defender portal → Settings → Endpoints → Indicators → URLs/Domains → Add item
- 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
- 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.
- 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
- Enterprise applications → Consent and permissions → Permission classifications: chỉ phân loại Low cho
openid,profile,email,User.Read,offline_access - Đặ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ỗi | Nguyên nhân | Cách sửa |
|---|---|---|
| Script chạy rất chậm | Gọi Get-MgUser cho từng grant | Cache user vào hashtable, hoặc chạy ngoài giờ |
| Tắt app làm gián đoạn phòng ban | Không hỏi trước | Luôn hỏi user cấp quyền, tắt trước khi xóa |
| Advanced Hunting nhiều domain rác | CDN, quảng cáo | Thê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ại | Indicator chỉ áp máy onboard | App protection (bài 12), chính sách và đào tạo |
Tổng kết
| Thành phần | Đã làm |
|---|---|
| Danh sách | Mọ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ồi | Tắt đăng nhập 7 ngày, gỡ permission grant |
| SaaS ngoài SSO | Advanced Hunting top domain trên máy P2 |
| Chặn | Indicator 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
- Review permissions granted to enterprise applications
- Configure permission classifications
- Detect and remediate illicit consent grants
- Create indicators for IPs and URLs/domains
- Microsoft Defender for Cloud Apps overview (khi nâng cấp)
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é.
