จะทำอัตโนมัติการเข้าสู่ระบบ VPN ที่รอรหัสโทเคนได้อย่างไร
ไคลเอนต์ VPN แบบบรรทัดคำสั่งที่ถามในเทอร์มินัลจะทำให้สคริปต์ที่ส่งเพียงรหัสผ่านผ่านท่อหยุดชะงัก ทำการตรวจสอบทั้งห้านี้ก่อนจะหันไปใช้ expect
สคริปต์ที่เริ่มไคลเอนต์ VPN ของผู้จำหน่ายจะค้างจนหมดเวลา และบันทึกแสดงว่าไคลเอนต์กำลังขอรหัสยืนยันที่ไม่มีใครพิมพ์ รหัสผ่านถูกส่งไปแล้ว ข้อสรุปที่ดูเหมือนชัดเจนคือรหัสผ่านผิด แต่ไม่ใช่ การขอรหัสเป็นการสนทนาอีกชุดบนช่องทางอีกชุด และสคริปต์ของคุณไม่เคยเปิดมัน
ทำการตรวจสอบทั้งห้าข้อด้านล่างตามลำดับ หยุดที่ข้อแรกที่ล้มเหลว เพราะทุกขั้นตอนถัดไปตั้งสมมติฐานว่าข้อก่อนหน้าถูกต้อง
การตรวจสอบ 1: ไคลเอนต์อ่านอินพุตมาตรฐานหรือไม่
ทดสอบก่อนเขียนระบบอัตโนมัติใด ๆ: ส่งความลับปลอมเข้าไปในไคลเอนต์ผ่านท่อ แล้วดูว่าเกิดอะไรขึ้น ถ้ามันพิมพ์ข้อความถามแล้วรอ แสดงว่าไม่ได้อ่านท่อ
ไคลเอนต์จำนวนมากเปิดอุปกรณ์เทอร์มินัลโดยตรง หรือปฏิเสธที่จะรับความลับจากสตรีมที่ไม่ใช่เทอร์มินัล เพื่อไม่ให้ท่อที่หลงทางรั่วรหัสผ่านได้ OpenVPN เป็นข้อยกเว้นที่บันทึกไว้ในเอกสาร เพราะ --auth-user-pass รับพาธไฟล์ ไคลเอนต์ของผู้จำหน่ายที่ขอรหัสใช้ครั้งเดียวมักไม่มีตัวเลือกที่เทียบเท่า และข้อความถามของมันกำลังรอเทอร์มินัลที่สคริปต์ของคุณไม่เคยจัดให้
การตรวจสอบ 2: โปรเซสลูกมีเทอร์มินัลหรือไม่
pty จัดสรรเทอร์มินัลให้โปรเซสลูก ซึ่งเปลี่ยนข้อความถามให้เป็นเอาต์พุตที่อ่านได้และคุณตอบตามลำดับได้
import pexpect
child = pexpect.spawn("openconnect vpn.example.net", encoding="utf-8", timeout=30)
child.expect("GROUP:")
child.sendline("staff")
child.expect("USERNAME:")
child.sendline("alice")
child.expect("PASSWORD:")
child.sendline(PASSWORD)
child.expect("Connected as", timeout=60)สตริงข้อความถามด้านบนเป็นเพียงตัวอย่าง จงคัดลอกข้อความจริงที่ไคลเอนต์ของคุณพิมพ์ รวมทั้งตัวพิมพ์เล็กพิมพ์ใหญ่และเครื่องหมายวรรคตอน ทุกการรอคอยมีเวลาจำกัด และโปรเซสลูกที่ปิดไปจะโยนข้อยกเว้นแทนการคืนสถานะ ดังนั้นจงห่อลำดับและถือว่าจุดสิ้นสุดไฟล์คือความล้มเหลว สังเกตว่าบล็อกนี้ไม่ได้ทำอะไร: โปรเซสลูกตายไปพร้อมสคริปต์ เพราะ pty ไม่ใช่กลไกการแยกตัว และ disown เป็นคำสั่งในตัวของเชลล์ที่ไม่สามารถเข้าถึงโปรเซสที่สคริปต์ของคุณสร้างขึ้น
การตรวจสอบ 3: มีอินพุตแบบไม่โต้ตอบที่รองรับหรือไม่
การขูดหน้าจอแตกหักเมื่อไคลเอนต์อัปเกรด ดังนั้นจงหาตัวเลือกที่บันทึกไว้ในเอกสารก่อน
ตรวจดูเอาต์พุตความช่วยเหลือว่ามีตัวเลือกโทเคนหรือรหัสใช้ครั้งเดียวหรือไม่ และตรวจว่าบริการยอมรับรหัสที่ต่อท้ายช่องรหัสผ่านหรือไม่ ในกรณีที่ไคลเอนต์อ่านไฟล์ข้อมูลรับรอง จงให้ไฟล์นั้นแทนการรอป้อน:
openvpn --config office.ovpn --auth-user-pass <(printf "%s\n%s\n" "$USER_NAME" "$PASSWORD")การแทนที่โปรเซสทำให้ไคลเอนต์ได้พาธที่อ่านได้บนระบบที่มี /dev/fd ความลับยังคงเป็นความลับจากมุมมองของไคลเอนต์ ดังนั้นจงเก็บมันออกจากบันทึก ประวัติเชลล์ และรายการโปรเซส ถ้าไคลเอนต์ปฏิเสธ /dev/fd หรือเปิดพาธข้อมูลรับรองมากกว่าหนึ่งครั้ง จงเขียนไฟล์จริงที่มีสิทธิ์เข้มงวดและลบมันในสคริปต์เดียวกัน
การตรวจสอบ 4: อุโมงค์จะอยู่ได้นานกว่าสคริปต์หรือไม่
โดยค่าเริ่มต้นอุโมงค์ตายไปพร้อมกระบวนการแม่ ซึ่งตรงข้ามกับสิ่งที่สคริปต์เริ่มต้นระบบต้องการ
disown -h ช่วยได้เฉพาะเมื่อคุณเริ่มไคลเอนต์เป็นงานของเชลล์ เพราะมันแก้ตารางงานของเชลล์นั้นและไม่สามารถเข้าถึงโปรเซสที่สคริปต์ของคุณสร้างผ่าน pty ตัวจัดการบริการเป็นที่อยู่ที่ดีกว่าสำหรับทุกสิ่งที่ต้องเชื่อมต่อใหม่โดยไม่มีคนเฝ้า เพราะมันรีสตาร์ตไคลเอนต์และบันทึกว่ามันตายเพราะอะไร ไม่ว่าจะทางใด จงคาดว่าจะมีรหัสใหม่หลังการเชื่อมต่อใหม่ทุกครั้ง: โทเคนใช้ครั้งเดียวจะถูกใช้ไปในการยืนยันตัวตนครั้งแรกที่สำเร็จ
สังเกตว่า sudo ทำอะไรกับลำดับ คำขอรหัสผ่านของ sudo ไม่ใช่คำขอของ VPN และการตอบมันด้วยรหัสผ่านของ VPN คือวิธีที่พบบ่อยที่สุดที่ทำให้ลำดับการรอคอยที่ถูกต้องอยู่แล้วยังล้มเหลว
การตรวจสอบ 5: รหัสของบุคคลควรอยู่ในสคริปต์หรือไม่
นี่คือการตรวจสอบที่ผู้คนข้ามไป โทเคนเป็นของบุคคล ขณะที่อุโมงค์ที่ต้องขึ้นตามกำหนดเวลาเป็นของเครื่องจักร
หากงานต้องเชื่อมต่อใหม่โดยไม่มีคนเฝ้า จงถามว่าใบรับรองเครื่องหรือบัญชีบริการสามารถแทนการเข้าสู่ระบบแบบโต้ตอบได้หรือไม่ การทำให้รหัสใช้ครั้งเดียวของใครคนหนึ่งเป็นอัตโนมัติเปลี่ยนปัจจัยที่สองให้เป็นความลับที่จัดเก็บไว้ ซึ่งเป็นการเปลี่ยนนโยบายไม่ใช่ความสะดวกในการเขียนสคริปต์ ในกรณีที่บริการรองรับทั้งสอง จงเลือกข้อมูลรับรองที่ตรงกับวิธีที่งานทำงานจริง เขียนคำตอบไว้ เพราะคนถัดไปจะถามว่าทำไมสคริปต์จึงถือโทเคน
สคริปต์ที่ใช้งานได้มีหน้าตาอย่างไร
สคริปต์พิมพ์ขั้นตอนที่ไปถึง ไม่เคยพิมพ์ความลับ และออกด้วยรหัสที่ไม่ใช่ศูนย์เมื่อการรอคอยใดล้มเหลว
ทดสอบด้วยการทำให้มันพังโดยเจตนา: รหัสผ่านผิด กลุ่มผิด โทเคนหมดอายุ ทุกความล้มเหลวควรหยุดที่ขั้นตอนที่มีชื่อแทนที่จะค้าง จากนั้นรันกับบริการจริงหนึ่งครั้งและ ตรวจอุโมงค์จากภายนอกสคริปต์ ไม่ใช่จากภายใน