ประโยชน์ของการไม่จัดสรรเทอร์มินัลใน ssh คืออะไร?


66

ทุกครั้งที่ฉันจะทำบางสิ่งบางอย่างเช่น

ssh user@host sudo thing

และฉันได้รับการเตือนว่า ssh ไม่ได้จัดสรรหลอกโดยค่าเริ่มต้น ทำไมไม่เป็นเช่นนั้น? สิ่งที่เป็นประโยชน์ผมจะสูญเสียถ้าฉัน aliased sshเพื่อssh -t?


1
> ฉันได้รับการเตือนว่า ssh ไม่จัดสรร psuedo-tty เกิดอะไรขึ้น มันจะเพิ่มคำถามให้เข้าใจว่าปัญหาคืออะไร
อากาศ

5
@ แอร์ไม่มีปัญหาฉันพยายามแก้ไข มีทางเลือกในการปรับใช้ ssh ที่ฉันพยายามเข้าใจ คำถามนั้นชัดเจนมากและคำตอบของ Andrew B ตอบคำถามอย่างชัดเจน คำตอบสามารถสรุปได้ดังนี้: การรันssh -tอยู่เสมอไม่ดีเพราะอาจทำให้คำสั่งบางคำสั่งแตกในลักษณะที่แปลก ขณะที่การรันคำสั่งที่ต้องการ PTY โดยไม่มีผลลัพธ์จะทำให้เกิดข้อความแสดงข้อผิดพลาดที่ชัดเจนว่าคุณต้องการเทอร์มินัล
Chas Owens

คำตอบ:


73

แตกต่างหลักคือแนวคิดของการติดต่อสื่อสาร มันคล้ายกับการเรียกใช้คำสั่งในเครื่องของสคริปต์และพิมพ์ออกมาด้วยตนเอง มันแตกต่างกันที่คำสั่งระยะไกลจะต้องเลือกค่าเริ่มต้นและไม่ใช่แบบโต้ตอบที่ปลอดภัยที่สุด (และมักจะซื่อสัตย์ที่สุด)

STDIN

  • หากมีการจัดสรร PTY แอปพลิเคชั่นสามารถตรวจจับสิ่งนี้และรู้ว่าปลอดภัยที่จะแจ้งให้ผู้ใช้รับข้อมูลเพิ่มเติมโดยไม่ทำลาย มีหลายโปรแกรมที่จะข้ามขั้นตอนในการกระตุ้นให้ผู้ใช้ป้อนข้อมูลหากไม่มีเทอร์มินัลอยู่และนั่นเป็นสิ่งที่ดี มันจะทำให้สคริปต์ที่จะแขวนมิฉะนั้นโดยไม่จำเป็น
  • ข้อมูลของคุณจะถูกส่งไปยังเซิร์ฟเวอร์ระยะไกลในช่วงระยะเวลาของคำสั่ง ซึ่งรวมถึงลำดับการควบคุม ในขณะที่ตัวCtrl-cแบ่งจะทำให้เกิดการวนซ้ำบนคำสั่ง ssh เพื่อแยกทันทีลำดับการควบคุมของคุณจะถูกส่งไปยังเซิร์ฟเวอร์ระยะไกลแทน สิ่งนี้ส่งผลให้ต้อง "ค้อน" การกดแป้นพิมพ์เพื่อให้แน่ใจว่าจะมาถึงเมื่อการควบคุมออกจากคำสั่ง ssh แต่ก่อนที่คำสั่ง ssh ถัดไปจะเริ่มขึ้น

ฉันจะระมัดระวังไม่ให้ใช้ssh -tสคริปต์ที่ไม่ต้องดูแลเช่น crons เชลล์แบบไม่มีการโต้ตอบที่ขอให้คำสั่งรีโมตทำงานแบบโต้ตอบสำหรับอินพุตกำลังร้องขอปัญหาทุกชนิด

คุณสามารถทดสอบการมีอยู่ของเทอร์มินัลในเชลล์สคริปต์ของคุณเอง หากต้องการทดสอบ STDIN ด้วย bash เวอร์ชันใหม่:

# fd 0 is STDIN
[ -t 0 ]; echo $?

STDOUT

  • เมื่อ aliasing sshเพื่อssh -tคุณสามารถคาดหวังที่จะได้รับผลตอบแทนการขนส่งพิเศษในสายของคุณสิ้นสุดลง อาจไม่ปรากฏให้คุณเห็น แต่มีอยู่ มันจะแสดงขึ้นเป็นเมื่อประปา^M cat -eจากนั้นคุณต้องใช้ความพยายามเพิ่มเติมเพื่อให้มั่นใจว่ารหัสควบคุมนี้ไม่ได้รับการกำหนดให้กับตัวแปรของคุณโดยเฉพาะอย่างยิ่งถ้าคุณกำลังจะแทรกผลลัพธ์นั้นลงในฐานข้อมูล
  • นอกจากนี้ยังมีความเสี่ยงที่โปรแกรมจะถือว่าพวกเขาสามารถแสดงผลลัพธ์ที่ไม่เป็นมิตรกับการเปลี่ยนเส้นทางไฟล์ โดยปกติหากคุณต้องการเปลี่ยนเส้นทาง STDOUT ไปที่ไฟล์โปรแกรมจะรับรู้ว่า STDOUT ของคุณไม่ใช่เทอร์มินัลและไม่ต้องใส่รหัสสีใด ๆ หากการเปลี่ยนเส้นทาง STDOUT มาจากเอาต์พุตของไคลเอ็นต์ sshและมี PTY ที่เชื่อมโยงกับรีโมตปลายทางของไคลเอนต์โปรแกรมระยะไกลไม่สามารถแยกความแตกต่างได้และคุณจะจบลงด้วยเทอร์มินัลขยะในไฟล์เอาต์พุตของคุณ การเปลี่ยนทิศทางเอาต์พุตไปยังไฟล์บนรีโมตปลายทางของการเชื่อมต่อควรยังคงทำงานตามที่คาดไว้

นี่คือการทดสอบทุบตีเช่นเดียวกับก่อนหน้านี้ แต่สำหรับ STDOUT:

# fd 1 is STDOUT
[ -t 1 ]; echo $?

แม้ว่าคุณจะสามารถแก้ไขปัญหาเหล่านี้ได้ แต่คุณจะลืมออกแบบสคริปต์รอบตัวพวกเขาอย่างหลีกเลี่ยงไม่ได้ เราทุกคนทำในบางจุด สมาชิกในทีมของคุณอาจไม่ตระหนัก / จำไว้ว่านามแฝงนี้อยู่ในสถานที่ซึ่งจะสร้างปัญหาให้คุณเมื่อพวกเขาเขียนสคริปต์ที่ใช้นามแฝงของคุณ

aliasing sshจะssh -tเป็นอย่างมากกรณีที่คุณจะได้รับการละเมิดหลักการออกแบบของความประหลาดใจอย่างน้อย ; ผู้คนจะประสบกับปัญหาที่พวกเขาไม่คาดหวังและอาจไม่เข้าใจสิ่งที่ทำให้พวกเขา


9
เกือบหนึ่งได้รับความประทับใจที่ผมเคยทำงานในทีมที่มีการทำแบบนี้ ...
แอนดรู B

ในขอบเขตที่ครอบคลุมโดยคำตอบนี้มันยอดเยี่ยม แต่คำถามมีขอบเขตที่กว้างขึ้นโดยพื้นฐานแล้วต้องการทราบความแตกต่างทั้งหมด (สิ่งที่คาดหวัง) ข้อมูลเพิ่มเติม: ที่ระดับกระบวนการ -t จะ FIRST จัดสรร tty และจากนั้นเรียกใช้เชลล์ (ตามวิธีการจัดหา / etc / profile และ ~ / .bash_profile) และเรียกใช้คำสั่ง หากไม่มี -t, ssh จะเข้าแทนที่ไฟล์ env ที่แตกต่างกัน (/etc/bash.bashrc จากนั้น ~ / .bashrc) จากนั้นเรียกใช้คำสั่งของคุณ ซึ่งหมายความว่าคุณสามารถเห็นพฤติกรรมที่แตกต่างกันในแต่ละอย่าง: $ PATH ที่สั้นลงอาจเป็นข้อผิดพลาด 'unary' ทุบตีเพราะ var ENV ที่คุณสันนิษฐานว่าไม่ได้อยู่ที่นั่น ...
Scott Prive

@Crossfit เราครอบคลุมหัวข้อเชลล์ล็อกอินและไม่ใช่ในความคิดเห็นของคำตอบอื่น แต่เราไม่ได้วิเคราะห์ความแตกต่างด้านสิ่งแวดล้อมอย่างละเอียดเพราะ OP ได้พิจารณาคำถามที่ตอบสนองความต้องการเฉพาะของพวกเขาแล้ว โปรดเพิ่มรายละเอียดที่คุณเห็นห้องว่างเพราะอาจช่วยผู้อื่นที่เข้ามาถามคำถามนี้
Andrew B

33

อักขระเลี่ยง SSH และการถ่ายโอนไฟล์ไบนารี

ข้อดีอย่างหนึ่งที่ยังไม่ได้รับการกล่าวถึงในคำตอบอื่น ๆ ก็คือว่าเมื่อการดำเนินงานโดยไม่ต้องหลอกขั้ว , จุ๊ตัวหนีเช่น~Cจะได้รับการสนับสนุน ; สิ่งนี้ทำให้ปลอดภัยสำหรับโปรแกรมที่จะถ่ายโอนไฟล์ไบนารีซึ่งอาจมีลำดับเหล่านี้

พิสูจน์แนวคิด

คัดลอกไฟล์ไบนารีโดยใช้เทอร์มินัลหลอก:

$ ssh -t anthony@remote_host 'cat /usr/bin/free' > ~/free
Connection to remote_host closed.

คัดลอกไฟล์ไบนารีโดยไม่ใช้เทอร์มินัลหลอก:

$ ssh anthony@remote_host 'cat /usr/bin/free' > ~/free2

ไฟล์สองไฟล์ไม่เหมือนกัน:

$ diff ~/free*
Binary files /home/anthony/free and /home/anthony/free2 differ

สิ่งที่ถูกคัดลอกด้วยเทอร์มินัลเทียมหลอกเสียหาย:

$ chmod +x ~/free*
$ ./free
Segmentation fault

ในขณะที่คนอื่นไม่:

$ ./free2
             total       used       free     shared    buffers     cached
Mem:       2065496    1980876      84620          0      48264    1502444
-/+ buffers/cache:     430168    1635328
Swap:      4128760        112    4128648

ถ่ายโอนไฟล์ผ่าน SSH

สิ่งนี้สำคัญอย่างยิ่งสำหรับโปรแกรมเช่นscpหรือrsyncที่ใช้ SSH สำหรับการถ่ายโอนข้อมูล นี้อธิบายรายละเอียดของวิธีการทำงานของโปรโตคอล SCPอธิบายถึงวิธีการโพรโทคอ SCP ประกอบด้วยส่วนผสมของข้อความต้นฉบับเดิมโปรโตคอลและข้อมูลแฟ้มไบนารี


OpenSSH ช่วยปกป้องคุณจากตัวคุณเอง

เป็นที่น่าสังเกตว่าถึงแม้ว่า-tจะมีการใช้การตั้งค่าสถานะsshไคลเอนต์OpenSSH จะปฏิเสธที่จะจัดสรรเทอร์มินัลหลอกถ้าตรวจพบว่าstdinสตรีมไม่ใช่เทอร์มินัล:

$ echo testing | ssh -t anthony@remote_host 'echo $TERM'
Pseudo-terminal will not be allocated because stdin is not a terminal.
dumb

คุณยังสามารถบังคับให้ไคลเอ็นต์ OpenSSH จัดสรรเทอร์มินัลเทียมด้วย-tt:

$ echo testing | ssh -tt anthony@remote_host 'echo $TERM'
xterm

ไม่ว่าในกรณีใดมัน (สมเหตุสมผล) ไม่สนใจว่าจะถูกเปลี่ยนเส้นทางstdoutหรือstderr:

$ ssh -t anthony@remote_host 'echo $TERM' >| ssh_output
Connection to remote_host closed.

2
นั่นเป็นประเด็นที่น่าสนใจมากที่ฉันไม่ได้พิจารณาขอบคุณสำหรับการเพิ่มคำตอบนี้!
เจนนี่ D

4

บนรีโมตโฮสต์เราต้องทำการตั้งค่านี้:

/etc/sudoers
...
Defaults requiretty

โดยไม่ต้อง sudo

$ ssh -T user@host echo -e 'foo\\nbar' | cat -e
foo$
bar$

และด้วย sudo

$ ssh -T user@host sudo echo -e 'foo\\nbar' | cat -e
sudo: sorry, you must have a tty to run sudo

ด้วย sudo เราได้รับผลตอบแทนพิเศษ

$ ssh -t user@host sudo echo -e 'foo\\nbar' | cat -e
foo^M$
      bar^M$
            Connection to localhost closed.

วิธีแก้ไขคือปิดการใช้งานการขึ้นบรรทัดใหม่แปลเป็น carline return-newlineด้วยstty -onlcr

$ ssh -t user@host stty -onlcr\; sudo echo -e 'foo\\nbar' | cat -e
foo$
    bar$
        Connection to localhost closed.

1
ดี แต่ผลลัพธ์จะถูกเยื้อง /: คุณรู้หรือไม่ว่าคุณสามารถรับคืนอัตโนมัติ (เหมือนยูนิกซ์) ได้หรือไม่?
Boop

1

คิดถึงความเข้ากันได้แบบย้อนหลัง

โหมดหลัก 2 โหมดของ ssh คือการล็อกอินแบบโต้ตอบด้วย tty และระบุคำสั่งโดยไม่มี tty เนื่องจากเป็นความสามารถที่แน่นอนของrloginและrshตามลำดับ ssh ต้องการให้ superset of rlogin/ rshfeatures ประสบความสำเร็จแทน

ดังนั้นค่าเริ่มต้นจะถูกตัดสินก่อนที่จะเกิด SSH ชุดค่าผสมเช่น "ฉันต้องการระบุคำสั่งและรับ tty" ต้องเข้าถึงด้วยตัวเลือกใหม่ จะดีใจที่อย่างน้อยเราก็มีrshตัวเลือกว่าตอนนี้ไม่เหมือนเมื่อเราได้ใช้ เราไม่แลกเปลี่ยนคุณลักษณะที่มีประโยชน์ใด ๆ เพื่อรับการเชื่อมต่อที่เข้ารหัส เรามีคุณสมบัติโบนัส!


0

จากman ssh:

 -t      Force pseudo-tty allocation.  This can be used to execute arbi-
         trary screen-based programs on a remote machine, which can be
         very useful, e.g. when implementing menu services.  Multiple -t
         options force tty allocation, even if ssh has no local tty.

สิ่งนี้ช่วยให้คุณได้รับ "เชลล์" เรียงลำดับไปยังเซิร์ฟเวอร์ระยะไกล สำหรับเซิร์ฟเวอร์ที่ไม่ให้สิทธิ์การเข้าถึงเชลล์ แต่อนุญาตให้ใช้ SSH (เช่น Github เป็นตัวอย่างที่ทราบสำหรับการเข้าถึง SFTP) การใช้แฟล็กนี้จะทำให้เซิร์ฟเวอร์ปฏิเสธการเชื่อมต่อของคุณ

เชลล์ยังมีตัวแปรสภาพแวดล้อมทั้งหมดของคุณ (เช่น$PATH) ดังนั้นการเรียกใช้งานสคริปต์โดยทั่วไปจำเป็นต้องใช้ tty เพื่อทำงาน


1
นี่ไม่ได้ตอบคำถาม ฉันรู้วิธีจัดสรรหลอกแล้ว ฉันอยากรู้ว่าทำไมฉันไม่ควรจัดสรรให้เสมอ
Chas Owens

1
@ Chas.Owens เพราะในขณะที่ฉันชี้ให้เห็นในคำตอบเซิร์ฟเวอร์ SSH บางอย่างไม่อนุญาตให้เข้าถึง tty และมันจะลดลงการเชื่อมต่อถ้าคุณขอหนึ่งจากเซิร์ฟเวอร์
นาธาน C

5
ฉันคิดว่าคุณอาจทำให้คำศัพท์ของคุณสับสน ไม่ใช่เปลือกเพราะ PTY เชื่อมโยงกับมัน โดยทั่วไปมีสามประเภทของเปลือก: non-interactive, และinteractive เป็นคุณสมบัติเพิ่มเติมของอีกสองประเภทเปลือก การเรียงสับเปลี่ยนของทั้งสามนี้จะกำหนดว่าไฟล์ใดมีแหล่งที่มาในการเข้าสู่ระบบซึ่งจะมีผลต่อวิธีการเริ่มต้นสภาพแวดล้อม (ตัวแปรตามที่คุณพูดถึง)loginlogin
แอนดรูว์ B

3
@AndrewB คุณพูดถูก ... ฉันได้เรียนรู้บางสิ่งจากคำถามนี้เช่นกัน :)
นาธาน C
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.