시스템 로그인 테스트는 어떻게 작성합니까?


9

bash명령 을 호출하는 Python CGI 스크립트를 작성 했으며 호스트에서 성공적인 로그인을 테스트해야합니다.

테스트를 어떻게 작성합니까?

예를 들어 bash호스트에 등록 된 사용자에 대해 주어진 사용자 이름과 비밀번호 조합을 테스트 하는 스크립트를 만들 수 있습니까?


1
아마도 당신은 login프로그램 뒤의 코드를 볼 수있을 것 입니다.
Kevin

질문과 관련이 없지만 사용자 로그인을 유선으로 스니핑 할 수 없도록 웹 서버에 대한 트래픽을 암호화하기를 바랍니다.
jw013

답변:


8

PAM을 사용하는 것이 가장 좋습니다. 작은 C 코드를 작성하거나 python-pam 패키지를 설치하고 python-pam 패키지와 함께 제공되는 python 스크립트를 사용할 수 있습니다. 보다/usr/share/doc/python-pam/examples/pamtest.py


PAM을 시도했지만 작동하지 않았습니다. 그러나이 예제를 다시 시도하면 효과가 있습니다.
jcubic

1
OpenSUSE 12.3 (python-pam 0.5.0-84.1.1) 및 13.1 (0.5.0-87.1.2)에서 pamtest.py의 전체 경로는 pamtest.py /usr/share/doc/packages/python-pam/examples/pamtest.py스크립트를 사용하여 PAM을 사용하는 시스템에서 자격 증명을 테스트 할 수 있습니다 인증을 위해 python-pam 패키지 (python 필요)에 포함되어 있으며 일부 배포판에서는 전체 경로가 /usr/share/doc/python-pam/examples/pamtest.py입니다.
ShadSterling

5

사용자가 로그인 할 수 있는지 테스트하는 올바른 방법은 실제로 해당 사용자로 로그인하는 것입니다.

따라서 내가 추천하는 것은 CGI 스크립트를 사용 expect하여 실행 su하고 암호를 전달한 다음 실행해야하는 명령을 실행하는 것입니다. 다음은이 작업을 수행하는 expect 스크립트 초안입니다 (경고 : 절대적으로 테스트되지 않았으며 기대에 유창하지 않습니다). (내가 쓴 경우 사용자 이름, 암호 및 명령에 대체 bob, swordfishsomecommand); 정확하게 인용하십시오.

spawn "/bin/su" "bob"
expect "Password:"
send "swordfish\r"
expect "^\\$"
send "somecommand"
expect -re "^\\$"
send "exit\r"
expect eof

suCGI 프로세스 자체에서 수행해야하는 작업 과 같이 계층을 통해 명령을 실제로 실행하지 않으려면 expect 명령을 실행 true하고 반환 상태가 0인지 확인하십시오.

또 다른 방법은 Python의 PAM 바인딩을 통해 응용 프로그램에서 직접 PAM 을 사용하는 것 입니다.


루트 액세스 권한이없는 유일한 솔루션입니다.
jcubic

이 작품 su -c true bob && echo success스와 인수로 암호를 허용하지 않는 것이 부끄러운
jcubic

suCGI 스크립트에서 테스트 했으며 작동하려면 터미널이 필요합니다.
jcubic

3
@jcubic 커맨드 라인 인자는 유닉스 시스템에서 공개되기 때문에 커맨드 라인 인자에 암호를 넣는 것은 정말 어리석은 생각입니다. 암호를 제거하면 명령 줄에 넣는 것과 같은 수준의 보안이 제공됩니다. 그리고 확인하기가 훨씬 쉬울 /bin/true것입니다.
20:53에

2

보다 구체적으로 대답하려면 : "호스트의 등록 된 사용자에 대해 지정된 사용자 이름 및 비밀번호 조합을 테스트하는 bash 스크립트를 작성할 수 있습니까?"

예.

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

2
이것이 당신을 위해 일했습니까? 섀도 암호와 기존 섀도 암호를 확인하고 있지만 해싱은 어디에 관련되어 있습니까?
Nikhil Mulley

나는 테스트했고 작동하지 않는다
jcubic

3
나쁜 생각! 프로그램이 루트 또는 최소한 shadow그룹 으로 실행 중이라고 가정하고 있는데, 이는 CGI에 매우 권장되지 않습니다. 다른 권한 상승 단계가 필요합니다. 그리고 특정 비밀번호 해싱 알고리즘 (openssl이 지원하는 알고리즘)과 비밀번호 저장 위치 ( /etc/shadow예 : NIS 또는 LDAP와 달리)가 특정 사용자에게 실제로 사용되거나 아닐 수도 있다고 가정합니다.
Gilles 'SO- 악마 그만해'

2

여기에 인용 된 'C', 'Python'PAM 솔루션이 있습니다.

출처 : http://search.cpan.org/~nikip/Authen-PAM-0.16/PAM/FAQ.pod#1._Can_I_authenticate_a_user_non_interactively ?

#!/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();

그래, 문제는 파이썬으로 작성된 CGI 스크립트에 관한 것이었다.
Gilles 'SO- 악의를 그만두십시오'

1

루트 액세스 권한이 있고 md5 비밀번호를 사용 중이고 비밀번호를 비교해야하는 경우 perl Crypt :: PasswdMD5 모듈을 사용할 수 있습니다 . / etc / shadow에서 MD5 해시를 가져와 $ 1 $를 벗기고 나머지 $로 나눕니다. 필드 1 = 소금, 필드 2 = 암호화 된 텍스트. 그런 다음 텍스트 입력을 CGI에 해시하고 암호화 된 텍스트와 비교하고 Bob은 삼촌입니다.

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

2
평범하고 간단한 :-). / etc / passwd가 md5 해싱을 사용하는 한 작동합니다. 시스템에 대한 인증 (nsswitch)이 다른 경우 pam 모듈을 사용하는 것이 가장 좋습니다.
Nikhil Mulley

2
나쁜 생각! 프로그램이 루트 또는 최소한 shadow그룹 으로 실행 중이라고 가정하고 있는데, 이는 CGI에 매우 권장되지 않습니다. 다른 권한 상승 단계가 필요합니다. 그리고 특정 비밀번호 해싱 알고리즘 (MD5 및 bcrypt 또는 기타 권장 알고리즘이 아님)과 비밀번호 저장 위치 ( /etc/shadow예 : NIS 또는 LDAP와 달리)가 특정 사용자에게 실제로 사용되거나 아닐 수 있다고 가정합니다.
Gilles 'SO- 악마 그만해'

0

검색 후 스크립트에서 사용할 수있는이 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"

1
나쁜 생각! 프로그램이 루트 또는 최소한 shadow그룹 으로 실행 중이라고 가정하고 있는데, 이는 CGI에 매우 권장되지 않습니다. 다른 권한 상승 단계가 필요합니다. 그리고 특정 비밀번호 해싱 알고리즘 (openssl이 지원하는 알고리즘)과 비밀번호 저장 위치 ( /etc/shadow예 : NIS 또는 LDAP와 달리)가 특정 사용자에게 실제로 사용되거나 아닐 수도 있다고 가정합니다. PAM을 사용하면 그 일을 알고 있습니다.
Gilles 'SO- 악한 중지'

예, 알고 있지만 루트가 없으면 이것이 가능하지 않다고 생각했습니다. 다른 모든 솔루션은 루트를 사용하여 사용자를 실행합니다.
jcubic

0

파이썬에서 CGI를 사용한다고 언급 했으므로 Apache를 httpd 서버로 사용한다고 가정하는 것이 적합합니다. 그렇다면 프로그램의 인증 프로세스를 Apache에 맡기고 인증 된 사용자 만 cgi 스크립트 / 프로그램을 실행하도록하십시오.

Apache에서 인증을 수행 할 수있는 충분한 모듈이 있으며, 실제로 원하는 인증 메커니즘의 종류에 따라 다릅니다. 질문에서 인용 한 방법은 / etc / passwd, shadow 파일을 기반으로하는 로컬 호스트 계정 인증과 관련이있는 것 같습니다. 이것에 관한 나의 빠른 검색에 오는 모듈은 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

또 다른 방법은 인증 된 사용자 대신 프로세스 (cgi 프로그램)를 실행하는 Apache의 SuEXEc 모듈을 사용하는 것입니다.


이 CGI 스크립트는 Ajax를 통해 호출 된 JSON-RPC 서비스이며 토큰을 반환하는 메소드 로그인이 필요합니다. 로그인이 성공하면 토큰이 반환되어야합니다. 따라서 기본적으로 모든 사용자는 해당 스크립트를 실행할 수 있어야합니다.
jcubic

0

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; 
}

문맥 정보를 추가하여 답변처럼 느끼도록 할 수 있습니까?
Volker Siegel

-3

호스트에 로그인하기 위해 스크립트가 필요한 경우 가장 좋은 방법은 호스트간에 ssh 키를 구성하는 것입니다.

링크 : http://pkeck.myweb.uga.edu/ssh/

나는 이것을 페이지에서 거의 들었다.


먼저, 두 개의 UNIX 시스템에 서둘러 OpenSSH를 설치하십시오. 이것은 내가 알 수있는 한 기본적으로 DSA 키와 SSH2를 사용하는 것이 가장 좋습니다. 내가 본 다른 모든 하우투는 RSA 키와 SSH1을 다루는 것처럼 보이며, 지침이 놀랍게도 SSH2와 작동하지 않습니다. 각 머신에서 ssh somemachine.example.com을 입력하고 일반 비밀번호로 연결하십시오. 홈 디렉토리에 적절한 perms와 함께 .ssh 디렉토리가 작성됩니다. 비밀 키를 사용하려는 기본 컴퓨터에서 (둘러 말해 보자)

ssh-keygen -t dsa

비밀 암호를 입력하라는 메시지가 표시됩니다. 이것이 기본 ID 키인 경우 올바른 암호를 사용해야합니다. 이것이 제대로 작동하면 .ssh 디렉토리에 id_dsa와 id_dsa.pub라는 두 파일이 생깁니다. 참고 : 암호 문구를 입력하라는 메시지가 표시되면 Enter 키를 누르면 암호 문구가없는 키를 만들 수 있습니다. 이것은 신원 키에 대한 나쁜 생각 ™이므로 수행하지 마십시오! 암호없이 키를 사용하려면 아래를 참조하십시오.

scp ~/.ssh/id_dsa.pub burly:.ssh/authorized_keys2

id_dsa.pub 파일을 authorized_keys2라는 이름으로 다른 호스트의 .ssh 디렉토리에 복사하십시오. 이제 ssh 키를 받아 들일 준비가되었습니다. 사용할 키를 알려주는 방법은 무엇입니까? ssh-add 명령이이를 수행합니다. 테스트를 위해

ssh-agent sh -c 'ssh-add < /dev/null && bash'

그러면 ssh-agent가 시작되고 기본 ID가 추가되고 (암호를 입력하라는 메시지가 표시됨) bash 쉘이 생성됩니다. 이 새로운 쉘에서 다음을 수행 할 수 있어야합니다.

ssh burly

로그인 할 수 있어야합니다


이것은 사실이지만 웹 브라우저를 통해 액세스하는 응용 프로그램에 관한 질문과 관련이없는 것 같습니다.
Gilles 'SO- 악마 그만해'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.