現(xiàn)U盤禁用守護(hù)進(jìn)程:插拔檢測(cè)、強(qiáng)制禁用與自我?;? alt=)
干這行的人多少都遇到過這種需求公司內(nèi)網(wǎng)機(jī)器要封U盤、機(jī)房設(shè)備只允許指定U盤讀寫、或者就是單純不想讓人隨便往服務(wù)器上插東西。市面上現(xiàn)成的管控軟件不是價(jià)格離譜就是策略太死板弄來弄去還不如自己用C#寫一個(gè)。今天這篇就聊一個(gè)完整的C# U盤禁用守護(hù)進(jìn)程覆蓋U盤插入、拔出、卸載這三個(gè)關(guān)鍵動(dòng)作的處理順帶把服務(wù)化、自我?;钸@類生產(chǎn)環(huán)境必須考慮的問題也講透。適合有WinForm、Windows服務(wù)基礎(chǔ)的C#開發(fā)者參考也適合被臨時(shí)部署一套U盤管控折磨過的運(yùn)維、桌面管理人員。1. 為什么要自己寫一個(gè)U盤管控守護(hù)服務(wù)1.1 現(xiàn)成方案能做到什么程度系統(tǒng)自帶的策略確實(shí)能禁U盤但操作路徑深、效果有限。打開組策略編輯器定位到計(jì)算機(jī)配置-管理模板-系統(tǒng)-可移動(dòng)存儲(chǔ)訪問里面有一堆可移動(dòng)磁盤拒絕讀取權(quán)限之類的選項(xiàng)啟用后普通U盤確實(shí)被擋住了。問題是這個(gè)策略對(duì)已經(jīng)安裝過驅(qū)動(dòng)、或者通過USB讀卡器轉(zhuǎn)接的設(shè)備經(jīng)常漏網(wǎng)而且策略刷新有延遲用戶插上U盤到策略生效之間有幾秒鐘的空窗期。更麻煩的是管理員自己要用U盤的時(shí)候來回改策略太折騰沒法做到按設(shè)備白名單放行。注冊(cè)表禁用USBSTORSYSTEM\CurrentControlSet\Services\USBSTOR的 Start 值改為 4是另一種常見手段但只對(duì)還沒裝驅(qū)動(dòng)的U盤有效已緩存驅(qū)動(dòng)的設(shè)備照樣能識(shí)別。而且改注冊(cè)表需要管理員權(quán)限被安全軟件攔截的概率也不低。所以我自己折騰這套東西的目的很明確把插拔檢測(cè)、設(shè)備禁用、白名單放行、后臺(tái)?;钸@些東西集中到一個(gè)C#守護(hù)進(jìn)程里既能實(shí)時(shí)響應(yīng)插拔動(dòng)作又能按設(shè)備實(shí)例ID精確管控。1.2 守護(hù)進(jìn)程要管的三件事所謂守護(hù)進(jìn)程核心就是三件事盯著、攔截、活著。盯著隨時(shí)知道U盤的插入、拔出、彈出請(qǐng)求。攔截在U盤剛插入還沒生效時(shí)禁用或者在用戶點(diǎn)安全刪除硬件時(shí)阻止卸載。活著進(jìn)程不能被普通用戶隨手kill服務(wù)崩潰了能自動(dòng)拉起開機(jī)自啟不依賴用戶登錄。用C#寫這套東西好處是托管代碼寫起來快WMI、注冊(cè)表、Windows服務(wù)這些基礎(chǔ)設(shè)施調(diào)用方便對(duì)很多做上位機(jī)和桌面軟件的人來說門檻也低。壞處是容易被殺軟盯上后面會(huì)專門聊排坑。2. 插拔檢測(cè)WMI事件監(jiān)聽和DevicChange消息要怎么選2.1 WMI的Win32_VolumeChangeEvent監(jiān)聽要實(shí)時(shí)感知U盤插入和拔出最省事的方法是WMI事件監(jiān)聽。用ManagementEventWatcher訂閱Win32_VolumeChangeEvent當(dāng)系統(tǒng)發(fā)生卷變更事件時(shí)回調(diào)會(huì)觸發(fā)。示例代碼using System.Management; var watcher new ManagementEventWatcher( new WqlEventQuery(SELECT * FROM Win32_VolumeChangeEvent)); watcher.EventArrived (sender, e) { var eventType Convert.ToInt32(e.NewEvent.Properties[EventType].Value); var driveName e.NewEvent.Properties[DriveName].Value?.ToString(); // EventType: 1配置變更, 2設(shè)備到達(dá)(插入), 3設(shè)備拔出, 4彈出請(qǐng)求 switch (eventType) { case 2: Console.WriteLine($[插入] {driveName}); break; case 3: Console.WriteLine($[拔出] {driveName}); break; case 4: Console.WriteLine($[彈出請(qǐng)求] {driveName}); break; } }; watcher.Start(); // 程序退出時(shí)記得 watcher.Stop() 和 watcher.Dispose()這段代碼有一個(gè)必須注意的坑WMI事件的回調(diào)線程和你的主線程不是同一個(gè)如果需要操作UI必須通過Invoke或SynchronizationContext切回UI線程。對(duì)服務(wù)程序來說沒這個(gè)問題但如果你的守護(hù)進(jìn)程是WinForm托盤程序不改的話會(huì)在回調(diào)里直接拋跨線程異常。還有一點(diǎn)Win32_VolumeChangeEvent只對(duì)分配了盤符的卷觸發(fā)。有些U盤量產(chǎn)工具會(huì)把U盤識(shí)別成無盤符的存儲(chǔ)設(shè)備這種情況WMI事件不觸發(fā)需要配合下面的設(shè)備通知。2.2 WM_DEVICECHANGE與設(shè)備級(jí)別的通知如果需要更底層的設(shè)備插拔事件比如U盤還沒分配盤符就立刻感知應(yīng)該在窗口過程中處理WM_DEVICECHANGE消息。WinForm里重寫WndProcprotected override void WndProc(ref Message m) { const int WM_DEVICECHANGE 0x0219; const int DBT_DEVICEARRIVAL 0x8000; // 設(shè)備已插入 const int DBT_DEVICEQUERYREMOVE 0x8001; // 系統(tǒng)詢問能否移除 const int DBT_DEVICEREMOVEPENDING 0x8003; // 移除即將發(fā)生 const int DBT_DEVICEREMOVECOMPLETE 0x8004; // 移除完成 if (m.Msg WM_DEVICECHANGE) { var wParam m.WParam.ToInt32(); switch (wParam) { case DBT_DEVICEARRIVAL: // 設(shè)備剛插入此時(shí)卷可能還未就緒 break; case DBT_DEVICEQUERYREMOVE: // 用戶點(diǎn)了安全刪除硬件或系統(tǒng)準(zhǔn)備彈出設(shè)備 // 這里可以設(shè)置 m.Result (IntPtr)1; 阻止移除 break; case DBT_DEVICEREMOVEPENDING: // 移除已經(jīng)無法阻止只能記錄 break; case DBT_DEVICEREMOVECOMPLETE: break; } } base.WndProc(ref m); }WM_DEVICECHANGE是發(fā)送到窗口消息隊(duì)列的所以必須有窗口句柄。如果你把守護(hù)進(jìn)程寫成Windows服務(wù)Session 0里沒有可見窗口就得靠隱藏窗口或者直接用WMI方案。我實(shí)際項(xiàng)目里的做法是WMI負(fù)責(zé)卷級(jí)別插拔感知WM_DEVICECHANGE負(fù)責(zé)攔截安全刪除硬件的彈出請(qǐng)求兩者配合才算完整。2.3 為什么不能只靠定時(shí)掃描有人會(huì)想何必搞事件監(jiān)聽直接寫個(gè)Timer每秒鐘掃一遍盤符列表對(duì)比上次狀態(tài)不就知道插拔了這種做法在低要求環(huán)境能跑但有兩個(gè)硬傷。第一是響應(yīng)延遲。定時(shí)掃描最快也得幾百毫秒一輪U盤插上去到被禁用之間的時(shí)間窗口可能被利用——有人就是趁著這零點(diǎn)幾秒把文件拷走的。事件驅(qū)動(dòng)是系統(tǒng)主動(dòng)通知延遲在毫秒級(jí)。第二是攔不住彈出請(qǐng)求。安全刪除硬件這個(gè)動(dòng)作不會(huì)有盤符變化只是系統(tǒng)發(fā)一個(gè)DBT_DEVICEQUERYREMOVE詢問。這種操作只有處理設(shè)備消息才能攔截輪詢盤符列表根本感知不到。如果你的需求里有禁止用戶隨意卸載U盤這一條定時(shí)掃描方案可以直接放棄了。3. 禁用的幾種手段和組合拳3.1 注冊(cè)表USBSTOR開關(guān)最經(jīng)典的禁用方式是修改USBSTOR服務(wù)的啟動(dòng)類型using Microsoft.Win32; private static void SetUsbStorageDisabled(bool disabled) { const string path SYSTEM\CurrentControlSet\Services\USBSTOR; using (var key Registry.LocalMachine.OpenSubKey(path, writable: true)) { if (key null) return; // 4 禁用, 3 手動(dòng)(默認(rèn)) key.SetValue(Start, disabled ? 4 : 3, RegistryValueKind.DWord); } }注意這個(gè)操作需要管理員權(quán)限而且修改后不會(huì)立刻對(duì)已插入的設(shè)備生效。注冊(cè)表里的 Start 值只影響下一次插入時(shí)是否加載驅(qū)動(dòng)。也就是說U盤已經(jīng)插在上面時(shí)改這個(gè)值不會(huì)把已經(jīng)加載的設(shè)備頂?shù)簟O胍⒓瓷У门浜显O(shè)備管理器的禁用設(shè)備操作見下一節(jié)。還有個(gè)特殊情況USBSTOR鍵可能不存在通常是因?yàn)橄到y(tǒng)里從沒插過U盤。鍵不存在時(shí)不能直接創(chuàng)建并寫 Start 值正確做法是先插一次U盤讓系統(tǒng)生成鍵或者用pnputil加載默認(rèn)驅(qū)動(dòng)否則注冊(cè)表寫入會(huì)失敗。我遇到過部署腳本在全新系統(tǒng)上報(bào)找不到USBSTOR的坑后來統(tǒng)一改成先判斷鍵是否存在不存在就在日志里提示先去設(shè)備管理器刷新一次。3.2 設(shè)備實(shí)例級(jí)別的啟用與禁用如果要在U盤已經(jīng)插入的情況下強(qiáng)制禁用可以通過pnputil命令行工具按設(shè)備實(shí)例ID來操作:: 禁用指定設(shè)備 pnputil /disable-device USBSTOR\DISKVEN_GENERICPROD_USB_MS_STORAGEREV_0000\1234567890 :: 啟用指定設(shè)備 pnputil /enable-device USBSTOR\DISKVEN_GENERICPROD_USB_MS_STORAGEREV_0000\1234567890 :: 枚舉當(dāng)前所有U盤設(shè)備 pnputil /enum-devices /class USBSTORC#里可以這樣調(diào)用using System.Diagnostics; private static void RunPnputil(string arguments) { var psi new ProcessStartInfo(pnputil.exe, arguments) { UseShellExecute false, CreateNoWindow true, WindowStyle ProcessWindowStyle.Hidden }; using (var proc Process.Start(psi)) { proc?.WaitForExit(10000); } }判斷設(shè)備是不是U盤可以用WMI查詢Win32_DiskDrive的InterfaceType是否為USB或者Win32_PnPEntity的DeviceID是否以USBSTOR\開頭。以DeviceID做白名單匹配更可靠因?yàn)橥粋€(gè)U盤的DeviceID里的序列號(hào)是固定的量產(chǎn)過的除外。組合拳的思路是注冊(cè)表USBSTOR Start4 做全局默認(rèn)禁用白名單設(shè)備在插入瞬間用 pnputil /enable-device 放行。這樣既保證默認(rèn)安全又允許指定U盤使用。3.3 彈出請(qǐng)求的攔截前面提到用戶點(diǎn)安全刪除硬件時(shí)系統(tǒng)發(fā)DBT_DEVICEQUERYREMOVE。要禁止卸載在WndProc里把消息的Result設(shè)為(IntPtr)1case DBT_DEVICEQUERYREMOVE: // 判斷設(shè)備是否在白名單中 if (!IsDeviceAllowed(GetDeviceIdFromMessage(m))) { m.Result (IntPtr)1; // 拒絕移除 return; } break;DBT_DEVICEQUERYREMOVE的lParam里包含一個(gè)DEV_BROADCAST_HDR結(jié)構(gòu)要拿到設(shè)備實(shí)例ID還得解析DEV_BROADCAST_DEVICEINTERFACE或DEV_BROADCAST_HANDLE。用Marshal.PtrToStructure可以解析但代碼量不小。如果想省事可以給受保護(hù)的U盤先打開一個(gè)句柄不給共享刪除權(quán)限這樣系統(tǒng)會(huì)說設(shè)備正在使用中一樣攔得住。這個(gè)辦法比較粗暴但實(shí)現(xiàn)成本極低// 打開設(shè)備句柄并保持不釋放 FileStream fs new FileStream(\\.\E:, FileMode.Open, FileAccess.Read, FileShare.Read);不過這種保留句柄的方式副作用也明顯U盤無法安全彈出且極少數(shù)U盤會(huì)出現(xiàn)掉盤后句柄失效、程序崩潰的情況。按量化的方式用SetupAPI解析設(shè)備路徑更優(yōu)雅但對(duì)很多開發(fā)者來說Marshal解析結(jié)構(gòu)體這件事本身就是個(gè)坎。我的建議是如果項(xiàng)目周期緊先用手動(dòng)解析DBT消息的方案哪怕解析不到DevicePath也能通過盤符反查設(shè)備實(shí)例ID足夠應(yīng)付大多數(shù)場(chǎng)景。4. 守護(hù)進(jìn)程的服務(wù)化與自我?;?.1 Windows服務(wù)承載和普通進(jìn)程怎么選寫U盤守護(hù)進(jìn)程第一版通常是個(gè)WinForm小程序雙擊運(yùn)行、圖標(biāo)在托盤。在開發(fā)機(jī)上自測(cè)沒問題部署到用戶機(jī)器就出幺蛾子——用戶一注銷程序就退了程序崩了沒人點(diǎn)重啟。所以我后來統(tǒng)一改成Windows服務(wù)原因有四個(gè)服務(wù)由services.exe拉起用戶注銷不影響。服務(wù)默認(rèn)運(yùn)行在Session 0普通用戶的任務(wù)管理器里能看到進(jìn)程但沒有權(quán)限結(jié)束。服務(wù)可以設(shè)置Automatic啟動(dòng)類型開機(jī)自動(dòng)運(yùn)行。服務(wù)失敗時(shí)可以通過sc failure設(shè)置重啟動(dòng)作這是系統(tǒng)級(jí)的恢復(fù)機(jī)制。用C#寫Windows服務(wù)的骨架很簡(jiǎn)單public partial class UsbGuardService : ServiceBase { private ManagementEventWatcher _watcher; public UsbGuardService() { InitializeComponent(); ServiceName UsbGuardDaemon; } protected override void OnStart(string[] args) { StartWmiWatcher(); } protected override void OnStop() { _watcher?.Stop(); _watcher?.Dispose(); } }配一個(gè)安裝程序類[RunInstaller(true)] public class ProjectInstaller : Installer { public ProjectInstaller() { var serviceProcessInstaller new ServiceProcessInstaller { Account ServiceAccount.LocalSystem }; var serviceInstaller new ServiceInstaller { ServiceName UsbGuardDaemon, DisplayName USB Guard Daemon, Description USB device control and monitoring service, StartType ServiceStartMode.Automatic }; Installers.Add(serviceProcessInstaller); Installers.Add(serviceInstaller); } }安裝方式sc create UsbGuardDaemon binPath C:\Program Files\UsbGuard\UsbGuardDaemon.exe start auto sc failure UsbGuardDaemon reset 86400 actions restart/5000/restart/10000/restart/30000sc failure這一段特別關(guān)鍵它讓服務(wù)在異常退出后自動(dòng)重啟。但注意被任務(wù)管理器結(jié)束的服務(wù)恢復(fù)機(jī)制會(huì)觸發(fā)如果是被安全軟件直接kill了進(jìn)程這個(gè)機(jī)制通常不生效所以還需要第二層防護(hù)。4.2 雙進(jìn)程互監(jiān)控與看門狗Windows服務(wù)的恢復(fù)機(jī)制只能覆蓋服務(wù)管理器認(rèn)為服務(wù)掛了的情況攔不住進(jìn)程被強(qiáng)制結(jié)束。所以要再加一道保障一個(gè)獨(dú)立的看門狗進(jìn)程定時(shí)檢查服務(wù)進(jìn)程是否存在不存在就重新拉起??撮T狗本身是另一個(gè)普通Windows服務(wù)或計(jì)劃任務(wù)每隔10秒檢查主服務(wù)進(jìn)程private static bool IsServiceProcessRunning(string processName) { return Process.GetProcessesByName(processName).Length 0; } static void WatchLoop() { while (true) { if (!IsServiceProcessRunning(UsbGuardDaemon)) { // 重新拉起服務(wù) Process.Start(sc.exe, start UsbGuardDaemon); } Thread.Sleep(TimeSpan.FromSeconds(10)); } }但雙進(jìn)程也有它自己的問題看門狗被結(jié)束怎么辦所以更完整的架構(gòu)是三個(gè)進(jìn)程互相盯——主服務(wù)、看門狗、輔助工具進(jìn)程。三者的關(guān)系是主服務(wù)崩潰看門狗拉起??撮T狗崩潰主服務(wù)里的自檢邏輯發(fā)現(xiàn)心跳丟失重新啟動(dòng)看門狗。輔助工具進(jìn)程被結(jié)束主服務(wù)重新拉起。實(shí)現(xiàn)方式不一定要三進(jìn)程拉滿小環(huán)境下做主服務(wù)看門狗就夠了但看門狗建議用計(jì)劃任務(wù)跑因?yàn)橛?jì)劃任務(wù)獨(dú)立于登錄會(huì)話比輔助進(jìn)程存活率更高。我實(shí)際部署時(shí)發(fā)現(xiàn)光靠進(jìn)程互相拉不太夠還得在主服務(wù)里加一個(gè)Timer自檢線程定期檢查關(guān)鍵功能是否正常比如WMI watcher是否還活著、注冊(cè)表策略是否被改了。有一次用戶裝了某優(yōu)化軟件把USBSTOR的Start值給改回3了我的進(jìn)程還活著但策略已經(jīng)失效——這種狀態(tài)靠進(jìn)程?;钍前l(fā)現(xiàn)不了的必須每隔幾分鐘主動(dòng)復(fù)核一遍注冊(cè)表策略。4.3 Session 0隔離和權(quán)限的坑服務(wù)運(yùn)行在Session 0這個(gè)設(shè)計(jì)天然隔離了普通用戶的窗口交互。但要注意如果服務(wù)里寫了MessageBox.Show或者試圖彈出托盤圖標(biāo)、窗口用戶是看不到的。所以U盤被禁用時(shí)的用戶提示不能靠服務(wù)直接彈窗得另想辦法用WTSRegisterSessionNotification監(jiān)聽用戶會(huì)話然后跨Session彈窗。或者服務(wù)把事件寫入日志/發(fā)UDP廣播由用戶Session里的托盤程序負(fù)責(zé)展示通知。最省事只寫日志事件不管提示反正用戶發(fā)現(xiàn)U盤用不了自然會(huì)上報(bào)。權(quán)限方面服務(wù)用LocalSystem賬戶運(yùn)行操作注冊(cè)表、調(diào)用pnputil都沒問題。但有幾點(diǎn)要注意64位系統(tǒng)上注冊(cè)表有32位/64位視圖之分用Registry.LocalMachine默認(rèn)操作64位視圖沒問題如果用了RegistryView.Registry32去讀USBSTOR可能讀不到。pnputil在某些精簡(jiǎn)版系統(tǒng)上可能沒有部署前要檢查C:\Windows\System32\pnputil.exe是否存在。如果想用SetupAPI的CM_Disable_DevNode禁用設(shè)備需要管理員令牌服務(wù)模式下默認(rèn)有普通進(jìn)程跑就需要提權(quán)。5. 實(shí)際部署中踩過的坑和排查記錄5.1 注冊(cè)表改了Start4但U盤還能用這個(gè)坑我印象太深了?,F(xiàn)象是USBSTOR的Start值明明改成了4插上U盤照樣識(shí)別、照樣分配盤符。排查鏈路如下先看事件日志發(fā)現(xiàn)每次插入時(shí)驅(qū)動(dòng)加載記錄是USBSTOR成功。這就說明Start4沒生效。再翻注冊(cè)表發(fā)現(xiàn)USBSTOR鍵下有多個(gè)子鍵包括Enum和Parameters。重新讀文檔后意識(shí)到Start是USBSTOR服務(wù)的啟動(dòng)類型U盤設(shè)備已經(jīng)被系統(tǒng)緩存過之后驅(qū)動(dòng)文件已經(jīng)加載到內(nèi)存光改Start不夠必須配合pnputil /restart-device或重啟系統(tǒng)。另外有些機(jī)器插的是USB 3.0口走的驅(qū)動(dòng)可能不是USBSTOR而是USBXHCI棧下面的UASP驅(qū)動(dòng)UASPStor.sys需要把UASPStor也一起處理。解決方案是把這兩個(gè)服務(wù)都改掉var services new[] { SYSTEM\CurrentControlSet\Services\USBSTOR, SYSTEM\CurrentControlSet\Services\UASPStor };5.2 WMI事件偶發(fā)丟失Win32_VolumeChangeEvent在實(shí)際運(yùn)行中不是100%可靠壓力測(cè)試時(shí)發(fā)現(xiàn)拔出事件偶爾不觸發(fā)。原因多半是WMI倉(cāng)庫(kù)性能問題或者事件訂閱被回收。解決思路在ManagementEventWatcher的Stopped事件里重新訂閱。定期檢查watcher狀態(tài)。用WM_DEVICECHANGE兜底兩邊的事件都收到后做去重。我在代碼里加了一個(gè)簡(jiǎn)單的去重邏輯以盤符設(shè)備實(shí)例ID為key記錄最近一次事件時(shí)間10秒內(nèi)同一設(shè)備的事件只處理一次。這既避免重復(fù)處理又不影響對(duì)快速插拔的響應(yīng)。5.3 殺軟和繞過問題C#寫的服務(wù)編譯出來自帶.NET運(yùn)行時(shí)很多殺軟會(huì)掃描并提示可疑程序——尤其是當(dāng)你調(diào)用pnputil禁用設(shè)備、寫注冊(cè)表自啟動(dòng)這類行為時(shí)。我處理的辦法是給程序加上強(qiáng)名稱簽名必要時(shí)做一下EV代碼簽名能顯著降低誤報(bào)率。避免使用容易被標(biāo)記的混淆器。部署時(shí)先加白名單再放量。不要用Process.Start(cmd.exe, /c ...)這種明顯被監(jiān)控的調(diào)用鏈直接調(diào)用ProcessStartInfo指定pnputil.exe相對(duì)更安全。繞過的問題也提一嘴。聰明的用戶知道禁用U盤靠的是USBSTOR注冊(cè)表他會(huì)自己把它改回來。所以守護(hù)進(jìn)程要定時(shí)檢查Start值是否被篡改發(fā)現(xiàn)異常立即改回去并記日志。這屬于防君子不防小人但對(duì)絕大多數(shù)辦公環(huán)境來說已經(jīng)夠了。真要防有管理員權(quán)限的惡意用戶那就得上驅(qū)動(dòng)過濾或EDR級(jí)別的方案不是純靠C#用戶態(tài)程序能完全解決的。5.4 部署與回滾策略上生產(chǎn)之前一定要做好回滾方案。我們的做法是守護(hù)進(jìn)程不做永久的卸載阻斷而是帶一個(gè)維護(hù)模式開關(guān)。在配置文件里加一個(gè)MaintenanceMode選項(xiàng)管理員把U盤插入并按下組合鍵后守護(hù)進(jìn)程進(jìn)入臨時(shí)放行狀態(tài)放行窗口默認(rèn)5分鐘時(shí)間到自動(dòng)恢復(fù)管控。維護(hù)模式的開啟方式不能寫在日志里不然誰(shuí)都知道了?;貪L就是簡(jiǎn)單地停服務(wù)、刪注冊(cè)表改過的值、把pnputil /disable-device的設(shè)備重新enable。我已經(jīng)把部署腳本和回滾腳本都寫成PowerShell部署時(shí)自動(dòng)化執(zhí)行回滾也一鍵完成。對(duì)桌面環(huán)境的批量管控來說回滾能力比部署能力更重要——出了問題收不住比一開始沒管控更麻煩。寫在最后的幾個(gè)經(jīng)驗(yàn)這套守護(hù)進(jìn)程我從第一版WinForm托盤程序踩到現(xiàn)在服務(wù)看門狗架構(gòu)最大的體會(huì)是U盤管控的價(jià)值在策略的完整性而不在技術(shù)的高深。檢測(cè)插拔的方式再多策略本身有漏洞照樣白搭。比如只禁了USBSTOR卻沒禁讀卡器、只攔了彈出卻放過網(wǎng)絡(luò)共享都是實(shí)際項(xiàng)目中容易漏掉的口子。另一個(gè)經(jīng)驗(yàn)是做好日志審計(jì)。每次插入、拔出、禁用、放行都往Windows事件日志里寫一條結(jié)構(gòu)化記錄字段里帶上設(shè)備實(shí)例ID和盤符。出了任何問題看日志就能復(fù)盤整個(gè)鏈路省去大量扯皮時(shí)間。最后別貪多。U盤管控只是安全體系里的一小環(huán)如果你已經(jīng)在用終端管理軟件EDR、準(zhǔn)入客戶端先看看它有沒有現(xiàn)成的設(shè)備控制模塊能復(fù)用就別重復(fù)造輪子。只有現(xiàn)成方案滿足不了特殊需求時(shí)才值得自己寫守護(hù)進(jìn)程。真寫起來保持事件驅(qū)動(dòng)檢測(cè) 組合策略禁用 雙進(jìn)程?;? 審計(jì)日志這個(gè)骨架整個(gè)系統(tǒng)的穩(wěn)定性和可維護(hù)性都會(huì)有保障。