ฉันเขียนสคริปต์ Python CGI ที่เรียกใช้bash
คำสั่งและต้องทดสอบการลงชื่อเข้าใช้ที่สำเร็จบนโฮสต์
ฉันจะเขียนแบบทดสอบได้อย่างไร
ตัวอย่างเช่นฉันสามารถสร้างbash
สคริปต์ที่ทดสอบรวมชื่อผู้ใช้และรหัสผ่านที่กำหนดกับผู้ใช้ที่ลงทะเบียนในโฮสต์ได้หรือไม่
ฉันเขียนสคริปต์ Python CGI ที่เรียกใช้bash
คำสั่งและต้องทดสอบการลงชื่อเข้าใช้ที่สำเร็จบนโฮสต์
ฉันจะเขียนแบบทดสอบได้อย่างไร
ตัวอย่างเช่นฉันสามารถสร้างbash
สคริปต์ที่ทดสอบรวมชื่อผู้ใช้และรหัสผ่านที่กำหนดกับผู้ใช้ที่ลงทะเบียนในโฮสต์ได้หรือไม่
คำตอบ:
การใช้ PAM เป็นทางออกที่ดีที่สุด คุณสามารถเขียนรหัส C ขนาดเล็กหรือติดตั้งแพ็คเกจ python-pam และใช้สคริปต์ python ซึ่งมาพร้อมกับแพ็คเกจ python-pam ดู/usr/share/doc/python-pam/examples/pamtest.py
/usr/share/doc/packages/python-pam/examples/pamtest.py
สคริปต์ pamtest.py สามารถใช้เพื่อทดสอบข้อมูลรับรองในระบบที่ใช้PAMสำหรับการตรวจสอบจะรวมอยู่ในแพคเกจหลามแพม (ซึ่งต้องหลาม) /usr/share/doc/python-pam/examples/pamtest.py
และในการกระจายบางเส้นทางที่เต็มรูปแบบ
แนวทางที่ถูกต้องในการทดสอบว่าผู้ใช้สามารถเข้าสู่ระบบได้หรือไม่คือเข้าสู่ระบบในฐานะผู้ใช้รายนั้น
ดังนั้นสิ่งที่ฉันแนะนำคือการทำให้สคริปต์ CGI ใช้expect
เพื่อเรียกใช้su
ผ่านรหัสผ่านและเรียกใช้คำสั่งที่ต้องดำเนินการ นี่คือร่างของสคริปต์คาดหวังที่ทำสิ่งนี้ (คำเตือน: ยังไม่ได้ทดสอบอย่างสมบูรณ์และฉันไม่ได้คาดหวัง) แทนในชื่อผู้ใช้รหัสผ่านและคำสั่ง (ที่ผมเขียนbob
, swordfish
และsomecommand
); ให้แน่ใจว่าจะพูดอย่างถูกต้อง
spawn "/bin/su" "bob"
expect "Password:"
send "swordfish\r"
expect "^\\$"
send "somecommand"
expect -re "^\\$"
send "exit\r"
expect eof
หากคุณไม่ต้องการดำเนินการคำสั่งผ่านเลเยอร์ของsu
(ตัวอย่างเช่นเนื่องจากสิ่งที่คุณต้องดำเนินการโดยกระบวนการ CGI เอง) ให้ใช้การคาดหวังว่าจะเรียกใช้คำสั่งtrue
และตรวจสอบว่าสถานะการส่งคืนเป็น 0
อีกวิธีหนึ่งที่จะใช้PAMโดยตรงในใบสมัครของคุณผ่านPAM ธ ผูกพัน
su -c true bob && echo success
มันใช้งานได้ดีที่ su ไม่ยอมรับรหัสผ่านเป็นอาร์กิวเมนต์
su
จากสคริปต์ CGI และต้องการเทอร์มินัลเพื่อให้ทำงานได้
/bin/true
เพียงพอแล้ว
หากต้องการคำตอบเพิ่มเติมโดยเฉพาะ: "เป็นไปได้ไหมที่จะสร้างสคริปต์ทุบตีที่จะทดสอบชื่อผู้ใช้และรหัสผ่านที่กำหนดร่วมกับผู้ใช้ที่ลงทะเบียนบนโฮสต์"
ใช่.
#!/bin/bash
uid=`id -u`
if [ $uid -ne 0 ]; then
echo "You must be root to run this"
exit 1
fi
if [ $# -lt 1 ]; then
echo "You must supply a username to check - ($# supplied)"
exit 1
fi
username=$1
salt=`grep $username /etc/shadow | awk -F: ' {print substr($2,4,8)}'`
if [ "$salt" != "" ]; then
newpass=`openssl passwd -1 -salt $salt`
grep $username /etc/shadow | grep -q $newpass && echo "Success" || echo "Failure"
fi
shadow
กลุ่มซึ่งไม่แนะนำอย่างยิ่งสำหรับ CGI: คุณต้องมีการเพิ่มระดับสิทธิ์อีกระดับ และคุณสมมติว่าอัลกอริทึมการแฮชรหัสผ่านหนึ่งอัน (อันหนึ่งสนับสนุนโดย openssl) และตำแหน่งที่เก็บรหัสผ่าน ( /etc/shadow
ตรงข้ามกับเช่น NIS หรือ LDAP) ซึ่งอาจใช้หรือไม่ใช้กับผู้ใช้นั้น
มีคำว่า 'C', 'Python' PAM ที่ยกมาที่นี่ให้ฉันใส่ perl หนึ่งด้วย :-)
#!/usr/bin/perl
use Authen::PAM;
use POSIX qw(ttyname);
$service = "login";
$username = "foo";
$password = "bar";
$tty_name = ttyname(fileno(STDIN));
sub my_conv_func {
my @res;
while ( @_ ) {
my $code = shift;
my $msg = shift;
my $ans = "";
$ans = $username if ($code == PAM_PROMPT_ECHO_ON() );
$ans = $password if ($code == PAM_PROMPT_ECHO_OFF() );
push @res, (PAM_SUCCESS(),$ans);
}
push @res, PAM_SUCCESS();
return @res;
}
ref($pamh = new Authen::PAM($service, $username, \&my_conv_func)) ||
die "Error code $pamh during PAM init!";
$res = $pamh->pam_set_item(PAM_TTY(), $tty_name);
$res = $pamh->pam_authenticate;
print $pamh->pam_strerror($res),"\n" unless $res == PAM_SUCCESS();
หากคุณมีสิทธิ์เข้าถึงรูตและใช้รหัสผ่าน md5 และคุณเพียงต้องการเปรียบเทียบรหัสผ่านคุณสามารถใช้โมดูลCrypt :: PasswdMD5 perlได้ ใช้ MD5 Hash จาก / etc / shadow เปลื้อง $ 1 $ จากนั้นแยกส่วนที่เหลือ $ ฟิลด์ 1 = เกลือ, ฟิลด์ 2 = ข้อความที่เข้ารหัส จากนั้นแฮชข้อความที่ป้อนลงใน CGI ของคุณเปรียบเทียบกับข้อความที่เข้ารหัสและบ๊อบเป็นลุงของคุณ
#!/usr/bin/env perl
use Crypt::PasswdMD5;
my $user = $ARGV[0];
my $plain = $ARGV[1];
my $check = qx{ grep $user /etc/shadow | cut -d: -f2 };
chomp($check);
my($salt,$md5txt) = $check =~ m/\$1\$([^\$].+)\$(.*)$/;
my $pass = unix_md5_crypt($plain, $salt);
if ( "$check" eq "$pass" ) {
print "OK","\n";
} else {
print "ERR","\n";
}
shadow
กลุ่มซึ่งไม่แนะนำอย่างยิ่งสำหรับ CGI: คุณต้องมีการเพิ่มระดับสิทธิ์อีกระดับ และคุณสมมติว่าอัลกอริทึมการแฮ็นรหัสผ่านโดยเฉพาะ (MD5 ไม่ใช่ bcrypt หรืออัลกอริทึมอื่น ๆ ที่แนะนำ) และที่เก็บรหัสผ่าน ( /etc/shadow
ตรงข้ามกับ NIS หรือ LDAP) ซึ่งอาจใช้หรือไม่ใช้กับผู้ใช้นั้น
หลังจากการค้นหาบางฉันเขียนโปรแกรม C นี้ที่สามารถใช้จากสคริปต์
#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <shadow.h>
#include <string.h>
#include <crypt.h>
#include <unistd.h>
#include <libgen.h>
int main(int argc, char **argv) {
struct spwd *pwd;
if (argc != 3) {
printf("usage:\n\t%s [username] [password]\n", basename(argv[0]));
return 1;
} else if (getuid() == 0) {
pwd = getspnam(argv[1]);
return strcmp(crypt(argv[2], pwd->sp_pwdp), pwd->sp_pwdp);
} else {
printf("You need to be root\n");
return 1;
}
}
คุณรวบรวมด้วย:
gcc -Wall password_check.c /usr/lib/libcrypt.a -o check_passwd
คุณสามารถใช้มันเป็น
sudo ./check_passwd <user> <password> && echo "success" || echo "failure"
shadow
กลุ่มซึ่งไม่แนะนำอย่างยิ่งสำหรับ CGI: คุณต้องมีการเพิ่มระดับสิทธิ์อีกระดับ และคุณสมมติว่าอัลกอริทึมการแฮชรหัสผ่านหนึ่งอัน (อันหนึ่งสนับสนุนโดย openssl) และตำแหน่งที่เก็บรหัสผ่าน ( /etc/shadow
ตรงข้ามกับเช่น NIS หรือ LDAP) ซึ่งอาจใช้หรือไม่ใช้กับผู้ใช้นั้น ใช้ PAM มันรู้หน้าที่ของมัน
เนื่องจากคุณพูดถึงว่าคุณกำลังใช้ CGI ใน python มันอาจจะเหมาะสมที่จะถือว่าคุณใช้ Apache เป็นเซิร์ฟเวอร์ httpd ของคุณ ถ้าเป็นเช่นนั้นปล่อยให้กระบวนการพิสูจน์ตัวตนของโปรแกรมของคุณเป็น Apache และให้ผู้ที่ได้รับการรับรองความถูกต้องดำเนินการสคริปต์ / โปรแกรม cgi ของคุณเท่านั้น
มีโมดูลมากมายที่สามารถทำการพิสูจน์ตัวตนของคุณบน Apache ได้ขึ้นอยู่กับประเภทของกลไกการตรวจสอบที่คุณกำลังมองหา วิธีที่คุณยกมาในคำถามดูเหมือนจะเกี่ยวข้องกับการตรวจสอบบัญชีโฮสต์ท้องถิ่นตาม / etc / passwd, ไฟล์เงา mod_auth_shadow
โมดูลที่มาพร้อมกับการค้นหาอย่างรวดเร็วของฉันเกี่ยวกับเรื่องนี้คือ ข้อดีคือคุณอนุญาตให้ผู้ใช้ที่มีสิทธิ์ (ใช้งานบนพอร์ตสิทธิ์ 80) เพื่อตรวจสอบสิทธิ์ผู้ใช้ / รหัสผ่านสำหรับคุณและคุณสามารถใช้ข้อมูลที่ได้รับการรับรองความถูกต้องของผู้ใช้เพื่อเรียกใช้คำสั่งในนามของผู้ใช้
ลิงค์ที่ดีสำหรับการเริ่มต้น:
http://adam.shand.net/archives/2008/apache_tips_and_tricks/#index5h2
http://mod-auth-shadow.sourceforge.net/
http://www.howtoforge.com/apache_mod_auth_shadow_debian_ubuntu
อีกวิธีหนึ่งคือการใช้โมดูล SuEXEc ของ Apache ซึ่งดำเนินการกระบวนการ (โปรแกรม CGI) ในนามของผู้ใช้รับรองความถูกต้อง
รหัสนี้ที่ใช้ PAM ใช้งานได้สำหรับฉัน:
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <string.h>
// Define custom PAM conversation function
int custom_converation(int num_msg, const struct pam_message** msg, struct pam_response** resp, void* appdata_ptr)
{
// Provide password for the PAM conversation response that was passed into appdata_ptr
struct pam_response* reply = (struct pam_response* )malloc(sizeof(struct pam_response));
reply[0].resp = (char*)appdata_ptr;
reply[0].resp_retcode = 0;
*resp = reply;
return PAM_SUCCESS;
}
int main (int argc, char* argv[])
{
if (argc > 2)
{
// Set up a custom PAM conversation passing in authentication password
char* password = (char*)malloc(strlen(argv[2]) + 1);
strcpy(password, argv[2]);
struct pam_conv pamc = { custom_converation, password };
pam_handle_t* pamh;
int retval;
// Start PAM - just associate with something simple like the "whoami" command
if ((retval = pam_start("whoami", argv[1], &pamc, &pamh)) == PAM_SUCCESS)
{
// Authenticate the user
if ((retval = pam_authenticate(pamh, 0)) == PAM_SUCCESS)
fprintf(stdout, "OK\n");
else
fprintf(stderr, "FAIL: pam_authentication failed.\n");
// All done
pam_end(pamh, 0);
return retval;
}
else
{
fprintf(stderr, "FAIL: pam_start failed.\n");
return retval;
}
}
fprintf(stderr, "FAIL: expected two arguments for user name and password.\n");
return 1;
}
สิ่งที่ดีที่สุดที่คุณสามารถทำได้หากคุณต้องการสคริปต์เพื่อเข้าสู่โฮสต์คือกำหนดค่าคีย์ ssh ระหว่างโฮสต์
ลิงก์: http://pkeck.myweb.uga.edu/ssh/
ฉันยกนี่ขึ้นมาจากหน้า
ก่อนอื่นให้ติดตั้ง OpenSSH ลงในเครื่อง UNIX สองเครื่องก่อนและหลัง สิ่งนี้ทำงานได้ดีที่สุดโดยใช้คีย์ DSA และ SSH2 โดยค่าเริ่มต้นเท่าที่ฉันจะบอกได้ HOWTO อื่น ๆ ทั้งหมดที่ฉันเคยเห็นดูเหมือนจะจัดการกับคีย์ RSA และ SSH1 และคำแนะนำที่ไม่น่าแปลกใจที่ล้มเหลวในการทำงานกับ SSH2 ในแต่ละประเภทเครื่อง ssh somemachine.example.com และทำการเชื่อมต่อกับรหัสผ่านปกติของคุณ สิ่งนี้จะสร้าง. ssh dir ในโฮมไดเร็กตอรี่ของคุณด้วย perms ที่เหมาะสม บนเครื่องหลักของคุณที่คุณต้องการให้รหัสลับของคุณมีชีวิตอยู่ (สมมติว่ารีบ) พิมพ์
ssh-keygen -t dsa
สิ่งนี้จะแจ้งให้คุณทราบสำหรับข้อความรหัสผ่านลับ หากนี่คือรหัสประจำตัวหลักของคุณตรวจสอบให้แน่ใจว่าคุณใช้ข้อความรหัสผ่านที่ดี หากสิ่งนี้ถูกต้องคุณจะได้รับสองไฟล์ชื่อ id_dsa และ id_dsa.pub ใน. ssh dir ของคุณ หมายเหตุ: มันเป็นไปได้ที่จะเพียงแค่กดปุ่ม Enter เมื่อได้รับแจ้งสำหรับวลีรหัสผ่านซึ่งจะทำให้คีย์ที่ไม่มีข้อความรหัสผ่าน นี่คือ Bad Idea ™สำหรับรหัสประจำตัวดังนั้นอย่าทำ! ดูด้านล่างสำหรับการใช้งานของคีย์โดยไม่มีข้อความรหัสผ่าน
scp ~/.ssh/id_dsa.pub burly:.ssh/authorized_keys2
คัดลอกไฟล์ id_dsa.pub ไปยัง. ssh dir ของโฮสต์อื่นด้วยชื่อ authorized_keys2 ตอนนี้แข็งแรงพร้อมที่จะรับกุญแจ ssh ของคุณแล้ว จะบอกได้อย่างไรว่าควรใช้คีย์ใด คำสั่ง ssh-add จะทำ สำหรับการทดสอบให้พิมพ์
ssh-agent sh -c 'ssh-add < /dev/null && bash'
สิ่งนี้จะเริ่มต้น ssh-agent เพิ่มตัวตนเริ่มต้นของคุณ (พร้อมท์ให้คุณใส่ข้อความรหัสผ่าน) และวางเปลือก bash จากเปลือกใหม่นี้คุณควรจะสามารถ:
ssh burly
คุณควรจะสามารถเข้าสู่ระบบได้
login
โปรแกรม