使用脚本自动输入SSH密码


193

我需要创建一个脚本,该脚本会自动向OpenSSH ssh客户端输入密码。

假设我需要myname@somehost使用密码SSH进入a1234b

我已经尝试过...

#~/bin/myssh.sh
ssh myname@somehost
a1234b

...但这是行不通的。

如何将此功能纳入脚本?

Answers:


278

首先,您需要安装sshpass

  • Ubuntu / Debian: apt-get install sshpass
  • Fedora / CentOS: yum install sshpass
  • 拱: pacman -S sshpass

例:

sshpass -p "YOUR_PASSWORD" ssh -o StrictHostKeyChecking=no YOUR_USERNAME@SOME_SITE.COM

自定义端口示例:

sshpass -p "YOUR_PASSWORD" ssh -o StrictHostKeyChecking=no YOUR_USERNAME@SOME_SITE.COM:2400

笔记:

  • sshpass-f传递标志时,也可以从文件中读取密码。
    • -f如果ps执行该命令,则使用会防止密码可见。
    • 密码存储在其中的文件应具有安全权限。

12
这比使用Expect好得多。
Per Mejdal Rasmussen 2013年

5
请注意,尽管sshpass会阻止您的密码进入类似的命令ps -aux,但通常不应通过键入密码来运行命令,因为同一台计算机上的其他用户可能会通过运行看到密码ps -aux。如果可行,您还希望使用公共密钥身份验证,如其他答案中所述。这样,您就可以将身份验证信息与脚本分开,以便可以与其他人共享脚本,然后再无忧地决定在〜/ .ssh文件夹中启用加密,而无需对脚本进行加密。
亚历山大·泰勒

2
不幸的是,这在具有自定义ssh端口的服务器上对我不起作用...为什么ssh不能只给我们提供在命令行中插入密码的选项?
安迪

2
为使自定义端口起作用,请在命令末尾添加“ -p端口号”
Ye Lwin Soe,2016年


95

在寻找问题答案几个月后,我终于找到了一个更好的解决方案:编写一个简单的脚本。

#!/usr/bin/expect

set timeout 20

set cmd [lrange $argv 1 end]
set password [lindex $argv 0]

eval spawn $cmd
expect "assword:"
send "$password\r";
interact

将其放在/usr/bin/exp,则可以使用:

  • exp <password> ssh <anything>
  • exp <password> scp <anysrc> <anydst>

做完了!


2
这个答案应该会得到更多的投票,这是一个很好的包装器。刚刚尝试了一些常见的操作,例如与各种标志进行rsync和远程命令执行,并且每次都有效。添加到我的有用脚本工具箱中,谢谢@damn_c!
user2082382

7
也许由于人们没想到它没有得到更多的支持?
clearlight '17

7
之所以说这是IMO并不是一个很好的答案,是因为密码是在脚本中写的,这是迄今为止最不安全的方法……
PierreE

8
在计算机上运行ps的任何人都可以看到该密码。
Daniel Persson


71

使用公共密钥身份验证:https : //help.ubuntu.com/community/SSH/OpenSSH/Keys

在源主机中,仅运行一次:

ssh-keygen -t rsa # ENTER to every field
ssh-copy-id myname@somehost

就是这样,之后,您无需密码即可执行ssh。


21
我懂了。但是我需要使用密码ssh。这是因为“ I”脚本可能位于拇指驱动器上,并且需要在任何计算机上运行;同时不禁用密码。
user1467855'8

3
@ user1467855,我认为您需要更好地解释您的要求。没有人建议您使用不安全的网络。在公共密钥方法中,用户仍然可以使用密码登录。但是您会将私钥复制到拇指驱动器上,这意味着拇指驱动器将是唯一无需密码即可登录的东西。
亚伦·麦克戴德

5
不幸的是,我处于OP状态,因为sysadmin不允许通过rsa / dsa密钥进行身份验证,并且需要密码。你要去做什么。
卡雷尔·比列克(KarelBílek),2013年

26
投反对票,因为这甚至都没有尝试回答所提出的实际问题。
Parthian Shot

2
这仍然提示您首次登录,并且不能在脚本中使用!
Mehrdad Mirreza

29

您可以使用Expects脚本。我已经有一段时间没有写论文了,但是看起来应该像下面这样。您将需要以#!/usr/bin/expect

#!/usr/bin/expect -f
spawn ssh HOSTNAME
expect "login:" 
send "username\r"
expect "Password:"
send "password\r"
interact

我按照您的建议做了,但是收到以下错误:/bin/myssh.sh: 2: spawn: not found /bin/myssh.sh: 3: expect: not found /bin/myssh.sh: 4: send: not found /bin/myssh.sh: 5: expect: not found /bin/myssh.sh: 6: send: not found
user1467855

感谢亚伦修改我的答案是正确的。您可能需要运行以下命令来找到正确的路径以进行预期的操作。which expect
Lipongo

1
您也可以使用以下shebang线:#!/usr/bin/env expect
glenn jackman 2012年

1
我添加interact到结尾,所以ssh会话实际上是交互式的
KarelBílek'13

-1表示在脚本中保留纯文本密码会带来巨大的安全风险。
亚伦·迪古拉

21

变体I

sshpass -p PASSWORD ssh USER@SERVER

变体II

#!/usr/bin/expect -f
spawn ssh USERNAME@SERVER "touch /home/user/ssh_example"
expect "assword:"
send "PASSWORD\r"
interact

-p标志用于指定端口号。
Kookerus

4
否。sshpass不是ssh。 SYNOPSIS sshpass [-ffilename|-dnum|-ppassword|-e] [options] command arguments
RemiZOffAlex

为了在Linux CentOS中运行sshpass,您必须yum -y install epel-release然后yum -y install sshpass
JuniorMayhé16

在这种情况下,可以忽略此数据
RemiZOffAlex

虽然我知道这是一篇老文章,但值得注意的是,Variant II方法会使bash历史记录中的会话密码易受攻击,因此不建议使用。
柯克兰

10

sshpass + autossh

已经提到的一个不错的好处sshpass是您可以将它与一起使用autossh,从而消除了更多的交互效率低下的情况。

sshpass -p mypassword autossh -M0 -t myusername@myserver.mydomain.com

如果例如由于关闭笔记本电脑而中断了wifi,这将允许自动重新连接。


2
请注意,您不能-f在此组合中向when used with autossh, ssh will be *unable* to ask for passwords or passphrases. autossh添加选项,因为harding.motd.ca/autossh/README.txt也是superuser.com/questions/1278583/…–
allenyllee

9

sshpass 具有更好的安全性

我偶然发现此线程时,正在寻找SSH进入陷入困境的服务器的方法-处理SSH连接尝试花费了超过一分钟的时间,并且在输入密码之前超时。在这种情况下,我希望能够在出现提示时立即提供密码。

(如果不清楚,那就是:在服务器处于这种状态的情况下,设置公共密钥登录为时已晚。)

sshpass进行营救。但是,有比这更好的方法sshpass -p

我的实现直接跳到交互式密码提示符(不浪费时间查看是否可以进行公钥交换),并且永远不会将密码显示为纯文本。

#!/bin/sh
# preempt-ssh.sh
# usage: same arguments that you'd pass to ssh normally
echo "You're going to run (with our additions) ssh $@"

# Read password interactively and save it to the environment
read -s -p "Password to use: " SSHPASS 
export SSHPASS

# have sshpass load the password from the environment, and skip public key auth
# all other args come directly from the input
sshpass -e ssh -o PreferredAuthentications=keyboard-interactive -o PubkeyAuthentication=no "$@"

# clear the exported variable containing the password
unset SSHPASS

1
自我注意:更新脚本以trap防止ctrl-C泄漏SSHPASS变量
Ian

1
我发现这PreferredAuthentications=keyboard-interactive行不通,但是用行之有效的代替了它PreferredAuthentications=password
迈克·帕特里奇

7

这就是我登录服务器的方式。

ssp <server_ip>
  • 别名ssp ='/ home / myuser / Documents / ssh_script.sh'
  • 猫/home/myuser/Documents/ssh_script.sh

#!/ bin / bash

sshpass -p mypassword ssh root @ $ 1

因此...

ssp server_ip

5
# create a file that echo's out your password .. you may need to get crazy with escape chars or for extra credit put ASCII in your password...
echo "echo YerPasswordhere" > /tmp/1
chmod 777 /tmp/1

# sets some vars for ssh to play nice with something to do with GUI but here we are using it to pass creds.
export SSH_ASKPASS="/tmp/1"
export DISPLAY=YOURDOINGITWRONG
setsid ssh root@owned.com -p 22

参考:https : //www.linkedin.com/pulse/youre-doing-wrong-ssh-plain-text-credentials-robert-mccurdy?trk=mp-reader-card


3
我认为这篇文章只是在讽刺!
Yan Foto

5

我认为我没有看到有人建议这样做,OP只是说了“脚本”,所以...

我需要解决相同的问题,而我最舒适的语言是Python。

我使用了paramiko库。此外,我还需要使用发出需要升级权限的命令sudo。事实证明,sudo可以通过“ -S”标志通过stdin接受其密码!见下文:

import paramiko

ssh_client = paramiko.SSHClient()

# To avoid an "unknown hosts" error. Solve this differently if you must...
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# This mechanism uses a private key.
pkey = paramiko.RSAKey.from_private_key_file(PKEY_PATH)

# This mechanism uses a password.
# Get it from cli args or a file or hard code it, whatever works best for you
password = "password"

ssh_client.connect(hostname="my.host.name.com",
                       username="username",
                       # Uncomment one of the following...
                       # password=password
                       # pkey=pkey
                       )

# do something restricted
# If you don't need escalated permissions, omit everything before "mkdir"
command = "echo {} | sudo -S mkdir /var/log/test_dir 2>/dev/null".format(password)

# In order to inspect the exit code
# you need go under paramiko's hood a bit
# rather than just using "ssh_client.exec_command()"
chan = ssh_client.get_transport().open_session()
chan.exec_command(command)

exit_status = chan.recv_exit_status()

if exit_status != 0:
    stderr = chan.recv_stderr(5000)

# Note that sudo's "-S" flag will send the password prompt to stderr
# so you will see that string here too, as well as the actual error.
# It was because of this behavior that we needed access to the exit code
# to assert success.

    logger.error("Uh oh")
    logger.error(stderr)
else:
    logger.info("Successful!")

希望这对某人有帮助。我的用例是一次创建目录,发送和解压缩文件以及在约300台服务器上启动程序。因此,自动化至关重要。我尝试了sshpassexpect然后提出了这个建议。


2

我的工作如下

修改了.ssh / config,以消除是/否提示-我在防火墙后面,所以我不必担心欺骗的ssh密钥

host *
     StrictHostKeyChecking no

为期望创建响应文件,即answer.expect

set timeout 20
set node [lindex $argv 0]
spawn ssh root@node service hadoop-hdfs-datanode restart

expect  "*?assword {
      send "password\r"   <- your password here.

interact

创建您的bash脚本,然后在文件中调用Expect

#!/bin/bash
i=1
while [$i -lt 129]    # a few nodes here

  expect answer.expect hadoopslave$i

  i=[$i + 1]
  sleep 5

done

获取使用新配置刷新的128个hadoop数据节点-假设您正在对hadoop / conf文件使用NFS挂载

希望这对某人有帮助-我是Windows用户,这花了我大约5个小时才弄清楚!


“我在防火墙后面,所以我不必担心欺骗的ssh密钥”。在这种情况下,防火墙完全不执行任何操作。HostKeyCheck是这样,因此您可以验证另一端的主机不是木马主机。即,一个只假装是您要连接的地方。如果您连接到未知主机,并做一些敏感的事情,例如编写具有凭据或令牌的文件或输入密码,则该信息现在实际上是公共知识。您在防火墙后面是无关紧要的。
JCGB

2

如果在Windows系统上执行此操作,则可以使用Plink(PuTTY的一部分)。

plink your_username@yourhost -pw your_password




0

在下面的示例中,我将编写使用的解决方案:

场景:我想使用sh脚本从服务器复制文件:

#!/usr/bin/expect
$PASSWORD=password
my_script=$(expect -c "spawn scp userName@server-name:path/file.txt /home/Amine/Bureau/trash/test/
expect \"password:\"
send \"$PASSWORD\r\"
expect \"#\"
send \"exit \r\"
")

echo "$my_script"

-2

在脚本中使用此脚本,第一个参数是主机名,第二个参数是密码。

#!/usr/bin/expect
set pass [lindex $argv 1]
set host [lindex $argv 0]
spawn ssh -t root@$host echo Hello
expect "*assword: " 
send "$pass\n";
interact"

这在现有答案之上显示了什么?特别是那些由damn_c,Lipongo或RemiZOffAlex等人撰写的人
马丁·

脚本执行以及ssh#!/ usr / bin / expect set pass [lindex $ argv 1] set host [lindex $ argv 0] spawn ssh -t root @ $ host sh /tmp/anyscript.sh期望“ * assword:”发送“ $ pass \ n”;互动”
Shivam Mehrotra

-3

要通过外壳脚本连接远程计算机,请使用以下命令:

sshpass -p PASSWORD ssh -o StrictHostKeyChecking=no USERNAME@IPADDRESS

其中IPADDRESSUSERNAMEPASSWORD是需要在脚本中提供的输入值,或者如果我们想在运行时提供,请使用“ read”命令。


5
该答案在现有答案之上显示什么?+绝不建议任何人在StrictHostKeyChecking=no不解释后果的情况下使用。
Martin Prikryl

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.