如何在Bash脚本中验证文件名?

5

关于我的应用程序:

我正在编写一个小型的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":良好的文件名格式
  • "":不好,因为文件名不能为空
  • "*":?
  • "/":?
  • "con":?....
4个回答

10

使某物具有安全性的唯一方法是使用白名单。这意味着不要列出坏字符,而是允许好字符。黑名单永远不会成功的原因是你无法列出所有奇怪字符,你总会忘记某些。特别是当你使用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

感谢关于Ext4的信息。我对白名单有相同的想法:),https://github.com/damphat/kv-bash/blob/master/kv-bash - damphat

5
除了 @Aleks-Daniel Jakimenko-A. 的回答之外,以下脚本检查以下条件。如果所有条件都设置,则返回True
  • a-z
  • A-Z
  • 0-9
  • 下划线 (_)
  • 破折号 (-)
  • 句点 (.)
  • 最大长度为255
  • 第一个字符应该是字符或数字: {a-zA-z0-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";

1
有没有理由先检查字符串长度?在许多系统上,参数大小限制似乎约为≈2MB,因此如果我们后来返回false,那么将所有内容与正则表达式匹配可能是徒劳的。 - Aleks-Daniel Jakimenko-A.
没有特定的原因。我更新了我的答案,首先检查字符串长度。@Aleks-DanielJakimenko-A. - alper
为什么第一个字符不能是点?在Unix和类Unix系统中,这会创建一个带有有效文件名的隐藏文件。 - Hilton Fernandes
1
@HiltonFernandes 第一个字符可以是点。我根据您的评论更新了我的答案。提醒一下,不要有文件名“。”或“..”。 - alper
@alper,非常感谢你提供了一个很棒的函数。 - Hilton Fernandes

1
如果您只想检查文件是否已经存在,请使用test命令,并像以下方式使用进行验证:
if [[ ! -e "$KEY" ]]
then
    #file doet not exists
fi

0
你想要验证什么,只是一个键不包含任何路径信息吗?
KEY=$(basename $KEY) 

这将删除路径中任何作为KEY的部分。话虽如此,用户可能输入许多不好的东西。也许你可以有一个允许的键列表,然后拒绝不在该列表中的任何内容?

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


嗨,zigdon,basename从路径中提取文件名,而不是用于验证文件名。有效的文件名是可创建的文件名。 - damphat
这就是我想要找到的 - 你所说的“验证”KEY是什么意思。 - zigdon
通过正则表达式允许的键列表,感谢zigdon。 - damphat
如果您有一个允许的键列表,我不会使用正则表达式,只需将其与该列表进行比较。例如,在每个目录中预填充允许的键,然后允许覆盖已存在的键,但不允许创建新键。 - zigdon

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