在Unix系统上保护NamedPipeServerStream的安全方案问询
好的,我来帮你解决这两个问题:
在Windows上你已经用PipeSecurity搞定了命名管道的权限,但Unix域套接字本质是文件系统中的特殊文件,所以我们需要直接修改它的文件权限来达到和mkfifo -m700一样的效果。由于你的项目兼容net451和netstandard1.6,得考虑API的兼容性,下面是具体实现步骤:
步骤1:判断当前运行平台
首先要区分Windows和Unix系统,在netstandard1.6中可以用Environment.OSVersion.Platform来判断:
bool isUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX;
步骤2:创建NamedPipeServerStream并获取套接字路径
在Unix上,如果你传入的管道名是相对名称(比如"MyPipe"),.NET Core会自动在/tmp目录下创建Unix域套接字文件,路径为/tmp/MyPipe。如果你需要自定义路径,可以直接传入绝对路径(比如"/var/run/MyPipe")。
创建实例的代码和Windows上一致:
using (var server = new NamedPipeServerStream( "MyPipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None)) { // 后续处理权限 }
步骤3:修改套接字文件的权限为700
由于netstandard1.6没有内置的Unix文件权限设置API,我们可以通过P/Invoke调用系统的chmod函数来实现:
using System.Runtime.InteropServices; // 引入libc的chmod函数 [DllImport("libc", SetLastError = true)] private static extern int chmod(string path, int mode); // 在创建server实例后调用 if (isUnix) { string socketPath = "/tmp/MyPipe"; // 对应你传入的管道名 const int S_IRWXU = 0x700; // 八进制700的十进制表示,对应当前用户读、写、执行权限 int result = chmod(socketPath, S_IRWXU); if (result != 0) { // 处理错误,比如抛出异常 throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); } }
这样就能确保只有当前用户能访问这个Unix域套接字,和mkfifo -m700的效果完全一致。
mkfifo创建的管道,.NET Core会复用吗? 答案是不会,因为两者是完全不同的IPC机制:
mkfifo创建的是FIFO管道(也叫命名管道,属于字节流管道),是基于文件系统的单向/双向字节流通道。- .NET Core的
NamedPipeServerStream在Unix系统上底层实现的是Unix域套接字(SOCK_STREAM),这是一种更强大的IPC机制,支持全双工通信,并且和FIFO的文件类型完全不同(Unix域套接字的文件类型是s,而FIFO是p)。
如果你提前用mkfifo创建了一个同名文件,当你尝试创建NamedPipeServerStream时,.NET Core会因为路径已存在但不是Unix域套接字而抛出异常。所以不要用这种方式,直接让.NET Core创建Unix域套接字,再按上面的方法修改权限即可。
内容的提问来源于stack exchange,提问作者Tyler James Leonhardt

