Java应用程序有办法获取root权限吗?

18

以非特权用户身份运行 Files.walk(Paths.get("/var/")).count()可能会抛出异常,因为 /var/ 中存在需要root权限才能遍历的文件夹。

不是在寻找以root身份执行bash命令(例如sudo find /var),使用Process等方式。

我只是想确保Files.walk(Paths.get("/var/")).count()不会抛出AccessDeniedException异常:

Exception in thread "restartedMain" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0
    at sun.reflect.NativeMethodAccessorImpl.invoke
    at sun.reflect.DelegatingMethodAccessorImpl.invoke
    at java.lang.reflect.Method.invoke
    at org.springframework.boot.devtools.restart.RestartLauncher.run
Caused by: java.io.UncheckedIOException: java.nio.file.AccessDeniedException: /var/cache/httpd
    at java.nio.file.FileTreeIterator.fetchNextIfNeeded
    at java.nio.file.FileTreeIterator.hasNext
    at java.util.Iterator.forEachRemaining
    at java.util.Spliterators$IteratorSpliterator.forEachRemaining
    at java.util.stream.AbstractPipeline.copyInto
    at java.util.stream.AbstractPipeline.wrapAndCopyInto
    at java.util.stream.ReduceOps$ReduceOp.evaluateSequential
    at java.util.stream.AbstractPipeline.evaluate
    at java.util.stream.LongPipeline.reduce
    at java.util.stream.LongPipeline.sum
    at java.util.stream.ReferencePipeline.count
    at com.example.DemoApplication.main
    ... 5 more
Caused by: java.nio.file.AccessDeniedException: /var/cache/httpd
    at sun.nio.fs.UnixException.translateToIOException
    at sun.nio.fs.UnixException.rethrowAsIOException
    at sun.nio.fs.UnixException.rethrowAsIOException
    at sun.nio.fs.UnixFileSystemProvider.newDirectoryStream
    at java.nio.file.Files.newDirectoryStream
    at java.nio.file.FileTreeWalker.visit
    at java.nio.file.FileTreeWalker.next
    at java.nio.file.FileTreeIterator.fetchNextIfNeeded

这只是一个例子。使用filter(...)可以解决异常问题。但是此示例也可扩展到其他用例。

简而言之,CLI、JavaFX等应用程序是否有可能在通过java -jar app.jar等方法从命令行执行后获得root权限?


4
如果可能的话,那将是一个重大的安全问题... 想象一下,该应用程序获得了根访问权限并执行 rm -rf / 命令。糟糕透了。 - Tunaki
7
该应用程序可以弹出对话框并要求用户输入sudo/root密码。许多本地应用程序已经具备此功能,例如Gnome软件、磁盘工具等。哎呀(表情) - Behrang
5
正确的问题应该是:“我如何忽略我没有访问权限的位置。” - user3458
2
诚实并请求您的应用程序进行sudo执行。所有Linux用户都会喜欢这种方法。 - Joao Polo
1
相关链接:https://dev59.com/VnE95IYBdhLWcg3wDpcG - Kedar Mhaswade
显示剩余5条评论
3个回答

9
如果您想跳过没有访问权限的路径,有两种方法: 这个问题的答案中,解释了如何获取您可以访问的子树所有文件的流。

但是此示例也可以扩展到其他用例。

FileVisitor 使用FileVisitor添加了很多代码,但在遍历目录树时为您提供了更多的灵活性。要解决相同的问题,您可以将Files.walk()替换为:
Files.walkFileTree(Path start, FileVisitor<? super Path> visitor);

扩展 SimpleFileVisitor(以计算文件数量)并覆盖一些方法。

您可以:

  1. 重写 visitFileFailed 方法,以处理由于某些原因无法访问文件的情况;(Lukasz_Plawny 的建议)
  2. (可选)重写 preVisitDirectory 方法,在访问目录之前检查权限:如果您无法访问它,则可以简单地跳过其子树(请注意,您可能能够访问某个目录,但不能访问其所有文件);

例如 1

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    // you can log the exception 'exc'
    return FileVisitResult.SKIP_SUBTREE;
}

例如2

@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {

    if(!Files.isReadable(dir))
        return FileVisitResult.SKIP_SUBTREE;

    return FileVisitResult.CONTINUE;

}

FileVisitor文档

FileVisitor教程

希望对您有所帮助。


2
我的建议是从FileVisitor实现visitFileFailed方法,当无法访问文件时调用该方法。当您在此方法中添加return FileVisitResult.SKIP_SUBTREE;时,就不会抛出AccessDeniedException异常了。 - Lukasz_Plawny

3

以下是几个未经测试的想法:

1) 一开始就使用root权限运行您的应用程序:

sudo java -jar myapp.jar

2) 让您的应用程序启动请求root权限的launcher-class,然后继续运行您的应用程序的其余部分:

java -jar myapp.jar

这又执行了一个shell命令,但只是一个提示输入root密码的xterm窗口,然后继续以root权限运行java程序:

xterm -e "sudo sh -c 'java -jar /tmp/myrootapp.jar'"

或者使用更好看的gksudo。注意 '"

也许 myapp.jar 会提取自身到一个临时目录myapp.jar 包含 myrootapp.jar,因此可以按上述方式启动它。当然,/tmp 应该从Java内部获取,并且最好是一个随机名称的目录,只有运行 myapp.jar 的用户才能访问,以防止注入 myrootapp.jar

跨平台

您自己提到了 /var/,因此我假设您在某种Linux上。如果这也要跨平台工作,例如在Macintosh或Microsoft Windows上,您需要首先进行一些系统识别。然后可以在代码中应用StrategyPattern来处理让 myrootapp.jar 获得root或管理员权限的各种方法。


2
然而,根据您的应用程序,要记住以root权限运行应用程序可能会引入更多有害漏洞。例如,当您使用Rhino引擎时,存在注入漏洞,允许攻击者通过引擎注入任意Java代码。在这种情况下,注入的代码当然是以root权限运行的。 - Max

2

更改权限没有简单的方法。Java不擅长处理这些任务。只有一些技巧,比如在启动时检查权限,尝试通过su/sudo更改权限,然后重新启动应用程序或使用Java-gnome。请在此处阅读更多信息:Java:在Ubuntu上请求root权限


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接