쉘 스크립트 AIX에서 암호화된 비밀번호를 사용하는 방법

쉘 스크립트 AIX에서 암호화된 비밀번호를 사용하는 방법

일부 작업을 수행하기 위해 데이터베이스에 연결하는 쉘 스크립트를 작성했습니다.

이것은 내 샘플 코드입니다.

#!/usr/bin/ksh
. /home/ram/.profile

sqlplus username/pwd@TNS<<EOF
select sysdate from dual;
exit;
EOF

내 시스템에서 이 코드를 사용하고 AIX있는데비밀번호암호화합니다.

셸에 명령이 있나요? crypt명령에 보안 문제가 있다고 들었습니다.

crypt(1) 암호화를 해제하는 프로그램은 어디에서나 사용할 수 있습니다. 1984~1985년에 작성된 Bob Baldwin의 Crypt Breaker's Workbench[2]는 사용자가 수정해야 하는 지속적인 일반 텍스트 추측을 제공하는 대화형 도구입니다. Peter Selinger의 unixcrypt-breaker[3]는 간단한 통계 모델을 사용하여 합리적인 일반 텍스트를 추측하며 사용자 상호 작용이 필요하지 않습니다.(원천-위키피디아).

AIX에서 crypt 명령을 시도했지만 오류가 발생합니다.

[shell-ksh]$uname    
AIX
[shell-ksh]$crypt
ksh: crypt: command not found
[shell-ksh]$echo $SHELL
/usr/bin/ksh

쉘에서 비밀번호를 암호화하는 안전한 방법이 있는지 궁금합니다.

답변1

oracle password repository쉘 스크립트에서 비밀번호를 하드 코딩하는 대신 쉘 스크립트 에서 사용할 수 있습니다 .

이 도구는 간단한 파일을 사용하여 암호화된 비밀번호를 저장합니다. 다른 사람이 액세스할 수 없도록 이 파일을 보호할 수 있습니다. 도구를 찾을 수 있습니다여기. 다음에서 도구의 설치 단계를 볼 수 있습니다.여기.

답변2

귀하의 userand가 and pass에 저장되어 있다고 가정합니다.user.txtpass.txt

암호화:

$ openssl aes-256-cbc -salt -in user.txt -out user.txt.enc -pass file:pass.txt

해독:

$ openssl aes-256-cbc -d -salt -in user.txt.enc -out user.txt.dec -pass file:pass.txt

보다 안전한 암호화를 위해 자신만의 복잡한 솔트를 사용해 볼 수 있습니다 -S "your complex string". 그러나 이것은 아마도 대부분의 목적에 충분할 것입니다.

답변3

당신은 사용을 고려할 수 있습니다SSH 터널. 로컬 포트에서 수신하도록 데이터베이스를 설정하고 사용자가 비밀번호 없이 해당 포트에 연결하도록 허용한 다음(127.0.0.1을 제외한 특정 인터페이스의 모든 연결 거부) SSH를 사용하여 해당 포트에 대한 터널을 협상할 수 있습니다. 그런 다음 스푸핑이 어렵고 하드코딩된 비밀번호가 없는 인증서 인증을 사용하여 SSH에 연결할 수 있습니다. 이 스크립트를 cron 작업에서 실행해야 하는 경우 nologin 셸을 사용하여 실행되는 서비스 계정으로 실행할 수 있습니다.

이 시점에서 귀하의 관심사는 SSH 키 관리이며, 도움이 될 수 있는 많은 도구가 있습니다.이것. 로컬에서 개인 키를 얻을 수 있는 유일한 사람은 루트 액세스 권한이 있는 사용자입니다. 이 경우 암호화된 비밀번호 저장소도 이들로부터 안전하지 않습니다.

또 다른 이점은 코드가 구현된 시스템 외부로 코드가 유출되는 경우 스크립트에서 콘텐츠를 추출할 수 없는 대신 스크립트를 원격 버전 제어에 배치할 수 있고 인증은 구현 세부 사항에 맡겨진다는 것입니다.

일부 데이터베이스는 이미 인증서 인증(예: Postgresql)을 지원하지만 SSH 터널을 사용하면 명령줄 클라이언트가 있는 모든 데이터베이스에서 작동합니다. 나는 이것을 MySQL과 Postgresql의 스크립트 백업에 사용했는데 정말 매력적이었습니다.

답변4

나는 비슷한 문제에 부딪혔고 암호화된 비밀을 쉘 스크립트에 저장하는 간단하면서도 안전한 솔루션을 원했습니다. 내가 생각해낸 최선의 해결책은 암호화된 비밀번호를 사용자의 홈 디렉토리에 저장한 다음 이를 스크립트에서 읽어오는 것이었습니다. 컴퓨터의 루트 사용자는 이러한 비밀에 액세스할 수 있지만 그렇지 않은 경우에는 안전합니다. 이는 자격 증명을 노출하지 않고도 코드 저장소에 스크립트를 배포하거나 저장할 수 있다는 이점이 있습니다.

이 솔루션은 우리 회사를 위해 시간이 지남에 따라 발전했습니다(Plyint -https://plyint.com)생각하다. 쉘 스크립트를 다운로드할 수 있습니다.encpass.sh, github에서https://github.com/plyint/encpass.sh.

기본적으로 수행하는 작업은 각 스크립트(또는 사용자 정의 버킷)에 대해 AES 256비트 키를 생성한 다음 폴더에 액세스하기 위해 사용자만 액세스할 수 있는 홈 디렉터리 아래의 숨겨진 폴더에 해당 스크립트에 대한 모든 비밀을 암호화하는 것입니다. . 또한 키를 사용하지 않을 때 키 자체를 비밀번호로 암호화하는 잠금 명령도 제공합니다.

아래에 붙여넣은 코드는 압축된 버전이지만 github에서 전체 버전을 다운로드할 수 있습니다. MIT 라이선스를 보유하고 있어 상업적인 환경에서 사용 및 배포가 가능합니다.

 #!/bin/sh
 ################################################################################
 # Copyright (c) 2020 Plyint, LLC <[email protected]>. All Rights Reserved.
 # This file is licensed under the MIT License (MIT). 
 # Please see LICENSE.txt for more information.
 # 
 # DESCRIPTION: 
 # This script allows a user to encrypt a password (or any other secret) at 
 # runtime and then use it, decrypted, within a script.  This prevents shoulder 
 # surfing passwords and avoids storing the password in plain text, which could 
 # inadvertently be sent to or discovered by an individual at a later date.
 #
 # This script generates an AES 256 bit symmetric key for each script (or user-
 # defined bucket) that stores secrets.  This key will then be used to encrypt 
 # all secrets for that script or bucket.  encpass.sh sets up a directory 
 # (.encpass) under the user's home directory where keys and secrets will be 
 # stored.
 #
 # For further details, see README.md or run "./encpass ?" from the command line.
 #
 ################################################################################

 encpass_checks() {
    [ -n "$ENCPASS_CHECKS" ] && return

    if [ -z "$ENCPASS_HOME_DIR" ]; then
        ENCPASS_HOME_DIR="$HOME/.encpass"
    fi
    [ ! -d "$ENCPASS_HOME_DIR" ] && mkdir -m 700 "$ENCPASS_HOME_DIR"

    if [ -f "$ENCPASS_HOME_DIR/.extension" ]; then
        # Extension enabled, load it...
        ENCPASS_EXTENSION="$(cat "$ENCPASS_HOME_DIR/.extension")"
        ENCPASS_EXT_FILE="encpass-$ENCPASS_EXTENSION.sh"
        if [ -f "./extensions/$ENCPASS_EXTENSION/$ENCPASS_EXT_FILE" ]; then
            # shellcheck source=/dev/null
          . "./extensions/$ENCPASS_EXTENSION/$ENCPASS_EXT_FILE"
        elif [ ! -z "$(command -v encpass-"$ENCPASS_EXTENSION".sh)" ]; then 
            # shellcheck source=/dev/null
            . "$(command -v encpass-$ENCPASS_EXTENSION.sh)"
        else
            encpass_die "Error: Extension $ENCPASS_EXTENSION could not be found."
        fi

        # Extension specific checks, mandatory function for extensions
        encpass_"${ENCPASS_EXTENSION}"_checks
    else
        # Use default OpenSSL implementation
        if [ ! -x "$(command -v openssl)" ]; then
            echo "Error: OpenSSL is not installed or not accessible in the current path." \
                "Please install it and try again." >&2
            exit 1
        fi

        [ ! -d "$ENCPASS_HOME_DIR/keys" ] && mkdir -m 700 "$ENCPASS_HOME_DIR/keys"
        [ ! -d "$ENCPASS_HOME_DIR/secrets" ] && mkdir -m 700 "$ENCPASS_HOME_DIR/secrets"
        [ ! -d "$ENCPASS_HOME_DIR/exports" ] && mkdir -m 700 "$ENCPASS_HOME_DIR/exports"

    fi

   ENCPASS_CHECKS=1
 }

 # Checks if the enabled extension has implented the passed function and if so calls it
 encpass_ext_func() {
   [ ! -z "$ENCPASS_EXTENSION" ] && ENCPASS_EXT_FUNC="$(command -v "encpass_${ENCPASS_EXTENSION}_$1")" || return
    [ ! -z "$ENCPASS_EXT_FUNC" ] && shift && $ENCPASS_EXT_FUNC "$@" 
 }

 # Initializations performed when the script is included by another script
 encpass_include_init() {
    encpass_ext_func "include_init" "$@"
    [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    if [ -n "$1" ] && [ -n "$2" ]; then
        ENCPASS_BUCKET=$1
        ENCPASS_SECRET_NAME=$2
    elif [ -n "$1" ]; then
        if [ -z "$ENCPASS_BUCKET" ]; then
          ENCPASS_BUCKET=$(basename "$0")
        fi
        ENCPASS_SECRET_NAME=$1
    else
        ENCPASS_BUCKET=$(basename "$0")
        ENCPASS_SECRET_NAME="password"
    fi
 }

 encpass_generate_private_key() {
    ENCPASS_KEY_DIR="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET"

    [ ! -d "$ENCPASS_KEY_DIR" ] && mkdir -m 700 "$ENCPASS_KEY_DIR"

    if [ ! -f "$ENCPASS_KEY_DIR/private.key" ]; then
        (umask 0377 && printf "%s" "$(openssl rand -hex 32)" >"$ENCPASS_KEY_DIR/private.key")
    fi
 }

 encpass_set_private_key_abs_name() {
    ENCPASS_PRIVATE_KEY_ABS_NAME="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key"
    [ ! -n "$1" ] && [ ! -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ] && encpass_generate_private_key
 }

 encpass_set_secret_abs_name() {
    ENCPASS_SECRET_ABS_NAME="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET/$ENCPASS_SECRET_NAME.enc"
    [ ! -n "$1" ] && [ ! -f "$ENCPASS_SECRET_ABS_NAME" ] && set_secret
 }

 encpass_rmfifo() {
    trap - EXIT
    kill "$1" 2>/dev/null
    rm -f "$2"
 }

 encpass_mkfifo() {
    fifo="$ENCPASS_HOME_DIR/$1.$$"
    mkfifo -m 600 "$fifo" || encpass_die "Error: unable to create named pipe"
    printf '%s\n' "$fifo"
 }

 get_secret() {
    encpass_checks
    encpass_ext_func "get_secret" "$@"; [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    [ "$(basename "$0")" != "encpass.sh" ] && encpass_include_init "$1" "$2"

    encpass_set_private_key_abs_name
    encpass_set_secret_abs_name
    encpass_decrypt_secret "$@"
 }

 set_secret() {
    encpass_checks

    encpass_ext_func "set_secret" "$@"; [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    if [ "$1" != "reuse" ] || { [ -z "$ENCPASS_SECRET_INPUT" ] && [ -z "$ENCPASS_CSECRET_INPUT" ]; }; then
        echo "Enter $ENCPASS_SECRET_NAME:" >&2
        stty -echo
        read -r ENCPASS_SECRET_INPUT
        stty echo
        echo "Confirm $ENCPASS_SECRET_NAME:" >&2
        stty -echo
        read -r ENCPASS_CSECRET_INPUT
        stty echo

        # Use named pipe to securely pass secret to openssl
        fifo="$(encpass_mkfifo set_secret_fifo)"
    fi

    if [ "$ENCPASS_SECRET_INPUT" = "$ENCPASS_CSECRET_INPUT" ]; then
        encpass_set_private_key_abs_name
        ENCPASS_SECRET_DIR="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET"

        [ ! -d "$ENCPASS_SECRET_DIR" ] && mkdir -m 700 "$ENCPASS_SECRET_DIR"

        # Generate IV and create secret file
        printf "%s" "$(openssl rand -hex 16)" > "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
        ENCPASS_OPENSSL_IV="$(cat "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc")"

        echo "$ENCPASS_SECRET_INPUT" > "$fifo" &
        # Allow expansion now so PID is set
        # shellcheck disable=SC2064
        trap "encpass_rmfifo $! $fifo" EXIT HUP TERM INT TSTP

        # Append encrypted secret to IV in the secret file
        openssl enc -aes-256-cbc -e -a -iv "$ENCPASS_OPENSSL_IV" \
            -K "$(cat "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key")" \
            -in "$fifo" 1>> "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
    else
        encpass_die "Error: secrets do not match.  Please try again."
    fi
 }

 encpass_decrypt_secret() {
    encpass_ext_func "decrypt_secret" "$@"; [ ! -z "$ENCPASS_EXT_FUNC" ] && return

    if [ -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ]; then
        ENCPASS_DECRYPT_RESULT="$(dd if="$ENCPASS_SECRET_ABS_NAME" ibs=1 skip=32 2> /dev/null | openssl enc -aes-256-cbc \
            -d -a -iv "$(head -c 32 "$ENCPASS_SECRET_ABS_NAME")" -K "$(cat "$ENCPASS_PRIVATE_KEY_ABS_NAME")" 2> /dev/null)"
        if [ ! -z "$ENCPASS_DECRYPT_RESULT" ]; then
            echo "$ENCPASS_DECRYPT_RESULT"
        else
            # If a failed unlock command occurred and the user tries to show the secret
            # Present either a locked or failed decrypt error.
            if [ -f "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.lock" ]; then 
            echo "**Locked**"
            else
                # The locked file wasn't present as expected.  Let's display a failure
            echo "Error: Failed to decrypt"
            fi
        fi
    elif [ -f "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.lock" ]; then
        echo "**Locked**"
    else
        echo "Error: Unable to decrypt. The key file \"$ENCPASS_PRIVATE_KEY_ABS_NAME\" is not present."
    fi
 }

 encpass_die() {
   echo "$@" >&2
   exit 1
 }
 #LITE

관련 정보