如何通过ASP.NET Web应用显示并打开本地计算机已安装应用程序
ASP.NET 实现下拉展示本地已装应用、点击启动的可行方案
先讲最核心的前提:浏览器默认安全沙箱从根源上禁止网页直接枚举访问者本地已安装软件、直接启动本地程序,不存在零配置纯前端/纯公网部署就能实现的方案,以下方案仅适用于本地部署、内网可信场景,公网面向陌生用户的场景无法绕过安全限制实现该需求。
方案1:ASP.NET站点本地部署(站点和访问端在同一台设备,比如本地工具类Web服务)
这个场景实现最简单,所有逻辑都可以在后端完成:
- 枚举本地已安装应用:Windows系统下直接读取注册表的卸载项就能拿到所有已注册的安装程序信息,需要同时读取32位和64位两个注册表路径,避免漏读:
- 64位程序路径:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall - 32位程序路径:
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
对应C#读取的示例代码如下,读取时注意过滤掉没有主程序路径的系统补丁、运行库类条目:
using Microsoft.Win32; using System.Diagnostics; // 全局缓存已安装的应用白名单,避免每次请求都读注册表 private static readonly List<(string AppName, string ExePath)> InstalledAppCache = new(); public List<(string AppName, string ExePath)> LoadInstalledApps() { if (InstalledAppCache.Any()) return InstalledAppCache; string[] regPaths = new[] { @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall" }; foreach (var regPath in regPaths) { using var uninstallKey = Registry.LocalMachine.OpenSubKey(regPath); if (uninstallKey == null) continue; foreach (var subKeyName in uninstallKey.GetSubKeyNames()) { using var appKey = uninstallKey.OpenSubKey(subKeyName); var displayName = appKey?.GetValue("DisplayName")?.ToString(); var iconPath = appKey?.GetValue("DisplayIcon")?.ToString()?.Split(',')[0]; if (string.IsNullOrWhiteSpace(displayName) || string.IsNullOrWhiteSpace(iconPath) || !iconPath.EndsWith(".exe", StringComparison.OrdinalIgnoreCase) || !File.Exists(iconPath)) { continue; } // 去重后加入缓存 if (!InstalledAppCache.Any(a => a.ExePath.Equals(iconPath, StringComparison.OrdinalIgnoreCase))) { InstalledAppCache.Add((displayName, iconPath)); } } } return InstalledAppCache; } - 64位程序路径:
- 前端渲染:页面加载时请求后端接口拿到应用列表,绑定到下拉选择框即可
- 启动逻辑:给下拉框加选中事件,选中后把对应程序的路径传给后端启动接口,接口必须做白名单校验,绝对不能直接执行前端传来的任意路径,避免路径遍历攻击,示例代码:
注意:如果站点部署在IIS,需要把对应应用程序池的标识修改为有桌面交互权限的本地账号,否则启动的程序会在隐藏的后台会话中运行,用户看不到前台界面[HttpGet("app-list")] public IActionResult GetAppList() => Ok(LoadInstalledApps()); [HttpPost("start-app")] public IActionResult StartApp([FromBody] string exePath) { // 校验传入路径是否在提前枚举的白名单内,非白名单路径直接拒绝 if (!InstalledAppCache.Any(a => a.ExePath.Equals(exePath, StringComparison.OrdinalIgnoreCase))) { return Forbid(); } Process.Start(new ProcessStartInfo(exePath) { UseShellExecute = true }); return Ok(); }
方案2:ASP.NET部署在远端服务器,用户通过自己的设备访问
这个场景服务端无法直接操作用户本地设备,需要配合本地代理实现:
- 在用户本地设备安装一个轻量后台服务,仅监听本地回环地址
127.0.0.1的固定端口,提供两个接口:一是返回本机已安装的应用列表,二是接收指令启动指定白名单内的程序 - 前端页面加载时,请求本地服务的接口拉取应用列表渲染下拉菜单,用户选中应用时再请求本地服务的启动接口拉起程序
- 如果不想开发本地代理,也可以用自定义URL协议的方式拉起程序,但这个方案无法自动枚举所有已安装应用,只能提前配置好注册了自定义协议的程序(比如VS Code的
vscode://、百度网盘的baiduyunguanjia://),且用户首次点击时浏览器会弹出安全确认提示。
避坑提醒
- 不要尝试用
ActiveXObject实现相关逻辑,该接口仅在IE10及更早版本的IE浏览器中支持,所有现代浏览器均已禁用 - 所有启动本地程序的逻辑必须加白名单校验,禁止直接执行前端传入的任意路径,否则会存在严重的远程代码执行漏洞
- 本地代理服务不要监听公网IP,仅允许本地回环地址访问,避免被外部恶意调用
内容的提问来源于stack exchange,提问作者Shubham Nalawade
相关产品推荐
相关产品推荐

