ใช้ Expect ในสคริปต์ Bash เพื่อระบุรหัสผ่านสำหรับคำสั่ง SSH


131

ฉันพยายามใช้ Expect ในสคริปต์ Bash เพื่อระบุรหัสผ่าน SSH การให้รหัสผ่านใช้งานได้ แต่ฉันไม่ได้อยู่ในเซสชัน SSH เท่าที่ควร มันย้อนกลับไปสู่ ​​Bash

สคริปต์ของฉัน:

#!/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"

ผลลัพธ์ของสคริปต์ของฉัน:

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

ฉันต้องการมีเซสชัน SSH ของฉันและเมื่อฉันออกเท่านั้นเพื่อกลับไปที่สคริปต์ Bash ของฉัน

เหตุผลที่ฉันใช้ Bash before Expect ก็เพราะว่าฉันต้องใช้เมนู ฉันสามารถเลือกหน่วย / อุปกรณ์ที่จะเชื่อมต่อได้

สำหรับผู้ที่ต้องการตอบกลับว่าฉันควรใช้คีย์ SSH โปรดงดเว้น


49
โปรดดูบรรทัดแรก: สำหรับผู้ที่ต้องการตอบกลับว่าฉันควรใช้คีย์ SSH โปรดงด
สูงสุด

54
ฉันจะแก้ไขบรรทัดแรกของคุณให้เป็นมิตรกว่านี้ คุณอาจพิจารณาบางอย่างเช่น "เนื่องจากข้อ จำกัด ฉันไม่สามารถใช้คีย์ SSH ได้ฉันต้องหาวิธีทำให้มันทำงานได้ตามที่คาดหวัง" คุณควรคาดหวังว่าคนทั่วไปอาจสงสัยว่าทำไมคุณถึงไม่ใช้กุญแจและพยายามทำตัวให้เป็นประโยชน์ :) @Ignacio ไม่ได้แนะนำให้คุณใช้มันเขาแค่ยืนยันว่ามันเป็นข้อ จำกัด ไม่ใช่การควบคุมดูแล
Tim Post

ฉันจะลองใช้มิตในกรณีนี้ มีภาษาสคริปต์ที่แข็งแกร่งมากcolumbia.edu/kermit/skermit.html#scripts
f3xy

คำตอบ:


86

การผสม Bash และ Expect ไม่ใช่วิธีที่ดีในการบรรลุผลตามที่ต้องการ ฉันจะพยายามใช้ Expect เท่านั้น:

#!/usr/bin/expect
eval spawn ssh -oStrictHostKeyChecking=no -oCheckHostIP=no usr@$myhost.example.com

# Use the 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

วิธีแก้ปัญหาตัวอย่างสำหรับ bash อาจเป็น:

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

การดำเนินการนี้จะรอEnterและกลับไปที่เซสชันแบบโต้ตอบ (สักครู่)


1
มันใช้งานได้ดีขอบคุณ จะเกิดอะไรขึ้นถ้าฉันต้องการพิมพ์คำสั่งเมื่อฉันเข้าสู่ระบบผ่าน SSH ฉันต้องทำอย่างไร?
สูงสุด

สคริปต์นี้ควรส่งคืนเชลล์ที่ไม่ใช้งานร่วมกับผู้ใช้ที่ล็อกอิน ฉันไม่เข้าใจคำถาม หากคุณต้องการใช้สคริปต์เดียวกันใน bash ให้ดูที่รายการที่แก้ไข
Piotr Król

เช่นเดียวกับที่ฉันส่งรหัสผ่านเมื่อได้รับแจ้งฉันต้องการส่งคำสั่งระบบเมื่อเข้าสู่ระบบ
สูงสุด

เพิ่มโค้ด Samlple ในโพสต์ด้านบน แน่นอนว่าสิ่งนี้จะใช้ได้จนกว่า my_commandX จะไม่เปลี่ยนพรอมต์ที่ส่งคืนหากสิ่งนี้เกิดขึ้นควรเปลี่ยนตัวแปรพร้อมต์
Piotr Król

@pietrushnic คุณช่วยอธิบายหน่อยได้ไหมว่าทำไมจึงใช้ "โต้ตอบ -o -nobuffer -re $ prompt return" แทนที่จะเป็น "expect $ prompt" อันหลังดูใช้บ่อยกว่า ..
Richard

53

วิธีที่ง่ายที่สุดคือการใช้sshpass สิ่งนี้มีอยู่ในที่เก็บUbuntu / Debianและคุณไม่จำเป็นต้องจัดการกับการรวมความคาดหวังกับ Bash

ตัวอย่าง:

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

คำสั่งดังกล่าวสามารถรวมเข้ากับสคริปต์ Bash ได้อย่างง่ายดาย

หมายเหตุ:โปรดอ่านหัวข้อข้อควรพิจารณาด้านความปลอดภัยman sshpassเพื่อความเข้าใจอย่างถ่องแท้เกี่ยวกับผลกระทบด้านความปลอดภัย


ฉันไม่รู้ว่ามันเป็นทางออกที่ดีหรือเปล่า แต่มันช่วยให้ง่ายขึ้นมาก ขอบคุณ
erikbwork

9
อันตรายมากจากมุมมองด้านความปลอดภัย - อาร์กิวเมนต์บรรทัดคำสั่งสามารถอ่านได้โดยกระบวนการอื่น ๆ ในระบบ เป็นไปได้ที่จะเขียนทับพวกเขาและหวังว่าsshpassจะทำได้ แต่ถึงอย่างนั้นก็ยังมีช่วงเวลาหนึ่งในขณะที่ยังคงเริ่มต้นทำงานก่อนที่จะสามารถทำได้เมื่อรหัสผ่านพร้อมใช้งานสำหรับทุกกระบวนการที่จะเห็น
Charles Duffy

1
@CharlesDuffy แน่นอนคุณพูดถูก sshpassใช้ในสถานการณ์ที่คุณมีสคริปต์ทดสอบอย่างง่ายที่ดำเนินการในสภาพแวดล้อมเครือข่ายท้องถิ่นที่ความปลอดภัยไม่ใช่ประเด็นสำคัญ ในความเป็นจริงมีส่วนman sshpassที่อธิบายทั้งหัวข้อเกี่ยวกับข้อพิจารณาด้านความปลอดภัย เพิ่มสิ่งนี้เพื่อตอบขอบคุณ
dotnix

@ erikb85 โดยปกติแล้วแพคเกจจะทำสิ่งสกปรกทั้งหมดให้คุณ แต่ในทุกกรณีสคริปต์เหล่านี้สร้างขึ้นเพื่อการใช้งานนั้นโดยเฉพาะจะดีกว่าการเพิ่มสิ่งของของคุณเอง ความคิดเห็นนี้เกี่ยวกับอย่าสร้างล้อใหม่ จัดการกับเรื่องยาก ๆ ก็ต่อเมื่อยังไม่มีใครจัดการกับมัน sshpass มันเป็นฟังก์ชั่นที่ดี
m3nda

2
เพื่อความสมบูรณ์ฉันพูดถึงว่า "man sshpass" ส่งคำเตือนด้านความปลอดภัยที่เหมาะสมให้กับผู้ใช้ที่คาดหวังชี้ให้เห็นว่า "-p" เป็นวิธีที่ปลอดภัยน้อยที่สุดในการใช้งานและเสนอตัวเลือก "-e" สำหรับการรับรหัสผ่านผ่านตัวแปรสภาพแวดล้อม ซึ่งอย่างน้อยก็ทำให้ไม่อยู่ในบรรทัดคำสั่ง
Ron Burk

22

เพิ่มคำสั่ง Expect 'โต้ตอบ' ก่อน EOD ของคุณ:

#!/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"

สิ่งนี้จะช่วยให้คุณสามารถโต้ตอบกับเครื่องระยะไกลได้จนกว่าคุณจะออกจากระบบ จากนั้นคุณจะกลับมาที่ Bash


มันเข้าไปและกลับออกไปทันที "คุณไม่อยู่" ถูกพิมพ์ออกมา
Emmanuel

8
ฉันได้แทนที่ "โต้ตอบ" และ "EOD" ด้วย "คาดว่าจะได้รับ eof" และได้ผลสำหรับฉัน นี่คือบน Mac
Emmanuel

2
ไม่มีคำตอบใดในหน้านี้ที่ใช้ได้ผลสำหรับฉัน แต่คำแนะนำของ @MManuel ที่จะใช้expect eofแก้ไขปัญหาได้
moertel

ถอด'จากusr@$myhost.example.com'และมันควรจะทำงาน และบางทีคุณอาจต้องแทนที่\nด้วย\rแต่ YMMV
Tino

20

หลังจากหาคำตอบสำหรับคำถามมาหลายเดือนในที่สุดฉันก็พบทางออกที่ดีที่สุดนั่นคือการเขียนสคริปต์ง่ายๆ

#!/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

ใส่ไป/usr/bin/expแล้วคุณสามารถใช้:

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

ทำ!


expect "assword:"คุณหมายถึงexpect "password:"อะไร?
ผู้ใช้

1
@user "assword"จะจับคู่ทั้งสองPasswordและpassword.
Ferdinand.kraft

8

ตรวจสอบให้แน่ใจว่าได้ใช้

send -- "$PWD\r"

แทนเนื่องจากรหัสผ่านที่ขึ้นต้นด้วยเครื่องหมายขีด (-) จะล้มเหลว

ข้างต้นจะไม่ตีความสตริงที่ขึ้นต้นด้วยขีดเป็นตัวเลือกของคำสั่ง send


8

สคริปต์คาดหวังง่ายๆ:

ไฟล์Remotelogin.exp

    #!/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

ตัวอย่าง:

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

7

ใช้เครื่องมือตัวช่วยfd0ssh(จาก hxtools ไม่ใช่ pmt) ใช้งานได้โดยไม่ต้องคาดหวังการแจ้งเตือนใด ๆ จากsshโปรแกรม


นี่มันเยี่ยมมาก! มันค่อนข้างยากที่จะทำให้มันทำงาน (อย่างน้อยก็ในเซิร์ฟเวอร์ ubuntu) แต่ทำงานได้อย่างราบรื่น! การกำหนดค่าที่เราทำ: echo "yoursshpass" | fd0ssh ssh -c -L$port:$ip:$remote_port user@yourserver.com & ขอบคุณ!
JP Illanes

1
ปลอดภัยกว่าการส่งรหัสผ่านในบรรทัดคำสั่งอย่างsshpassมาก
Charles Duffy

5

อีกวิธีหนึ่งที่ฉันพบว่ามีประโยชน์ในการใช้สคริปต์ Expect ขนาดเล็กจากสคริปต์ Bash มีดังนี้

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

สิ่งนี้ได้ผลเพราะ ...If the string "-" is supplied as a filename, standard input is read instead...


คุณไม่จำเป็นต้องใช้-ที่นี่เนื่องจากexpectอ่านจากstdinค่าเริ่มต้นหากคุณเรียกใช้โดยไม่มีการโต้แย้ง อย่างไรก็ตามจะมีประโยชน์หากคุณต้องการเรียกใช้แบบโต้ตอบโดยไม่ใช้พรอมต์คำสั่ง ( expectเทียบกับexpect -) หรือในกรณีที่คุณทำบางอย่างเช่นexpect -f "$@"โดยที่อาร์กิวเมนต์แรกจะเป็นไฟล์แม้ว่าจะดูเหมือนเป็นตัวเลือก (ขึ้นต้นด้วย-) ในกรณีที่ถ้า$1(ที่กำหนดไฟล์) เป็นนี้อ่านจาก- stdin
Tino

1

sshpassเสียหากคุณพยายามใช้ภายในเป้าหมายการสร้างข้อความ Sublimeภายใน Makefile แทนที่จะsshpassคุณสามารถใช้passh: https://github.com/clarkwang/passh

กับsshpassคุณจะทำ:

sshpass -p pa$$word ssh user@host

กับpasshคุณจะทำ:

passh -p pa$$word ssh user@host

หมายเหตุ: -o StrictHostKeyChecking=noอย่าลืมที่จะใช้ มิฉะนั้นการเชื่อมต่อจะค้างในครั้งแรกที่คุณใช้งาน ตัวอย่างเช่น:

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

อ้างอิง:

  1. ส่งคำสั่งสำหรับรหัสผ่านไม่ทำงานโดยใช้สคริปต์ Expect ในการเชื่อมต่อ SSH
  2. ฉันจะปิดใช้งานการตรวจสอบคีย์โฮสต์ที่เข้มงวดใน ssh ได้อย่างไร
  3. วิธีปิดใช้งานการตรวจสอบคีย์โฮสต์ SSH
  4. scp โดยไม่ต้องตรวจสอบ known_hosts
  5. pam_mount และ sshfs ด้วยการตรวจสอบรหัสผ่าน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.