如何实现Windows进程间数据传输及同一用户身份验证?
Windows下同一用户进程间安全通信方案
针对同一Windows机器上、需操作系统验证双方为*同一用户(相同SID)*的进程间安全通信需求,以下是几种替代Linux/Unix套接字+SO_PEERCRED的方案:
一、命名管道(Named Pipes)—— 原生首选IPC方案
命名管道是Windows原生IPC机制,自带安全控制能力,可直接实现同一用户进程的身份验证:
创建管道时限制访问权限
创建命名管道时,通过SECURITY_ATTRIBUTES设置仅允许当前用户访问的安全描述符,从源头阻止非授权进程连接。示例代码片段:SECURITY_ATTRIBUTES sa = {0}; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = FALSE; // 生成仅当前用户可完全访问的安全描述符(需替换为实际当前用户SID) ConvertStringSecurityDescriptorToSecurityDescriptor( L"D:P(A;;GA;;;S-1-5-21-XXXXXXXXX-XXXXXXXXX-XXXXXXXXX-XXXXXX)", SDDL_REVISION_1, &sa.lpSecurityDescriptor, NULL); HANDLE hPipe = CreateNamedPipe( L"\\\\.\\pipe\\MySecurePipe", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &sa);接收方验证客户端身份
客户端连接后,通过系统API获取其进程ID,再提取进程令牌中的SID与自身SID对比:DWORD clientPid; GetNamedPipeClientProcessId(hPipe, &clientPid); // 打开客户端进程并获取令牌 HANDLE hClientProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, clientPid); HANDLE hClientToken; OpenProcessToken(hClientProcess, TOKEN_QUERY, &hClientToken); // 提取客户端SID DWORD sidSize = 0; GetTokenInformation(hClientToken, TokenUser, NULL, 0, &sidSize); PTOKEN_USER pTokenUser = (PTOKEN_USER)LocalAlloc(LPTR, sidSize); GetTokenInformation(hClientToken, TokenUser, pTokenUser, sidSize, &sidSize); // 获取自身SID并对比 HANDLE hSelfToken; OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hSelfToken); // 省略自身SID提取逻辑,用EqualSid完成对比 BOOL isSameUser = EqualSid(pTokenUser->User.Sid, selfSid);
二、Unix域套接字(Windows 10 1709+)—— 类Linux SO_PEERCRED方案
Windows 10 1709及以上版本支持AF_UNIX套接字,可通过GetUnixSocketPeerCredentials直接获取对等方凭据,实现与Linux SO_PEERCRED一致的验证逻辑:
创建Unix套接字
服务端创建AF_UNIX类型套接字,绑定到本地管道路径(Windows下Unix套接字路径需以\\.\pipe\开头):SOCKET sock = socket(AF_UNIX, SOCK_STREAM, 0); struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; wcscpy_s(addr.sun_path, L"\\\\.\\pipe\\MyUnixSocket"); bind(sock, (struct sockaddr*)&addr, sizeof(addr)); listen(sock, 5);验证对等方身份
接受连接后,调用getsockopt配合SO_PEERCRED选项获取客户端PID,后续流程同命名管道的SID对比:SOCKET clientSock = accept(sock, NULL, NULL); UNIX_SOCKET_PEER_CREDENTIALS creds; DWORD credSize = sizeof(creds); getsockopt(clientSock, SOL_SOCKET, SO_PEERCRED, (char*)&creds, &credSize); DWORD clientPid = creds.ProcessId; // 通过PID提取客户端SID并与自身对比(逻辑同命名管道)
三、本地TCP套接字+SSPI身份验证
使用127.0.0.1的TCP套接字,结合Windows SSPI(安全支持提供程序接口)完成NTLM/Kerberos身份验证,由系统自动确认双方为同一用户:
- 客户端调用
InitializeSecurityContext发起验证请求,服务端调用AcceptSecurityContext响应; - 验证通过后,系统已确认双方属于同一用户,无需手动处理SID对比。
四、非套接字方案:文件映射+令牌验证
若无需套接字风格的流式通信,可采用文件映射实现IPC,结合令牌验证:
- 创建文件映射时,设置仅当前用户可访问的安全描述符,确保只有同一用户的进程能打开映射;
- 通信过程中,接收方可通过共享同步对象(如事件)获取发送方进程ID,再通过
OpenProcessToken提取SID完成对比。
内容的提问来源于stack exchange,提问作者Cort Ammon
相关产品推荐
相关产品推荐

