繁体   English   中英

在以root身份运行的Java线程中,我们如何应用特定于登录用户的Unix权限?

[英]In a Java thread running as root, how can we apply Unix rights specific to a logged-in user?

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

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

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

对于单线程Linux程序,您可以使用setfsuid() / setfsgid() ,但这不是便携式或多线程程序的选项。

使用SecurityManager!

  1. 将当前的unix用户标识放入ThreadLocal
  2. 创建自己的SecurityManager,检查checkRead()和checkWrite()上的unix用户权限
  3. System.setSecurityManager(new 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执行此操作

如果您只希望允许应用程序通过user1读取文件,我强烈建议应用程序以user1运行。

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

这里举例说明

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

如果您想在单线程Java程序中调用setuid可以在http://www2.sys-con.com/itsg/virtualcd/Java/archives/0510/Silverman/index.html上找到一个很好的例子。

另一种办法是颠倒的做法:运行的代码,而不是为根的大部分时间,要么改变用户ID或以某种方式检查时,它必须使用一些限制资源的权限,运行在用户的大部分时间和通话当一个较小的守护进程需要做一些只有root可以做的事情时,以root身份运行。 这还具有减少攻击面的附加好处。

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

我也遇到了Mikael的确切问题,并且到了这个页面寻找答案。

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

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

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

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

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

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

    此外,子应用程序可以合并 (甚至“钝化”,如果有这样的事情),就像Java EE EJB容器那样。 因此,即使有10,000个用户和(可能)10,000个子应用程序服务,运行的子应用程序的最大数量也会受到限制。 空闲的应用程序被关闭,为其他人腾出空间。

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

对我而言,现在,实施最快最简单的是#1。 但是,我理想的解决方案是#4,但需要时间并测试它是否运行良好。 (这个概念本身借用了inetd / xinetd和EJB,所以我觉得它从根本上来说很合理)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM