【问题标题】:How to validate filename in bash script?如何验证bash脚本中的文件名?
【发布时间】:2013-08-16 22:15:40
【问题描述】:

关于我的申请的一点点:

我正在用 bash 脚本编写一个小应用程序。应用程序必须将个人设置存储到主目录。

我的设置是以键/值对的形式存储为文件名/内容:

for example:
~/my-github-app
    ├── github-account
    ├── github-token

我目前添加键/值的解决方案:

read KEY
read VALUE
# FIXME! should check for for valid filename.
#        user can do injection hack by KEY="../../path/to/yourfile"
echo $VALUE > ~/my-github-app/$KEY

验证 $KEY 最简单、最安全的方法是什么?

  • 内置函数?
  • 正则表达式?

我真的需要一个可重复使用的解决方案,而不仅仅是这个应用程序。

编辑:

“验证文件名”表示检查字符串是否为正确的文件名格式,被操作系统接受。

  • “bob”:良好的文件名格式
  • "" : 错误,因为文件名不能为空
  • “*”:?
  • “/”:?
  • “骗局”:? ....

【问题讨论】:

    标签: bash validation filenames


    【解决方案1】:

    除了@Aleks-Daniel Jakimenko-A. 的回答之外,以下脚本会检查以下条件,如果设置了所有条件,则返回 True

    • a-z
    • A-Z
    • 0-9
    • 下划线 (_)
    • 破折号 (-)
    • 句号 (.)
    • 最大长度为 255
    • 第一个字符应该是字符或数字:{a-z or A-z or 0-9}

    my_script.sh:

    #!/bin/bash
    # To run: bash my_script.sh <my_string_is>
    
    key=$1
    val=$(echo "${#key}")
    
    if [[ $key == "" ]]; then
       echo "False";
       exit
    fi
    
    if [[ $key == "." ]] || [[ $key == ".." ]]; then
        # "." and ".." are added automatically and always exist, so you can't have a
        # file named . or .. // https://askubuntu.com/a/416508/660555
        echo "False";
        exit
    fi
    
    if [ $val -gt 255 ]; then
       # String's length check
       echo "False";
       exit
    fi
    
    if ! [[ $key =~ ^[0-9a-zA-Z._-]+$ ]]; then
        # Checks whether valid characters exist
        echo "False";
        exit
    fi
    
    _key=$(echo $key | cut -c1-1)
    if ! [[ $_key =~ ^[0-9a-zA-Z.]+$ ]]; then
        # Checks the first character
        echo "False";
        exit
    fi
    
    echo "True";
    

    【讨论】:

    • 有什么理由不先检查字符串长度吗?在许多系统上,参数大小限制似乎约为 2MB,因此如果我们稍后返回 false,将所有这些与正则表达式匹配可能是浪费精力。
    • 没有具体原因。我更新了我的答案以首先检查字符串长度。@Aleks-DanielJakimenko-A.
    • 为什么第一个字符不能是点?在 Unix 和类 Unix 系统中,a 将创建一个具有有效文件名的隐藏文件。
    • @HiltonFernandes 第一个字符可以是点。我根据您的评论更新了我的答案。只是提醒没有文件名“。”或“..”
    • @alper,非常感谢您提供的出色功能。
    【解决方案2】:

    确保安全的唯一方法是使用白名单。这意味着不要将坏字符列入黑名单,而是允许好字符。黑名单总是失败的原因是你不能把所有奇怪的字符都列入黑名单,你总是会忘记一些东西。特别是如果您使用的是 unicode 字符串。

    文件名可以包含任何内容。根据维基百科:

    文件名中允许的 Ext4 字符:除 NUL ('\0') 和 '/' 之外的所有字节

    这意味着整个 bash 脚本都可以是有效的文件名。 所以,如果我是你,我只会允许 a-zA-Z 作为有效字符。问题解决了。

    你就是这样做的:

    # if [[ $key =~ [^a-zA-Z] ]]; then # or this. Whatever makes more sense to you
    if ! [[ $key =~ ^[a-zA-Z]+$ ]]; then
        echo 'Wrong key. Only a-zA-Z characters are allowed' >&2 # write to stderr
        exit 1
    fi
    

    【讨论】:

    【解决方案3】:

    如果您只想检查文件是否已经存在,请使用test 命令并像这样使用它进行验证:

    if [[ ! -e "$KEY" ]]
    then
        #file doet not exists
    fi
    

    【讨论】:

      【解决方案4】:

      您要验证什么,只是密钥不包含任何路径信息?

      KEY=$(basename $KEY) 
      

      这将删除作为路径一部分的 KEY 的任何部分。也就是说,有很多用户可以输入的东西可能是个坏主意。您能否列出允许的密钥,然后拒绝不在该列表中的任何内容?

      如果您尝试查看文件是否可写,您可以检查 a) 它是否存在且可写 (-w) 或 b) 尝试写入并检查错误。

      【讨论】:

      • 嗨 zigdon,basename 从路径中提取文件名,而不是用于验证文件名。有效的文件名是可创建的文件名。
      • 这就是我试图找出的 - 你所说的“验证” KEY 是什么意思。
      • 是的“允许的键列表”通过正则表达式,谢谢 zigdon
      • 如果您有一个允许键的列表,我不会使用正则表达式,只需对照该列表进行检查即可。比如说,在每个目录中预先填充允许的键,然后如果它已经存在,则允许覆盖,但不能创建新的。
      猜你喜欢
      • 2010-09-16
      • 2014-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-16
      • 2010-09-29
      相关资源
      最近更新 更多