简体   繁体   English

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

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

We have a Java program run as root on Unix, that therefore can read for example the content of the folders /home/user1 and /home/user2 . 我们在Unix上以root身份运行Java程序,因此可以读取文件夹/home/user1/home/user2 However, if the Unix user "user1" is logged in in our application, he should not be able to access "/home/user2" data. 但是,如果Unix用户“user1”在我们的应用程序中登录,则他应该无法访问“/ home / user2”数据。 We would like to use directly the Unix rights and not recreate all the permissions in our application ! 我们想直接使用Unix权限,而不是在我们的应用程序中重新创建所有权限! So, could we... 那么,我们能......

  1. try to change the UID of our program depending on the user logged in ? 尝试根据用户登录来更改我们程序的UID? Sounds difficult, and each file access is in different threads so the UID would be different on each thread of our program... 听起来很难,每个文件访问都在不同的线程中,所以UID在我们程序的每个线程上都会有所不同......
  2. use JNI to read permissions of " /home/user2 "...And then determine if user1 has sufficient permissions on " /home/user2 " ? 使用JNI读取“ /home/user2 ”的权限...然后确定user1是否对“ /home/user2 ”有足够的权限? (how ?). (怎么样 ?)。

The simplest and most portable way would be to spawn a child process, have it exec a wrapper written in C which changes the UID, drops all the privileges (be careful, writting a wrapper to do that is tricky - it is as hard as writing a setuid wrapper), and execs another java instance to which you talk via RMI. 最简单和最便携的方法是生成一个子进程,让它执行一个用C编写的包装器来改变UID,删除所有权限(小心,写一个包装器来做到这一点很棘手 - 它和写入一样难一个setuid包装器),并执行另一个你通过RMI谈话的java实例。 That java instance would do all the filesystem manipulation on behalf of the user. 该java实例将代表用户执行所有文件系统操作。

For single-threaded Linux programs, you could instead use setfsuid() / setfsgid() , but that is not an option for portable or multithreaded programs. 对于单线程Linux程序,您可以使用setfsuid() / setfsgid() ,但这不是便携式或多线程程序的选项。

Use SecurityManager! 使用SecurityManager!

  1. Put current unix user id into ThreadLocal 将当前的unix用户标识放入ThreadLocal
  2. Create your own SecurityManager that checks unix user permissions on checkRead() and checkWrite() 创建自己的SecurityManager,检查checkRead()和checkWrite()上的unix用户权限
  3. System.setSecurityManager(new MySecurityManager()) System.setSecurityManager(new MySecurityManager())
  4. Enjoy 请享用

Update 更新

There is no, of course, standard library to read unix file permissions. 当然,没有标准库来读取unix文件权限。 It's not WORA. 这不是WORA。

But I have tried briefly to find a ready to use library, and found this one: http://jan.newmarch.name/java/posix/ It uses JNI, but you don't need to write your own JNI code, which is a big relief. 但我已经尝试过简单地找到一个可以使用的库,并找到了这个: http//jan.newmarch.name/java/posix/它使用JNI,但你不需要编写自己的JNI代码,是一个很大的解脱。 :) I'm sure there must also be others. :)我敢肯定还必须有其他人。

Class Stat from there gives you all required access information: http://jan.newmarch.name/java/posix/posix.Stat.html Class Stat从那里为您提供所有必需的访问信息: http//jan.newmarch.name/java/posix/posix.Stat.html

Update 2 更新2

As folks mentioned, this approach fails to check for "non-standard" unix security features, such as ACL or Posix Capabilities (may be; not sure if they apply to files). 正如人们提到的,这种方法无法检查“非标准”unix安全功能,例如ACL或Posix功能(可能是;不确定它们是否适用于文件)。 But if the goal of being totally in sync with host OS security is set, then we even more need to use SecurityManager, because it's a JVM-wide protection mechanism! 但是如果设置了与主机操作系统安全性完全同步的目标,那么我们更需要使用SecurityManager,因为它是一个JVM范围的保护机制! Yes, we can start a child SUID-process to verify the permissions (and keep it running, talking to it via pipe running while the user is logged in), but we need to do so from SecurityManager ! 是的,我们可以启动一个子SUID进程来验证权限(并保持运行,在用户登录时通过管道运行与它通信), 但我们需要从SecurityManager执行此操作

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

If everything else fails, you can run a shellscript from java and parse the result. 如果其他一切都失败了,你可以从java运行一个shellcript并解析结果。

Described for example here 这里举例说明

For those who were wondering, it's apparently not possible to do this by calling setuid with JNI for each independent thread. 对于那些谁想知道,这显然是不可能通过打电话来做到这一点setuid使用JNI为每个独立的线程。 setuid affects the whole process, not just the thread that invoked it. setuid影响整个过程,而不仅仅是调用它的线程。

Should you want to call setuid within a single-threaded Java program there's a good example at http://www2.sys-con.com/itsg/virtualcd/Java/archives/0510/Silverman/index.html . 如果您想在单线程Java程序中调用setuid可以在http://www2.sys-con.com/itsg/virtualcd/Java/archives/0510/Silverman/index.html上找到一个很好的例子。

Another option would be to invert the approach: instead of the code running as root most of the time and either changing the user ID or somehow checking the permissions whenever it has to use some restricted resource, run as the user most of the time and talk to a smaller daemon running as root when it needs to do something only root can do. 另一种办法是颠倒的做法:运行的代码,而不是为根的大部分时间,要么改变用户ID或以某种方式检查时,它必须使用一些限制资源的权限,运行在用户的大部分时间和通话当一个较小的守护进程需要做一些只有root可以做的事情时,以root身份运行。 This also has the added benefit of reducing the attack surface. 这还具有减少攻击面的附加好处。

Of course, you then have to authenticate the connection from the process running as the user to the process running as root. 当然,您必须验证从作为用户运行的进程到以root身份运行的进程的连接。

I am also having the exact problem as Mikael, and got to this page looking for answers. 我也遇到了Mikael的确切问题,并且到了这个页面寻找答案。

None of the answers are 100% satisfactionary for me. 没有一个答案对我来说是100%满意的。 So I am thinking of 4 alternatives: 所以我想到了4种选择:

  1. Use a Linux group that has access to all the users. 使用可以访问所有用户的Linux组。 Run a single Java app under that group. 在该组下运行单个Java应用程序。 This Java app can communicate to the 'root' app using whatever means. 这个Java应用程序可以使用任何方式与“root”应用程序通信。

    Potentially, it can be "hotel"-ed. 潜在地,它可以是“酒店” - 。 eg 1 "hotel" (app with group permissions) per 100 users (or as appropriate). 例如,每100个用户(或适当时)1个“酒店”(具有组权限的应用程序)。 So if you have 10,000 users you need 100 hotels, which is quite manageable. 因此,如果您有10,000名用户,则需要100家酒店,这是非常易于管理的。

  2. Spawn a JVM for each child app under its own user ID. 为每个子应用程序在其自己的用户ID下生成JVM。 This is like calling a script, but rather than using stdin/stdio/stderr, use any communication protocol. 这就像调用脚本,但不是使用stdin / stdio / stderr,而是使用任何通信协议。 In my case, I'm using XMPP and IO Data (which, since it's already in use by other components, it doesn't matter "where" aka which JVM it runs). 在我的情况下,我正在使用XMPP和IO数据 (由于它已经被其他组件使用,因此“无论在哪里”也称为哪个JVM运行)。

  3. Create a Super-Server 'root' app. 创建一个超级服务器 “root”应用程序。 This can be part of the original 'root' app or a separate service dedicated to service management. 这可以是原始“root”应用程序的一部分,也可以是专用于服务管理的单独服务。

    The Super-Server is responsible for handling incoming requests (ie it practically becomes a reverse proxy ) for the user-specific sub-apps, and launching the real child apps (if they're not running already), and passing messages back and forth between the client and the child app(s). 超级服务器负责处理用户特定子应用程序的传入请求(即它实际上成为反向代理 ),并启动真实子应用程序(如果它们尚未运行),并来回传递消息客户端和子应用程序之间。

    Additionally, the child apps can be pooled (or even "passivated", if there's such thing), much in the way Java EE EJB Container does it. 此外,子应用程序可以合并 (甚至“钝化”,如果有这样的事情),就像Java EE EJB容器那样。 So even if there are 10,000 users and (potentially) 10,000 child apps servicing, the maximum number of child apps running are capped. 因此,即使有10,000个用户和(可能)10,000个子应用程序服务,运行的子应用程序的最大数量也会受到限制。 Idle apps are shut down to make room for others. 空闲的应用程序被关闭,为其他人腾出空间。

  4. Same as #3 but rather than creating a proprietary service management mechanism, integrate with Upstart (or the service management framework in the underlying OS). 与#3相同,但不是创建专有服务管理机制,而是与Upstart (或底层操作系统中的服务管理框架)集成。 ie there is a 'root' service that can control Upstart. 即有一个可以控制Upstart的“root”服务。 Upstart can start, stop, restart, can query the status of the child services, just like it can control mysqld, Apache, etc. Upstart可以启动,停止,重启,可以查询子服务的状态,就像它可以控制mysqld,Apache等。

For me, now, the quickest and simplest to implement would be #1. 对我而言,现在,实施最快最简单的是#1。 However, my ideal solution would be #4, but it will take time and testing whether it works well. 但是,我理想的解决方案是#4,但需要时间并测试它是否运行良好。 (the concept itself borrows from inetd/xinetd and EJB, so I think it's pretty sound fundamentally) (这个概念本身借用了inetd / xinetd和EJB,所以我觉得它从根本上来说很合理)

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

相关问题 Jhipster网关用户如何才能仅从登录用户的服务中获取实体 - How Jhipster Gateway user can get the entities from a Service for the logged-in user ONLY CQ5:如何将登录用户的安全上下文传播到集成的Web应用程序? - CQ5: How can I propagate a logged-in user's security context to an integrated web application? 如何使用 JDBCRealm 获取登录用户的用户名? - How can I get the logged-in user's username using JDBCRealm? 从Java应用程序访问当前登录的Drupal用户 - Accessing currently logged-in Drupal user from Java application Java中获取登录用户的可靠且与平台无关的方式 - reliable and platform-independent way of getting logged-in user in java 在Spring 3控制器中,如何检查登录用户的权限并有条件地执行某些操作? - In a Spring 3 controller, how can I check the permissions of the logged-in user and do certain actions conditionally? Android / MySQL:如何根据与登录用户关联的部门显示数据? - Android/MySQL: how can I display data based on the department associated with the logged-in user? 如何在Java中获得Unix文件权限 - How to get Unix file rights in Java 如何在 Spring Boot 中找出当前登录的用户? - How to find out the currently logged-in user in Spring Boot? 如何在Java中使特定方法需要管理员权限? - How can you make specific methods in java require admin rights?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM