我正在开发一个基于Erlang的面向安全的项目。此应用程序需要访问受限于root或其他特权用户的系统的某些部分。目前,该项目仅适用于Unix / Linux / BSD系统,不应更改文件(只读访问)。
我已经考虑(并测试过)其中一些解决方案,但是,我不知道我应该如何使用Erlang。什么是最糟糕的?哪个最好?什么是最容易维护的?
谢谢!
这个解决方案是最糟糕的,我甚至想在测试服务器时避免使用它。
_____________________________
| |
| (root) |
| ___________ _______ |
| | | | | |
| | Erlang VM |<---| Files | |
| |___________| |_______| |
|_____________________________|
你可以在这里看到我目前不想要的大图。
#!/usr/bin/env escript
main([]) ->
ok;
main([H|T]) ->
{ok, Data} = file:read_file(H),
io:format("~p: ~p~n", [H,Data]),
main(T).
以root身份运行,然后瞧。
su - root
${script_path}/readfile.escript /etc/shadow
我需要启动2个节点,一个以root身份运行,另一个以特权用户身份运行,另一个运行节点由受限用户启动,可以从外部轻松访问。这种方法工作得很好,但有很多问题。首先,由于连接节点之间的远程过程调用,我无法使用标准的Erlang分布式协议连接到特权用户节点(受限节点可以在特权节点上执行任意命令)。我不知道Erlang是否可以在执行它们之前实际过滤RPC。其次,我需要在一台主机上管理两个节点。
________________ ____________________________
| | | |
| (r_user) | | (root) |
| ___________ | | ___________ _______ |
| | | | | | | | | |
| | Erlang VM |<===[socket]===>| Erlang VM |<---| Files | |
| |___________| | | |___________| |_______| |
|________________| |____________________________|
在下面的例子中,我将启动两个Erlang shell。第一个shell将处于受限模式:
su - myuser
erl -sname restricted -cookie ${mycookie}
第二个将与特权用户一起运行:
su - root
erl -sname privileged -cookie ${mycookie}
最后,在受限制的节点上(通过本例中的shell),我可以访问所有文件:
{ok, Data} = rpc:call(privileged, file, read_file, ["/etc/shadow"]).
我在本例中使用本地unix套接字,仅支持R19 / R20。 受限制的用户需要访问此套接字,存储在某处
/var/run
。
我赋予Erlang VM进程权限以使用sudo执行命令。我只需要执行特定的程序,获取stdout并解析它。在这种情况下,我需要使用我系统中现有的可用程序或创建一个新程序。
________________ _______________________
| | | |
| (r_user) | | (root) |
| ___________ | | ______ _______ |
| | | | | | | | | |
| | Erlang VM |<===[stdin]===>| sudo |<---| Files | |
| |___________| | | |______| |_______| |
|________________| |_______________________|
我使用setuid标志创建一个端口集。此程序现在有权从文件中读取,但我需要将其放在服务器上的安全位置。如果我想让它变得动态,我还应该在Erlang VM和这个端口之间定义一个严格的协议。 IMO,setuid很少是一个好的答案。
________________ ________________________
| | | |
| (r_user) | | (root) [setuid] |
| ___________ | | _______/ _______ |
| | | | | | | | | |
| | Erlang VM |<===[stdin]===>| ports |<---| Files | |
| |___________| | | |_______| |_______| |
|________________| |________________________|
我认为我不能在Erlang VM中赋予NIF特定权利,可能使用辣椒或其他非便携/ OS特定的内核功能。
_______________
| |
| (r_user) |
| ___________ |
| | | |
| | Erlang VM | |
| |___________| |
| | | |
| | NIF | |
| |___________| | _______
| | | | | |
| | ??? |<---| Files |
| |___________| | |_______|
|_______________|
我可以创建一个以root身份运行的守护程序,使用Unix Socket或其他方法连接到Erlang VM。这个解决方案有点像使用sudo的端口或外部命令,除了我需要管理一个具有特权的长生命守护进程。
________________ _________________________
| | | |
| (r_user) | | (root) |
| ___________ | | ________ _______ |
| | | | | | | | | |
| | Erlang VM |<===[socket]==>| daemon |<---| Files | |
| |___________| | | |________| |_______| |
|________________| |_________________________|
OpenSSH and lot of other secure software以root身份运行,并使用管道创建2个互连进程。以root身份启动Erlang VM时,会生成2个进程,一个作为root进程,另一个进入受限用户。当某些操作需要root权限时,受限进程会向root进程发送请求并等待其回答。我想这是当前比较复杂的解决方案,而且我没有掌握足够的C和Erlang VM来使这个东西运行良好。
______________ _______________
| | | |
| (root) | | (r_user) |
| __________ | | ___________ |
| | | | | | | |
| | PrivProc |<===[pipe]===>| Erlang VM | |
| |__________| | | |___________| |
|______________| |_______________|
答案 0 :(得分:1)
从安全角度来看,您最好的选择是尽量减少使用root权限运行的代码的数量和复杂性。因此,当你以root身份运行整个Erlang VM时,我会排除所有选项 - 那里只有太多的代码可以安全地锁定它。
只要您只需要阅读一些文件,最好的选择就是编写一个小型C程序,使用sudo
从Erlang VM运行。这个程序所要做的就是为你打开文件,并通过Unix套接字将文件描述符移交给Erlang进程。我曾经在一个依赖这种技术打开特权TCP端口的项目上工作,它就像一个魅力。不幸的是,这不是一个开源项目,但通过一些谷歌搜索我发现这个库完全相同:https://github.com/msantos/procket
我建议你分叉procket
并删除它(你似乎不需要icmp
支持,只有常规文件以只读模式打开。
在Erlang VM中拥有文件描述符后,您可以通过不同的方式阅读它:
procket:read/2
这样的NIF。procket
文档中的network sniffing example。