Sử dụng kỳ vọng trong tập lệnh bash để cung cấp mật khẩu cho lệnh SSH


131

Đối với những người muốn trả lời rằng tôi nên sử dụng khóa SSH, vui lòng kiêng

Tôi đang cố gắng sử dụng kỳ vọng trong tập lệnh bash để cung cấp mật khẩu SSH. Cung cấp mật khẩu hoạt động nhưng tôi không kết thúc phiên SSH như bình thường, nó sẽ quay trở lại bash.

Kịch bản của tôi:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com'
expect "password"
send "$PWD\n" 
EOD
echo "you're out"

Đầu ra của tập lệnh của tôi:

spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
usr@$myhost.example.com's password: you're out

Tôi muốn có phiên SSH của mình và chỉ khi tôi thoát nó mới quay lại tập lệnh bash của mình. Lý do tại sao tôi đang sử dụng bash trước khi mong đợi là vì tôi đã sử dụng menu tôi có thể chọn đơn vị nào để kết nối.

Cảm ơn


49
vui lòng xem dòng đầu tiên: Đối với những người muốn trả lời rằng tôi nên sử dụng các khóa SSH, vui lòng kiêng
Tối đa

54
Tôi sẽ chỉnh sửa dòng đầu tiên của bạn để thân thiện hơn một chút. Bạn có thể xem xét một cái gì đó như "Do các ràng buộc, đơn giản là tôi không thể sử dụng các khóa SSH, tôi phải tìm cách để nó hoạt động với mong đợi". Bạn nên mong đợi rằng mọi người có thể tò mò một cách tự nhiên tại sao bạn không sử dụng khóa và chỉ đang cố gắng trở nên hữu ích :) @Ignacio không đề nghị bạn sử dụng chúng, anh ta chỉ đơn giản xác nhận nó là một hạn chế và không phải là một sự giám sát.
Tim Post

Tôi sẽ cố gắng sử dụng kermit trong trường hợp này. Nó có một ngôn ngữ kịch bản rất mạnh mẽ columbia.edu/kermit/skermit.html#scripts
f3xy

Câu trả lời:


86

Trộn bash và mong đợi không phải là một cách tốt để đạt được hiệu quả mong muốn. Tôi chỉ cố gắng sử dụng Mong đợi:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
#use correct prompt
set prompt ":|#|\\\$"
interact -o -nobuffer -re $prompt return
send "my_password\r"
interact -o -nobuffer -re $prompt return
send "my_command1\r"
interact -o -nobuffer -re $prompt return
send "my_command2\r"
interact

Giải pháp mẫu cho bash có thể là:

#!/bin/bash
/usr/bin/expect -c 'expect "\n" { eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com; interact }'

Điều này sẽ chờ nhập và tương tác trở lại (trong giây lát) phiên tương tác.


1
nó hoạt động rất tốt, cảm ơn Nếu tôi muốn nhập lệnh sau khi tôi đăng nhập qua SSH, tôi cần phải làm gì?
Tối đa

Tập lệnh này sẽ trả về trình bao không hoạt động với người dùng đã đăng nhập. Tôi không hiểu câu hỏi. Nếu bạn hoàn toàn muốn sử dụng cùng một tập lệnh trong bash, hãy nhìn vào mục đã chỉnh sửa.
Piotr Król

Giống như cách tôi gửi mật khẩu khi được nhắc, tôi muốn gửi các lệnh hệ thống sau khi đăng nhập.
Tối đa

Mã Samlple đã được thêm vào để đăng ở trên. Tất nhiên, điều này sẽ hoạt động cho đến khi my_commandX không thay đổi dấu nhắc trả về, nếu điều này xảy ra thì nên thay đổi dấu nhắc.
Piotr Król

@pietrushnic bạn có thể giải thích một chút lý do tại sao sử dụng "tương tác -o -nobuffer -re $ prompt return", thay vì "mong đợi $ prompt" không? cái thứ hai có vẻ được sử dụng phổ biến hơn ..
Richard

53

Cách dễ nhất là sử dụng sshpass . Điều này có sẵn trong repos Ubuntu / Debian và bạn không phải đối phó với việc tích hợp kỳ vọng với bash.

Một ví dụ:

sshpass -p<password> ssh <arguments>
sshpass -ptest1324 ssh user@192.168.1.200 ls -l /tmp

Lệnh trên có thể dễ dàng tích hợp với tập lệnh bash.

Lưu ý: Vui lòng đọc phần Xem xét bảo mậtman sshpass để hiểu đầy đủ về ý nghĩa bảo mật.


Tôi không biết nếu đó là một giải pháp tốt, nhưng nó chắc chắn đơn giản hóa rất nhiều. Cảm ơn
erikbwork

9
Rất nguy hiểm từ góc độ bảo mật - các đối số dòng lệnh có thể được đọc bởi bất kỳ quá trình nào khác trên hệ thống. Có thể ghi đè lên chúng và hy vọng sshpassthực hiện được điều đó, nhưng ngay cả sau đó vẫn có một khoảng thời gian trong khi nó vẫn bắt đầu trước khi có thể làm điều đó khi mật khẩu có sẵn cho bất kỳ / mọi quá trình để xem.
Charles Duffy

1
@CharlesDuffy Tất nhiên, bạn đúng. sshpassđược sử dụng trong một kịch bản trong đó bạn có các tập lệnh kiểm tra đơn giản thực thi trong môi trường mạng cục bộ nơi bảo mật không phải là mối quan tâm hàng đầu. Trong thực tế, có một phần trong man sshpassđó toàn bộ phần về Cân nhắc bảo mật được giải thích. Đã thêm điều này để trả lời, Cảm ơn.
dotnix

@ erikb85 Thông thường, một gói làm tất cả những thứ bẩn thỉu cho bạn, nhưng, trong mọi trường hợp, các tập lệnh này được xây dựng chỉ cho việc sử dụng đó, sau đó sẽ TỐT HƠN hơn là thêm nội dung của riêng bạn. Nhận xét này là về việc không phát minh lại bánh xe. Đối phó với những thứ khó khăn chỉ khi chưa có người đối phó với nó. sshpass nó là một chức năng tốt.
m3nda

2
Để đầy đủ, tôi đề cập rằng "man sshpass" cung cấp các cảnh báo bảo mật phù hợp cho người dùng tiềm năng, chỉ ra rằng "-p" là cách ít an toàn nhất để sử dụng nó và cung cấp tùy chọn "-e" để lấy mật khẩu qua biến môi trường , mà ít nhất giữ nó ra khỏi dòng lệnh.
Ron Burk

22

Thêm lệnh mong đợi 'tương tác' ngay trước EOD của bạn:

#!/bin/bash

read -s PWD

/usr/bin/expect <<EOD
spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com
expect "password"
send "$PWD\n" 
interact
EOD
echo "you're out"

Điều này sẽ cho phép bạn tương tác với máy từ xa cho đến khi bạn đăng xuất. Sau đó, bạn sẽ trở lại trong bash.


Nó đi vào và đi ra ngoài ngay lập tức. "Bạn ra ngoài" được in.
Emmanuel

8
Tôi đã thay thế "tương tác" và "EOD" bằng "mong đợi eof" và nó hoạt động với tôi. Đây là trên máy Mac.
Emmanuel

2
Không có câu trả lời nào trên trang này có hiệu quả với tôi nhưng đề nghị sử dụng của @ Emmanuel đã expect eofgiải quyết vấn đề.
moertel

Loại bỏ 'từ usr@$myhost.example.com'và nó sẽ làm việc. Và có lẽ bạn cần phải thay thế \nbằng \r, nhưng YMMV
Tino

20

Sau khi tìm kiếm một câu trả lời cho câu hỏi trong nhiều tháng, cuối cùng tôi cũng tìm được một giải pháp thực sự tốt nhất: viết một kịch bản đơn giản.

#!/usr/bin/expect

set timeout 20

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

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

Đặt nó vào /usr/bin/exp, sau đó bạn có thể sử dụng:

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

Làm xong!


expect "assword:"ý bạn là expect "password:"sao
người dùng

1
@user "assword"sẽ khớp cả hai Passwordpassword.
Ferdinand.kraft

8

Cũng đảm bảo sử dụng

send -- "$PWD\r" 

thay vào đó, vì mật khẩu bắt đầu bằng dấu gạch ngang (-) sẽ thất bại.

Ở trên sẽ không giải thích một chuỗi bắt đầu bằng dấu gạch ngang như là một tùy chọn cho lệnh gửi.


8

Một kịch bản mong đợi đơn giản

Remotelogin.Ex

    #!/usr/bin/expect
    set user [lindex $argv 1]
    set ip [lindex $argv 0]
    set password [lindex $argv 2]
    spawn ssh $user@$ip
    expect "password"
    send "$password\r"
    interact

Thí dụ:

    ./Remotelogin.exp <ip> <user name> <password>

7

Sử dụng công cụ trợ giúp fd0ssh(từ hxtools, không phải pmt), nó hoạt động mà không phải mong đợi một lời nhắc cụ thể từ chương trình ssh.


Điều đó thật tuyệt! Hơi khó để làm cho nó chạy (ít nhất là trong máy chủ Ubuntu) nhưng hoạt động trơn tru! Cấu hình chúng tôi đã thực hiện: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port user@yourserver.com & CẢM ƠN!
JP Illanes

1
An toàn hơn nhiều so với việc truyền mật khẩu trên dòng lệnh sshpass.
Charles Duffy

5

Một cách khác mà tôi thấy hữu ích khi sử dụng tập lệnh mong đợi nhỏ từ tập lệnh bash là như sau.

...
bash-script start
bash-commands
...
expect - <<EOF 
spawn your-command-here
expect "some-pattern"
send "some-command"
...
...
EOF
...
more bash commands
...

Điều này hoạt động vì ...If the string "-" is supplied as a filename, standard input is read instead...


Bạn không cần -ở đây, vì expectđọc stdintheo mặc định nếu bạn gọi nó mà không cần đối số. Tuy nhiên, nó rất hữu ích nếu bạn muốn chạy nó một cách tương tác mà không có dấu nhắc lệnh ( expectvs. expect -) hoặc trong trường hợp bạn làm một cái gì đó giống như expect -f "$@"trong đó đối số đầu tiên sẽ là một tệp, ngay cả khi nó trông giống như một tùy chọn (bắt đầu bằng -). Trong trường hợp đó, nếu $1(tệp đã cho) là -cái này đọc từ stdin.
Tino

1

sshpassbị hỏng nếu bạn cố gắng sử dụng nó trong mục tiêu xây dựng Sublime Text, bên trong Makefile. Thay vì sshpassbạn có thể sử dụng passh: https://github.com/clarkwang/passh

Với sshpassbạn sẽ làm:

sshpass -p pa$$word ssh user@host

Với passhbạn sẽ làm:

passh -p pa$$word ssh user@host

Lưu ý: Đừng quên sử dụng -o StrictHostKeyChecking=no, nếu không, kết nối sẽ bị treo trong lần đầu tiên bạn sử dụng. Ví dụ:

passh -p pa$$word ssh -o StrictHostKeyChecking=no user@host

Người giới thiệu:

  1. Gửi lệnh cho mật khẩu không hoạt động bằng cách sử dụng tập lệnh mong đợi trong kết nối ssh
  2. https://askubfox.com/questions/87449/how-to-disable-strict-host-key-checking-in-ssh
  3. https://linuxcommando.blogspot.com/2008/10/how-to-disable-ssh-host-key-checking.html
  4. /server/330503/scp-without- Unknown-hosts-check
  5. https: //debian-adftime.org/article/587/pam_mount_and_sshfs_with_password_authentication
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.