3

我们有一个在 Unix 上以root身份运行的 Java 程序,因此可以读取文件夹的内容/home/user1/home/user2. 但是,如果 Unix 用户“user1”在我们的应用程序中登录,他应该无法访问“/home/user2”数据。我们想直接使用 Unix 权限,而不是在我们的应用程序中重新创建所有权限!那么,我们能不能...

  1. 尝试根据登录的用户更改我们程序的 UID 吗?听起来很难,而且每个文件访问都在不同的线程中,所以我们程序的每个线程上的 UID 都会不同......
  2. 使用JNI读取“ /home/user2”的权限...然后判断user1是否有足够的“ /home/user2”权限?(如何 ?)。
4

7 回答 7

2

最简单和最便携的方法是生成一个子进程,让它执行一个用 C 编写的包装器,该包装器更改 UID,删除所有特权(小心,编写一个包装器来做到这一点很棘手 - 这和写作一样难setuid 包装器),并执行您通过 RMI 与之交谈的另一个 java 实例。该 java 实例将代表用户执行所有文件系统操作。

对于单线程 Linux 程序,您可以改用setfsuid()/ setfsgid(),但这不是可移植或多线程程序的选项。

于 2008-11-05T10:09:11.773 回答
2

使用安全管理器!

  1. 将当前的 unix 用户 id 放入 ThreadLocal
  2. 创建您自己的 SecurityManager 来检查 unix 用户对 checkRead() 和 checkWrite() 的权限
  3. System.setSecurityManager(新的 MySecurityManager())
  4. 享受

更新

当然,没有标准库来读取 unix 文件权限。这不是WORA。

但是我已经简单地尝试找到一个可以使用的库,并找到了这个:http: //jan.newmarch.name/java/posix/它使用 JNI,但您不需要编写自己的 JNI 代码,它是一个很大的解脱。:) 我相信肯定还有其他人。

Class Stat 从那里为您提供所有必需的访问信息:http: //jan.newmarch.name/java/posix/posix.Stat.html

更新 2

正如人们所提到的,这种方法无法检查“非标准”unix 安全功能,例如 ACL 或 Posix 功能(可能是;不确定它们是否适用于文件)。但是如果设定了与主机操作系统安全性完全同步的目标,那么我们就更需要使用 SecurityManager,因为它是一种 JVM 范围的保护机制!是的,我们可以启动一个子 SUID 进程来验证权限(并保持它运行,在用户登录时通过管道运行与它通信),但我们需要从 SecurityManager 这样做

于 2008-11-05T12:14:32.487 回答
0

如果您只希望应用程序允许用户 1 读取文件,我强烈建议应用程序以用户 1 身份运行。

于 2008-11-05T09:54:51.940 回答
0

如果其他一切都失败了,您可以从 java 运行 shellscript 并解析结果。

例如描述here

于 2008-11-05T10:00:29.853 回答
0

对于那些想知道的人,显然不可能setuid通过为每个独立线程 调用 JNI 来做到这一点。setuid影响整个进程,而不仅仅是调用它的线程。

如果您想setuid在单线程 Java 程序中调用,那么http://www2.sys-con.com/itsg/virtualcd/Java/archives/0510/Silverman/index.html上有一个很好的示例。

于 2008-11-05T10:09:47.793 回答
0

另一种选择是颠倒该方法:大多数时间以root身份运行代码而不是更改用户ID或在必须使用某些受限资源时以某种方式检查权限,而是以大多数时间以用户身份运行交谈当它需要做一些只有root才能做的事情时,以root身份运行的一个较小的守护进程。这还具有减少攻击面的额外好处。

当然,您随后必须验证从以用户身份运行的进程到以 root 身份运行的进程的连接。

于 2008-11-05T12:37:43.033 回答
0

我也有像 Mikael 一样的确切问题,并到此页面寻找答案。

没有一个答案对我来说是 100% 满意的。所以我在想4个选择:

  1. 使用有权访问所有用户的 Linux 组。在该组下运行单个 Java 应用程序。这个 Java 应用程序可以使用任何方式与“根”应用程序通信。

    潜在地,它可以是“酒店”版。例如,每 100 个用户(或视情况而定)有 1 个“酒店”(具有组权限的应用程序)。因此,如果您有 10,000 个用户,您需要 100 家酒店,这是非常易于管理的。

  2. 为每个子应用程序在其自己的用户 ID 下生成一个 JVM。这就像调用脚本,但不是使用 stdin/stdio/stderr,而是使用任何通信协议。就我而言,我使用的是 XMPP 和IO 数据(因为它已经被其他组件使用,所以它在“哪里”运行,也就是运行哪个 JVM 并不重要)。

  3. 创建一个超级服务器“根”应用程序。这可以是原始“根”应用程序的一部分,也可以是专门用于服务管理的单独服务。

    超级服务器负责处理用户特定子应用的传入请求(即它实际上成为反向代理),并启动真正的子应用(如果它们尚未运行),并来回传递消息在客户端和子应用程序之间。

    此外,可以将子应用程序化(或者甚至“钝化”,如果有的话),就像Java EE EJB 容器那样。因此,即使有 10,000 个用户和(可能)10,000 个子应用程序服务,运行的子应用程序的最大数量也是有上限的。闲置的应用程序被关闭以为其他应用程序腾出空间。

  4. 与#3 相同,但不是创建专有的服务管理机制,而是与Upstart(或底层操作系统中的服务管理框架)集成。即有一个可以控制Upstart 的“根”服务。Upstart可以启动、停止、重启,可以查询子服务的状态,就像它可以控制mysqld、Apache等一样。

For me, now, the quickest and simplest to implement would be #1. However, my ideal solution would be #4, but it will take time and testing whether it works well. (the concept itself borrows from inetd/xinetd and EJB, so I think it's pretty sound fundamentally)

于 2011-07-16T16:08:29.500 回答