我有一个连接到 SFTP 站点并上传一些文件的期望脚本。 ID 和密码包含在本地文本文件中。 Expect 脚本将这些文件作为变量读取,然后将其传递到 SFTP 服务器。
我遇到的问题是我们提供的密码很复杂,其中包括特殊字符($\,!)等。例如,如果密码是 pass$word,则 $ 作为特殊字符而不是文字传递。这是通过变量传递的(多个站点和 ID)
我无法使用“$pw”,因为它会直接将 $pw 传递给服务器,而使用“$pw”会发送特殊字符。我需要它按原样传递密码。
到目前为止,我一直在手动将它们转义(例如 pass\$word),但这很乏味,我想以脚本方式进行。
脚本看起来像这样(名称和地点已更改以保护无辜者)
#!/bin/bash
home=/data/ftp/vf/drop/
un=`cat /home/vf/workflow/.udf/.u/.u$1`
pw=`cat /home/vf/workflow/.udf/.p/.p$1`
sl=`cd /home/vf/workflow/scheduler; grep $1 upload*|cut -d \: -f1`
/usr/bin/expect -c "
spawn /usr/bin/sftp -o KexDHMin=1024 $un@$sl.mysteriouslocation.com
set timeout -1
expect *Authentication
expect Password*
send \"$pw\r\"
expect sftp*
send \"mput /$home/$1/transfer/*\r\"
expect sftp*
send \"ls \r\"
expect sftp*
send \"bye\r\"
expect eof
exit
我怎样才能将密码传递给期望脚本,以便它发送文字字符而不赋予它们特殊含义?我不认为我可以为密码文件本身编写“修复”脚本,这意味着每次它看到特殊字符时,都会通过 sed 或其他方式将其转义,因为转义字符本身很特殊,可能最终会出现一个循环。
非常感谢您的帮助!
答案1
将值作为环境变量传递。这也将避免命令注入漏洞并在ps
输出中显示密码!
#! /bin/sh -
home=/data/ftp/vf/drop
un=$(cat /home/vf/workflow/.udf/.u/.u"$1")
pw=$(cat /home/vf/workflow/.udf/.p/.p"$1")
sl=$(cd /home/vf/workflow/scheduler &&
grep -Fe "$1" upload*|cut -d : -f1)
export home un sl pw
user=$1 /usr/bin/expect -c '
spawn /usr/bin/sftp -o KexDHMin=1024 $env(un)@$env(sl).mysteriouslocation.com
set timeout -1
expect *Authentication
expect Password*
send $env(pw)\r
expect sftp*
send "mput /$env(home)/$env(user)/transfer/*\r"
expect sftp*
send ls\r
expect sftp*
send bye\r
expect eof
exit'
(好吧,如果变量包含使sftp
run 命令类似于 的文本,它仍然可能是命令注入漏洞!reboot
)。
答案2
一个小的 Perl 片段可用于转义(反斜杠)所有不匹配的 ASCII 字符/[A-Za-z_0-9]/
方法是使用引用元功能。 Perl 命令行可以轻松地合并到您的 shell 脚本中:
#/bin/sh
pstr='$x%y!zpass' # plain, un-escaped string
estr=$(perl -e 'print quotemeta shift(@ARGV)' "${pstr}")
echo ${estr} # show escaped string
产生:
\$x\%y\!zpass
答案3
您可以将 Expect 程序放在一个单独的脚本中(我们称之为sftp.expect
),并将用户名/密码作为参数传递给它。
这确实存在命令行参数对系统上的其他用户可见的问题,所以这不是处理密码的最佳方法,并且您真的不想对共享系统上的密码执行此操作。
#!/usr/bin/expect -f
set un [lindex $argv 0];
set pw [lindex $argv 1];
set sl [lindex $argv 2];
spawn /usr/bin/sftp -o KexDHMin=1024 $un@$sl.mysteriouslocation.com
set timeout -1
expect *Authentication
expect Password*
send "$pw\r"
然后从 shell 脚本运行它
#!/bin/bash
un=$(cat /home/vf/workflow/.udf/.u/.u"$1")
pw=...
sl=...
expect -f sftp.expect "$un" "$pw" "$sl"
或者,如果您想将 Expect 脚本保留在同一个 shell 脚本中,请将其粘贴到此处文档中:
#!/bin/bash
un=foo
# ...
expect -f - "$un" <<'EOF'
set un [lindex $argv 0];
send "user is: $un\r\n"
# ...
EOF
(请注意 周围的引号EOF
,我们不希望 shell 解释此处文档中的变量。)