【问题标题】:Erlang Privilege SeparationErlang 权限分离
【发布时间】:2018-07-14 13:19:33
【问题描述】:

我正在开发一个基于 Erlang 的面向安全的项目。此应用程序需要访问仅限于 root 或其他特权用户的系统的某些部分。目前,该项目仅适用于 Unix/Linux/BSD 系统,不应更改文件(只读访问)。

我已经考虑过(并测试过)其中一些解决方案,但是,我不知道我应该对 Erlang 采取什么措施。最糟糕的是什么?哪个最好?什么最容易维护?

谢谢!

1 个节点(作为根)

这个解决方案是最糟糕的,而且,即使在测试服务器上,我也想避免它。

 _____________________________
|                             |
| (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

1 个节点(作为 root)+1 个节点(作为受限用户)

我需要启动 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}

标准 Erlang RPC(安全性不够)

最后,在受限节点上(本例通过 shell),我可以访问所有文件:

{ok, Data} = rpc:call(privileged, file, read_file, ["/etc/shadow"]).

使用“防火墙”方法

在此示例中,我使用的是本地 unix 套接字,仅在 R19/R20 之前受支持。 受限用户需要访问此套接字,存储在某处 /var/run.

1 个节点(作为受限用户)+ 外部命令(使用 sudo)

我授予 Erlang VM 进程使用 sudo 执行命令的权利。我只需要执行特定的程序,获取标准输出并解析它。在这种情况下,我需要使用系统中现有的可用程序或创建一个新程序。

 ________________            _______________________
|                |          |                       |
| (r_user)       |          | (root)                |
|  ___________   |          |  ______      _______  |
| |           |  |          | |      |    |       | |
| | Erlang VM |<===[stdin]===>| sudo |<---| Files | |
| |___________|  |          | |______|    |_______| |
|________________|          |_______________________|

1 个节点(作为受限用户)+ 端口(setuid)

我创建了一个带有 setuid 标志的端口集。该程序现在有权读取文件,但我需要将它放在服务器上的安全位置。如果我想让它动态化,我还应该在 Erlang VM 和这个端口之间定义一个严格的协议。 IMO,setuid 很少是一个好的答案。

 ________________            ________________________
|                |          |                        |
| (r_user)       |          | (root)   [setuid]      |
|  ___________   |          |  _______/     _______  |
| |           |  |          | |       |    |       | |
| | Erlang VM |<===[stdin]===>| ports |<---| Files | |
| |___________|  |          | |_______|    |_______| |
|________________|          |________________________|

1 个节点(作为受限用户)+ NIF

我认为我不能为 Erlang VM 中的 NIF 赋予特定权利,可能具有辣椒或其他非便携式/特定于操作系统的内核功能。

 _______________
|               |
| (r_user)      |
|  ___________  |
| |           | |
| | Erlang VM | |
| |___________| |
| |           | |
| | NIF       | |
| |___________| |   _______
| |           | |  |       |
| | ???       |<---| Files |
| |___________| |  |_______|
|_______________|

1 个节点(作为受限用户)+ 1 个守护进程(作为 root)

我可以创建一个以 root 身份运行的守护进程,使用 Unix Socket 或其他方法连接到 Erlang VM。这个解决方案有点像带有 sudo 的端口或外部命令,除了我需要管理一个具有特权的长寿守护程序。

 ________________            _________________________
|                |          |                         |
| (r_user)       |          | (root)                  |
|  ___________   |          |  ________      _______  |
| |           |  |          | |        |    |       | |
| | Erlang VM |<===[socket]==>| daemon |<---| Files | |
| |___________|  |          | |________|    |_______| |
|________________|          |_________________________|

自定义 Erlang 虚拟机

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 | |
| |__________| |          | |___________| |
|______________|          |_______________|

【问题讨论】:

    标签: c security unix erlang privileges


    【解决方案1】:

    从安全角度来看,您最好的选择是尽量减少以 root 权限运行的代码的数量和复杂性。因此,当您以 root 身份运行整个 Erlang VM 时,我会排除所有选项 - 那里的代码太多,无法安全锁定它。

    只要您只需要读取一些文件,最好的选择是编写一个小型 C 程序,您可以使用 sudo 从 Erlang VM 运行该程序。该程序所要做的就是为您打开文件并通过 Unix 套接字将文件描述符交给 Erlang 进程。我曾经在一个项目上工作,该项目依赖于这种技术来打开特权 TCP 端口,它的工作原理非常棒。不幸的是,这不是一个开源项目,但通过谷歌搜索,我发现这个库做的事情完全相同:https://github.com/msantos/procket

    我建议你 fork procket 并将其剥离一点(你似乎不需要 icmp 支持,只需要以只读模式打开常规文件)。

    一旦你在 Erlang VM 中获得了文件描述符,你就可以通过不同的方式读取它:

    • 使用像 procket:read/2 这样的 NIF。
    • 将文件描述符作为 Erlang 端口访问,请参阅 procket 文档中的 network sniffing example

    【讨论】:

      猜你喜欢
      • 2017-03-18
      • 2011-09-24
      • 2017-08-11
      • 2023-01-30
      • 2020-03-26
      • 1970-01-01
      • 2018-01-16
      • 2011-01-10
      • 2021-07-09
      相关资源
      最近更新 更多