【问题标题】:Bash: Only allow script to run by being called from another scriptBash:只允许脚本通过从另一个脚本调用来运行
【发布时间】:2016-07-15 21:44:50
【问题描述】:

我们有两个 bash 脚本来启动应用程序。第一个 (Start-App.sh) 设置环境,第二个 (startup.sh) 来自我们试图不进行大量编辑的第 3 方。如果有人在第一个脚本之前运行第二个脚本,则应用程序无法正确启动。

有没有办法保证startup.sh只能从Start-App.sh脚本中调用?

它们都在同一个目录中,并且在 Red Hat Linux 上通过 bash 运行。

【问题讨论】:

  • 正确的问题是,有没有办法阻止它自动运行(Start-App.sh 除外)并使其明显不应该手动运行?
  • 设置环境的脚本通常来源于需要这些环境的脚本。通过在 shebang source Start-App.sh 下方添加 1 行,不会对 startup.sh 进行大量修改。

标签: linux bash shell sysadmin


【解决方案1】:

TL;DR:

[ $(basename "$0") = "Start-App.sh" ] || exit


说明

与提出的所有其他解决方案一样,它不是 100% 防弹的,但这涵盖了我遇到的大多数常见情况,以防止直接意外运行脚本,而不是从另一个脚本调用它。

与介绍的其他方法不同,这种方法:

  • 不依赖于为每个包含/来源脚本手动设置文件名(即对文件名更改具有弹性)
  • 在所有带有 bash 的主要 *nix 发行版中表现一致
  • 不引入不必要的环境变量
  • 不绑定到单个父脚本
  • 阻止通过显式调用 bash 运行脚本(例如bash myscript.sh

基本的想法是在你的脚本顶部有这样的东西:

[ $(basename "$0") = $(basename "$BASH_SOURCE") ] && exit

$0返回执行链开头的脚本名称

$BASH_SOURCE 将始终指向当前执行的代码所在的文件(如果没有文件,则为空,例如将文本直接传输到 bash)

basename 仅返回主文件名,没有任何目录信息(例如,basename "/user/foo/example.sh" 将返回 example.sh)。这很重要,这样您就不会因为比较 example.sh./example.sh 而得到误报。

要将此调整为仅允许在源自您的问题中的一个特定文件时运行并向最终用户提供有用的错误消息,您可以使用:

[ $(basename "$0") = "Start-App.sh"  ] || echo "[ERROR] To start MyApplication please run ./Start-App.sh" && exit

正如在答案开头提到的那样,这并不是任何形式的严肃安全措施,但我猜这不是你想要的。

【讨论】:

    【解决方案2】:

    你可以创建一个脚本,我们称之为check-if-my-env-set包含

    #! /bin/bash
    
    source Start-App.sh
    exec /bin/bash $@
    

    并用该脚本替换startup.sh 上的shebang(参见this

    #! /abs/path/to/check-if-my-env-set
    #! /bin/bash
    ...
    

    然后,每次运行startup.sh 时,它都会确保环境设置正确。

    【讨论】:

      【解决方案3】:

      正如其他人指出的那样,简短的回答是“不”,虽然您可以整天玩权限,但这仍然不是万无一失的。既然您说您不介意编辑(只是不大量编辑)第二个脚本,那么完成此操作的最佳方法是:

      1) 在父/第一个脚本中,导出一个环境变量及其 PID。这成为父 PID。例如,

      # bash store parent pid
      export FIRST_SCRIPT_PID = $$
      

      2) 然后非常简短地,在第二个脚本中,检查调用 PID 是否与已知可接受的父 PID 匹配。例如,

      # confirm calling pid
      if [ $PPID != $FIRST_SCRIPT_PID ] ; then
          exit 0
      fi
      

      查看这些链接 herehere 以供参考。

      回顾一下:最直接的方法是在第二个脚本中添加至少一两行,希望这不会算作“大量编辑”。

      【讨论】:

        【解决方案4】:

        有没有办法保证startup.sh只能从Start-App.sh脚本中调用?

        确保?没有。如果不编辑startup.sh all 就更不用说了。但是你可以相当接近。

        以下是三个建议 - 您可以使用其中之一,或任意组合。


        最简单,也可能是最好的方法是在startup.sh 的顶部添加一行:

        [ -z $CALLED_FROM_START_APP ] && { echo "Not called from Start-App.sh"; exit 42; }
        

        然后像这样从Start-App.sh 调用它:

        export CALLED_FROM_START_APP=yes
        sh startup.sh
        

        当然,你可以自己在 shell 中设置这个环境变量,所以它实际上不会确保任何东西,但我希望你的工程人员足够成熟,不要这样做。


        你也可以从startup.sh中移除执行权限:

        $ chmod a-x startup.sh
        

        不会阻止人们使用sh startup.sh,所以这里有一个很小的保证;但它可能会阻止自动完成 oopsies,它会将文件标记为“不打算执行” - 如果我看到一个只有一个可执行 .sh 文件的目录,我会尝试运行 that 一个,而不是其他一个。


        最后,您或许可以重命名startup.sh 脚本;例如,您可以将其重命名为 do_not_run,或通过将其重命名为 .startup 来“隐藏”它。这可能不会干扰这个脚本的运行(虽然我不能检查这个)。

        【讨论】:

        • -z 测试中需要在"$CALLED_FROM_START_APP" 周围加上引号,否则它总是通过(即使为空),因为[ -z $var ] 变为[ -z ],shell 将其解释为[ -n -z ],这是真的(如-z 的长度非零)。
        • @EtanReisner 嗯,如果我在dashbash 中尝试这个,它可以在没有引号的情况下正常工作吗?例如[ -z $XXX ] && echo Empty 输出 Empty 符合预期,而 export XXX=yes; [ -z $XXX ] && echo Empty 没有...我也已经在不带引号的情况下输入了好几年了,并且不记得曾经遇到过您描述的问题...
        • 你是对的。我把问题倒过来了。 [ -n $XXX ] 永远不会失败,因为它会退化为 [ -n ],即 [ -n -n ] 而不是 [ -n '' ]。这就是说不使用引号仍然是错误的,因为您最终仍然会测试 [ -n -z ] 而不是 [ -z '' ] 并且如果您的值包含空格或通配符,则会出现错误。
        【解决方案5】:

        另一种选择是检查父进程并找到调用脚本。这也需要在第二个脚本中添加一些代码。

        例如,在被调用的脚本中,可以查看this的退出状态并终止。

        ps $PPID | tail -1 | awk '$NF!~/parent/{exit 1}'
        

        【讨论】:

          【解决方案6】:

          据我所知,没有办法以无法绕过它的方式做到这一点。

          但是,您可以通过使用权限来阻止大多数尝试。

          更改startup.sh 文件的所有者:

          sudo chown app_specific_user startup.sh
          

          使startup.sh 只能由所有者执行:

          chmod u+x startup.sh
          

          Start-App.sh 运行startup.sh 作为app_specific_user

          sudo -u app_specific_user ./startup.sh
          

          【讨论】:

            【解决方案7】:

            您可以在第一个脚本中设置环境变量,然后在运行第二个脚本之前检查该环境变量是否设置正确。

            【讨论】:

            • 这可行,但 OP 确实说他们不想编辑第二个脚本。
            • @sean,OP 说他们不想“大量”编辑启动脚本。
            【解决方案8】:

            您可以通过键入chmod -x startup.sh 使startup.sh 不可执行。这样用户将无法通过键入./startup.sh 来运行它。

            然后从Start-App.sh,通过显式调用shell来调用你的脚本:

            sh ./startup.sh arg1 arg2 ...
            

            bash ./startup.sh arg1 arg2 ...
            

            您可以通过检查startup.sh 的第一行来检查它应该在哪个shell 中运行,它应该如下所示:

            #!/bin/bash
            

            【讨论】:

            • 这不会阻止使用shbash 运行脚本的人。
            • 不会,但用户必须使用bash startup.sh 显式调用它。这样,当用户执行ls -l 时,只有Start-App.sh 会被标记为可执行文件,这表明应该使用它而不是另一个。我的理解是 OP 不想编辑 startup.sh 所以它可以很容易地从上游更新。
            猜你喜欢
            • 2023-01-13
            • 1970-01-01
            • 1970-01-01
            • 2012-06-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多