จะส่งรหัสผ่านไปยังกระบวนการลูกได้อย่างไร


18

การส่งรหัสผ่านบนบรรทัดคำสั่ง (ไปยังกระบวนการย่อยที่เริ่มต้นจากโปรแกรมของฉัน) นั้นไม่ปลอดภัย (เนื่องจากผู้ใช้รายอื่นสามารถใช้คำสั่ง ps) ตกลงเพื่อส่งเป็นตัวแปรสภาพแวดล้อมแทนหรือไม่?

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

ฉันโปรแกรมใน Perl


2
ทำไมมันไม่ง่าย? ไม่จำเป็นต้องเป็นไปตาม / แยกชื่อเพียง stdin / out ปกติจะทำ ... ที่ไม่ควรมีปัญหามากเกินไปในภาษาใด ๆ คุณสามารถวางไว้ในไฟล์กำหนดค่าธรรมดาหากคุณมั่นใจว่าสามารถอ่านได้โดยกระบวนการที่น่าสนใจเท่านั้น (ซึ่งยากกว่าฟังดู)
frostschutz

1
หากคุณไม่โทรหา exec ในเด็กคุณยังคงมีสำเนารหัสผ่านโดยไม่จำเป็นต้องทำอะไรเลย
James Youngman

คำตอบ:


26

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

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

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

echo "$password" | theprogram

หากtheprogramคาดว่ารหัสผ่านในอินพุตมาตรฐาน โปรดทราบว่านี่ปลอดภัยเพราะechoเป็น builtin; มันจะไม่ปลอดภัยกับคำสั่งภายนอกเนื่องจากการโต้แย้งจะถูกเปิดเผยในการpsส่งออก อีกวิธีหนึ่งในการบรรลุเอฟเฟกต์เดียวกันคือใช้เอกสาร here:

theprogram <<EOF
$password
EOF

บางโปรแกรมที่ต้องการรหัสผ่านสามารถบอกให้อ่านได้จากตัวให้คำอธิบายไฟล์เฉพาะ คุณสามารถใช้ file descriptor นอกเหนือจากอินพุตมาตรฐานหากคุณต้องการอินพุตมาตรฐานสำหรับอย่างอื่น ตัวอย่างเช่นด้วยgpg:

get-encrypted-data | gpg --passphrase-fd 3 --decrypt … 3<<EOP >decrypted-data
$password
EOP

หากโปรแกรมไม่สามารถบอกให้อ่านจาก file descriptor แต่สามารถบอกให้อ่านจากไฟล์คุณสามารถบอกให้อ่านจาก file descriptor โดยใช้ชื่อไฟล์เช่น `/ dev / fd / 3

theprogram --password-from-file=/dev/fd/3 3<<EOF
$password
EOF

ใน ksh, bash หรือ zsh, คุณสามารถทำสิ่งนี้ได้อย่างกระชับยิ่งขึ้นผ่านการทดแทนกระบวนการ

theprogram --password-from-file=<(echo "$password")

บน Solaris 9 และรุ่นเก่ากว่านั้น/usr/ucb/psคือ setuid root เพื่อให้สามารถอ่านและแสดงตัวแปรสภาพแวดล้อมของกระบวนการอื่น ๆ ได้ซึ่งจะถูกลบออกใน Solaris 10 ดังนั้นคำตอบที่ว่า
alanc

@alanc แน่นอนฉันไม่คิดว่าโซลาริส <10 จะทันสมัยวันนี้ Solaris 9 เกือบแก่เท่ากับ Windows XP!
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

Gilles: มีหลายวันที่ฉันลำบากสำหรับการพิจารณา Solaris 10 ที่ทันสมัยในขณะนี้ที่ Solaris 11 ออกมามากกว่า 5 ปีดังนั้นฉันจึงเข้าใจและยอมรับอย่างสมบูรณ์ แต่น่าเศร้าที่รู้ว่าบางคนยังคงใช้ Solaris 8 หรือ 9
alanc

10

แทนที่จะส่งรหัสผ่านโดยตรงผ่านอาร์กิวเมนต์หรือตัวแปรสภาพแวดล้อม

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $1"

ใช้อาร์กิวเมนต์หรือตัวแปรสภาพแวดล้อมเดียวกันเพื่อส่งชื่อไฟล์ :

#!/bin/bash
#filename: passwd_receiver
echo "The password is: $(< "$1")"

จากนั้นคุณสามารถส่งผ่านไฟล์ปกติได้รับอนุญาตที่มีการป้องกัน (แม้ว่าจะไม่ปกป้องคุณจากกระบวนการอื่น ๆ ที่ทำงานภายใต้ผู้ใช้เดียวกัน) หรือ/dev/stdinและท่อใน (ซึ่ง AFAIK จะปกป้องคุณจากกระบวนการอื่น ๆ ที่ทำงานภายใต้ผู้ใช้เดียวกัน):

 echo PASSWORD | ./passwd_receiver /dev/stdin 

ถ้าคุณใช้/dev/stdinที่นี่มันเป็นความจำเป็นที่ว่ามันเป็นท่อ หากเป็นเทอร์มินัลกระบวนการอื่น ๆ จะสามารถอ่านได้ภายใต้ผู้ใช้เดียวกัน

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

./passwd_receiver <(echo PASSWORD)

ไปป์ที่มีชื่อ (FIFO) อาจดูเหมือนว่าเหมือนกัน แต่ก็สามารถดักได้

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

ในอุดมคติแล้วคุณจะอ่านไฟล์เหล่านี้ (ไปป์เป็นไฟล์ด้วย) ลงในหน่วยความจำที่ทำเครื่องหมายด้วยmlock (2)ว่าไม่สามารถใช้งานได้ซึ่งเป็นโปรแกรมจัดการรหัสผ่านเช่น gnupg โดยทั่วไป

หมายเหตุ:

  1. ผ่านหมายเลข filedescriptor เป็นทฤษฎีที่ดีเพียงเป็นไฟล์เป็นชื่อไฟล์ผ่าน แต่ชื่อไฟล์ที่มีการปฏิบัติมากขึ้นเพราะ<()ช่วยให้คุณมีชื่อไฟล์ไม่ได้เป็นจำนวน filedescriptor (และcoprocs ให้ filedescriptors ทำเครื่องหมายFD_CLOEXECซึ่งจะทำให้ผู้ใช้ไม่ได้ filedescriptors ในบริบทนี้)

  2. หากคุณอยู่บนระบบ Linux ที่
    /proc/sys/kernel/yama/ptrace_scopeตั้งค่าไว้0AFAIK จะไม่มีวิธีการป้องกันตัวเองจากกระบวนการอื่นที่ทำงานภายใต้ผู้ใช้เดียวกัน (สามารถใช้ ptrace เพื่อแนบกับกระบวนการของคุณและอ่านหน่วยความจำของคุณ)

  3. หากคุณต้องการเก็บรหัสผ่านของคุณให้ห่างจากกระบวนการทำงานภายใต้ผู้ใช้ที่แตกต่างกัน (ไม่ใช่รูท) ดังนั้นอาร์กิวเมนต์ตัวแปรสภาพแวดล้อมไพพ์และไฟล์ที่ได้รับการป้องกันจะได้รับอนุญาต


7

ไม่ตัวแปรสภาพแวดล้อมสามารถอ่านได้ง่ายเช่นกันและรั่วไหลไปยังกระบวนการลูก ผ่านมันโดยใช้ท่อ


2
"ตัวแปรสภาพแวดล้อม ... รั่วไหลไปสู่กระบวนการลูก" นั่นเป็นจุดรวมของการใช้ตัวแปรสภาพแวดล้อม พวกเขาจะไร้ประโยชน์ถ้าพวกเขาไม่ได้รับมรดก "ตัวแปรสภาพแวดล้อมสามารถอ่านได้ง่ายเช่นกัน" ไม่เช่นนั้น
แพทริค

2
อ่านตัวแปรยกเลิกการตั้งค่า มันไม่ยาก และคุณสามารถใช้อาร์กิวเมนต์เดียวกันกับไพพ์ได้ หากไพพ์ไม่ได้ถูกอ่านมันจะถูกส่งไปยังกระบวนการลูกและกระบวนการลูกสามารถอ่านและรับรหัสผ่านได้
แพทริค

1
@ แพทริกเอกสารที่วิธีการของตัวแปรสภาพแวดล้อม unsetting ไม่จำเป็นต้องขัดค่าจากสถานที่psและ/procสามารถมองเห็นได้
zwol

1
ระบบบางระบบให้คุณอ่านตัวแปรสภาพแวดล้อมของกระบวนการตามอำเภอใจหรือไม่? ฉันไม่คิดว่าลีนุกซ์อนุญาตให้กระบวนการนั้นเป็นของผู้อื่น, และถ้าคุณเป็นผู้ใช้คนเดียวกัน, คุณสามารถptrace()กำหนดเป้าหมายและอ่านหน่วยความจำได้
ilkkachu

5
คำตอบนี้ผิด ผู้ใช้รายอื่นไม่สามารถอ่านตัวแปรสภาพแวดล้อมได้
Gilles 'ดังนั้นหยุดความชั่วร้าย'

1

หากไม่มีสิ่งใดเหมาะสมให้พิจารณาบริการการเก็บรักษาลีนุกซ์คีย์ (เคอร์เนลคีย์ริง)

เริ่มต้น: การรักษาความปลอดภัย / keys.txt หนึ่งใน keyrings เริ่มต้นสามารถโคลนได้ระหว่างกระบวนการหลักและลูก

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

ฉันไม่รู้เกี่ยวกับสถานะ "ทางการเมือง" ของมัน แต่ฉันมีความต้องการที่คล้ายกันและเริ่มทำงานกับ Guile binding ยังไม่เจอการสนับสนุน Perl ที่มีอยู่แล้ว

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