公开命令 java.lang.Runtime.exec(String command) 会带来什么安全风险?

huangapple go评论94阅读模式
英文:

What are the security risks on making public the command java.lang.Runtime.exec(String command)

问题

我正在尝试分解我的自定义应用程序,同时保持总体设计标准。
我最近学会了在Windows上使用GraalVM编译Java应用程序为本机exe文件。

我正在考虑从使用许多复杂的Web应用程序的设计更改为:

  • 只创建一个简单的Web应用程序用作https站点,
  • 并且只有一个Servlet,只有一个任务,即“将链接推送到相关的本机exe文件”,类似于下面的内容
/**
 * 例如,URL = "https://www.webpage.com/app-one/someNativeApplicationName?param1=value1&param2=value2...";
 * URL参数是ASCII或Base64
 */
public String callNativeApplication(String url) {
    //构建nativeApplicationFile
    String someNativeApplicationName = parseNativeApplicationNameFromUrl(url);
    Path nativeApplicationsFolder = Path.of("C:\\nativeApplicationsFolder");
    Path nativeApplicationFile = nativeApplicationsFolder.resolve(someNativeApplicationName);

    //检查目录劫持攻击
    nativeApplicationFile = nativeApplicationFile.toAbsolutePath();
    if (!nativeApplicationFile.startsWith(nativeApplicationsFolder)) {
        throw new RuntimeException("错误:目录劫持攻击");
    }

    //检查隐藏命令攻击
    if (url.chars().filter(ch -> ch == ' ').count() != 0) {
        throw new RuntimeException("错误:隐藏命令攻击");
    }

    //构建命令
    String command = nativeApplicationFile + " " + url;

    //检查隐藏字符攻击
    if (!Charset.forName("US-ASCII").newEncoder().canEncode(command)) {
        throw new RuntimeException("错误:隐藏字符攻击");
    }

    //执行
    Process p = java.lang.Runtime.getRuntime().exec(command);
    String reply = fetchReply(p);
    return reply;
}

并将结果作为回复返回。

是否会有任何安全风险,我还应该考虑什么?尝试这样做是否安全?

英文:

I am trying to fragment my custom applications, while keeping the total design standard.<br>
I have recently learned compiling java applications to native exe files on windows with graalvm.

I am thinking of chaging the design from using many complex web-applications to

  • make only one simple web application to serve as a https site,
  • and having only one servlet having only one task "to push the link to relative native exe files", as sth like below
     /**
     * for example url = &quot;https://www.webpage.com/app-one/someNativeApplicationName?param1=value1&amp;param2=value2...&quot;;
     * url params is ascii or base64
     */
    public String callNativeApplication(String url) {//
        //CONSTRUCT nativeApplicationFile
        String someNativeApplicationName = parseNativeApplicationNameFromUrl(url);
        Path nativeApplicationsFolder = Path.of(&quot;C:\\nativeApplicationsFolder&quot;);
        Path nativeApplicationFile = nativeApplicationsFolder.resolve(someNativeApplicationName);

        //CHECK FOR DIR HACK
        nativeApplicationFile = nativeApplicationFile.toAbsolutePath();
        if(!nativeApplicationFile.startsWith(nativeApplicationsFolder)) {
            throw new RuntimeException(&quot;ERROR: DIR HACK&quot;);
        }

        //CHECK HIDDEN COMMAND HACK
        if (url.chars().filter(ch -&gt; ch == &#39; &#39;).count() != 0) {
            throw new RuntimeException(&quot;ERROR: HIDDEN COMMAND HACK&quot;);
        }

        //CONSTRUCT command
        String command = nativeApplicationFile + &quot; &quot; + url;

        //CHECK HIDDEN CHAR HACK
        if (!Charset.forName(&quot;US-ASCII&quot;).newEncoder().canEncode(command)){
            throw new RuntimeException(&quot;ERROR: HIDDEN CHAR HACK&quot;);            
        }

        //EXECUTE
        Process p = java.lang.Runtime.getRuntime().exec(command); 
        String reply = fetchReply(p);
        return reply;
    }

and return the outcome as reply.

Will there be any security risk that i should additionally consider. Is it safe to give a go?

答案1

得分: 0

关于让用户执行任意 shell 代码为什么是一个坏主意,评论中有一些很好的意见。然而,有一些方法可以让它至少变得更安全一些。例如,您可以将端点限制为一组硬编码的命令,使用枚举:

public enum Command {
    ONE("C:/nativeApplicationsFolder/one.exe"),
    TWO("C:/nativeApplicationsFolder/two.exe"),
    ;

    private final String path;

    Command(String path) {
        this.path = path;
    }

    public String getPath() {
        return path;
    }
}

这样,您可以轻松检查命令是否是您知道是安全的。但仍需小心:如果需要用户传递命令行参数,那么现在您需要再次小心确保用户无法访问您不想让他们访问的文件或其他应用程序。

英文:

There are some great remarks in the comments about why letting users execute arbitrary shell code is a bad idea. However, there are some ways you can make it at least a bit safer. For example, you could restrict the endpoint to a hardcoded set of commands, using an enum:

public enum Command {
    ONE(&quot;C:/nativeApplicationsFolder/one.exe&quot;),
    TWO(&quot;C:/nativeApplicationsFolder/two.exe&quot;),
    ;

    private final String path;

    Command(String path) {
        this.path = path;
    }

    public String getPath() {
        return path;
    }
}

This way, you can easily check that the command is something you know is safe. Be careful, still: If you need the user to pass command line arguments, you now need to be careful again that the user doesn't access files or other applications you don't want them to.

答案2

得分: 0

我坚信使用URL执行shell代码是一个不好的主意。<br>
有很多事情可能会出错。请参见这里

与其处理终端执行的所有安全检查,可能更好的解决方案是:

  • 将URL字符串输入到数据库行中,
  • 然后根据行ID调用本机可执行文件。
String command = nativeApplicationFile + &quot; &quot; + 1234;
/**
     * 例如,url = &quot;https://www.webpage.com/app-one/someNativeApplicationName?param1=value1&amp;param2=value2...&quot;;
     * url参数是ASCII或base64
     */
    public String callNativeApplication(String url) {//
        //构造nativeApplicationFile
        String someNativeApplicationName = parseNativeApplicationNameFromUrl(url);
        Path nativeApplicationsFolder = Path.of(&quot;C:\\nativeApplicationsFolder&quot;);
        Path nativeApplicationFile = nativeApplicationsFolder.resolve(someNativeApplicationName);

        //检查目录是否被篡改
        nativeApplicationFile = nativeApplicationFile.toAbsolutePath();
        if (!nativeApplicationFile.startsWith(nativeApplicationsFolder)) {
            throw new RuntimeException(&quot;错误:目录篡改&quot;);
        }

        //检查文件是否存在
        if (!isFileExists(nativeApplicationFile)) {
            throw new RuntimeException(&quot;错误:文件未找到&quot;);
        }

        //构造命令
        var rowId = pushUrlToDB(url);
        String command = nativeApplicationFile + &quot; &quot; + rowId;

        //执行
        Process p = java.lang.Runtime.getRuntime().exec(command);
        String reply = fetchReply(p);
        return reply;
    }
英文:

I am convinced that executing shell code with url is a bad idea. <br>
There is so many things that can go wrong. Please see here.

Rather than dealing with all security checks for terminal execution, It is probably a better solution:

  • to input the url string to a database row,
  • then call the native exe with row id accordingly.
String command = nativeApplicationFile + &quot; &quot; + 1234;
 /**
     * for example url = &quot;https://www.webpage.com/app-one/someNativeApplicationName?param1=value1&amp;param2=value2...&quot;;
     * url params is ascii or base64
     */
    public String callNativeApplication(String url) {//
        //CONSTRUCT nativeApplicationFile
        String someNativeApplicationName = parseNativeApplicationNameFromUrl(url);
        Path nativeApplicationsFolder = Path.of(&quot;C:\\nativeApplicationsFolder&quot;);
        Path nativeApplicationFile = nativeApplicationsFolder.resolve(someNativeApplicationName);

        //CHECK FOR DIR HACK
        nativeApplicationFile = nativeApplicationFile.toAbsolutePath();
        if(!nativeApplicationFile.startsWith(nativeApplicationsFolder)) {
            throw new RuntimeException(&quot;ERROR: DIR HACK&quot;);
        }

        //CHECK IF FILE EXISTS
        if(!isFileExists(nativeApplicationFile)) {
            throw new RuntimeException(&quot;ERROR: FILE NOT FOUND&quot;);
        }

        //CONSTRUCT command
        var rowId = pushUrlToDB(url);
        String command = nativeApplicationFile + &quot; &quot; + rowId;

        //EXECUTE
        Process p = java.lang.Runtime.getRuntime().exec(command); 
        String reply = fetchReply(p);
        return reply;
    }

huangapple
  • 本文由 发表于 2023年8月10日 13:26:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872852.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定