簡體   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