web-dev-qa-db-ja.com

シェルスクリプトでパスワードを非表示にする

シェルスクリプトでパスワードを非表示にするにはどうすればよいですか?データベースにアクセスしている多くのスクリプトがあります。スクリプトを開くと、他のユーザーもユーザー名とパスワードを認識します。だから誰かが隠す方法を知っているなら私に知らせてください。

私には1つの方法があります。パスワードをファイルに入れ、そのファイルを非表示にして、誰もファイルにアクセスしないようにします(アクセス許可を変更し、データベースにアクセスするときにスクリプトでファイルを使用します)。

26
arun

最初、いくつかの人々がすでに言ったように、資格情報をスクリプトから分離しておくことは不可欠です。 (セキュリティの向上に加えて、資格情報が異なる複数のシステムで同じスクリプトを再利用できることも意味します。)

2番目、資格情報のセキュリティだけでなく、それらの資格情報が侵害された場合の影響も考慮する必要があります。データベースへのすべてのアクセスに対して1つのパスワードだけではなく、さまざまなレベルのアクセス権を持つさまざまな資格情報が必要です。たとえば、データベースで検索を実行する機能を持つ1人のDBユーザーがいる可能性があります。そのユーザーには読み取り専用アクセス権が必要です。別のユーザーが新しいレコードを挿入する権限を持っているかもしれませんが、それらを削除する権限はありません。 3番目のユーザーには、レコードを削除する権限がある場合があります。

各アカウントのアクセス許可を制限することに加えて、各アカウントをどこから使用できるかも制限する必要があります。たとえば、Webサーバーが使用するアカウントは、Webサーバー以外のIPアドレスからの接続を許可しないでください。データベースに対する完全なroot権限を持つアカウントは、接続元の点で非常に制限されている必要があり、対話形式以外で使用してはなりません。また、データベースでストアドプロシージャを使用して、各アカウントで実行できることを正確に制限することも検討してください。

これらの制限は、システムのDBサーバー側に実装する必要があるため、クライアント側が危険にさらされても、制限を変更することはできません。 (そして明らかに、DBサーバーはDB構成に加えてファイアウォールなどで保護する必要があります...)

限定された読み取り専用アクセスのみが許可され、特定のIPアドレスからのアクセスのみが許可されているDBアカウントの場合、データの機密性とホストスクリプトのセキュリティに応じて、それ以上の認証情報は必要ない場合があります。から実行されています。 1つの例としては、Webページに表示される情報のみを抽出するストアドプロシージャの使用のみを許可されているユーザーで実行できる、Webサイト上の検索フォームがあります。この場合、その情報はすでに公開されることを意図しており、ユーザーは機密性の高い他のデータにアクセスできないため、パスワードを追加しても実際には追加のセキュリティは付与されません。

また、データベースへの接続がTLSを使用して行われていることを確認してください。そうしないと、ネットワークでリッスンしている誰もが資格情報を取得できます。

番目、使用する資格情報の種類を検討します。パスワードは1つの形式にすぎず、最も安全ではありません。代わりに、何らかの形式の公開/秘密鍵ペア、またはAD/PAMなどを使用できます。

4番目、スクリプトが実行される条件を検討します。

インタラクティブに実行する場合は、パスワードを入力するか、秘密鍵または秘密鍵のパスワードを入力するか、実行時に有効なKerberosチケットでログインする必要があります。つまり、スクリプトは資格情報を、ファイルから読み取るのではなく、実行時に直接あなたから。

Webサーバーから実行する場合は、Webサーバーを起動するときに資格情報を設定することを検討してください。ここでの良い例がSSL証明書です。SSL証明書には公開証明書と秘密鍵があり、秘密鍵にはパスワードがあります。秘密鍵をウェブサーバーに保存することはできますが、Apacheを起動するときに、パスワードを入力する必要があります。また、物理的なカードやHSMなど、サーバーが起動したら削除またはロックできる、ある種のハードウェアに資格情報を持たせることもできます。 (もちろん、この方法の欠点は、何かが発生した場合にサーバーが自力で再起動できないことです。システムが危険にさらされるリスクよりもこれを優先しますが、距離は異なる場合があります...)

スクリプトがcronから実行されている場合、これは難しい部分です。誰かがシステムにアクセスできるような場所に資格情報を置きたくないのですが、スクリプトがそれらにアクセスできるように資格情報を置きたくありませんか?そうですね。スクリプトが何をしているかを正確に検討してください。データベースに対してどのような権限が必要ですか?間違った人がそれらのアクセス許可で接続しても問題にならないように制限できますか?代わりに、他のユーザーがいるサーバーからではなく、他の誰もがアクセスできないDBサーバーで直接スクリプトを実行できますか?私が思いつかない何らかの理由で、あなたが絶対にmust安全でないサーバー上でスクリプトを実行していて、must危険/破壊的なことができる場合。 ..アーキテクチャを再考する良い機会です。

Fifth、データベースのセキュリティを重視する場合は、他のユーザーがアクセスできるサーバーでこれらのスクリプトを実行しないでください。誰かがあなたのシステムにログインしている場合、彼らはwillがあなたの資格を取得する可能性があります。たとえば、SSL証明書を備えたウェブサーバーの場合、少なくとも誰かがルートを取得してhttpdプロセスのメモリ領域にアクセスし、認証情報を抽出できるという理論的な可能性があります。攻撃者がログインすることを要求することさえせずに、SSLを介してこれが行われる可能性がある最近のエクスプロイトが少なくとも1つありました。

また、システムで使用可能なSELinuxやapparmorなどを使用して、どのユーザーが何を実行できるかを制限することも検討してください。これにより、ユーザーが資格情報にアクセスできたとしても、ユーザーがデータベースに接続しようとすることを禁止することができます。

これがすべてあなたにとってやり過ぎのように聞こえる場合、そしてあなたにはそれをする余裕がないか、時間がない場合-そして、私の(傲慢でエリート主義の)意見では、あなたは何も保存すべきではありませんデータベースで重要または機密。重要な情報や機密情報を保存しない場合は、資格情報を保存する場所も重要ではありません。この場合、なぜパスワードを使用するのでしょうか。

最後に、ある種の資格情報の保存を絶対に避けられない場合、資格情報を読み取り専用にしてrootが所有することができ、rootはスクリプトから要求されたときに非常に一時的に所有権を付与できます(スクリプトはnotが絶対に必要でない限りrootとして実行する必要があり、データベースに接続しても必要にならないため)。しかし、それはまだ良い考えではありません。

41
Jenny D

まず、パスワードを最初からスクリプトの内部または横に保存する必要がないように変更できる方法がある場合は、そうするためにあらゆる努力をする必要があります。 ジェニーDの回答 には、その効果についての良いアドバイスがたくさん含まれています。

それ以外の場合は、制限されたアクセス許可を持つ別のファイルにパスワードを配置するという考えは、ほとんどそれです。たとえば、メインスクリプトからそのファイルを入手できます。

. /usr/local/etc/secret-password-here

また、メインスクリプトの権限を制限して、許可された人だけが実行できるようにすることもできますが、パスワード自体のみを制限されたファイルに保存することをお勧めします。そうすれば、コード自体の検査(機密情報なしで)、バージョン管理、スクリプトのコピーなどをより簡単に行えるようになります。

13
Celada

他の答えはhowに対応していますが、私はwhetherについて検討します。ユーザーが接続しているデータベースの種類に応じて、クライアントプログラムで既に使用されている適切なメカニズムがすでにある場合があります。その場合は、必ずそれらを使用してください(~/.mysqlrcまたは~/.pgpass)。

複数のユーザーがデータベースにアクセスして、共有アカウントを使用して特定のクエリを実行できるようにする場合は、おそらく許可しないでください。代わりに、データベースにアカウントがあり、それらのアカウントに必要以上の権限がないことを確認してください(おそらく、そのほとんどを読み取り、書き込みアクセスはほとんどありません)。他の方法ではアクセスできない特定のテーブルに対して特定のクエリを実行する必要がある場合は、ストアドプロシージャにSECURTY DEFINERを提供して、アクセスを許可します。

上記のいずれでも資格情報を保存する必要がない場合は、then他の回答をここで読んでください。

3
Toby Speight

アクセスできない場所にパスワードを隠すという考えは、状況によっては問題ないかもしれません。

情報が個別の場合、それはファイルの単純な編集を意味します。同僚とのコードレビュー中にそれを表示するつもりはありません。しかし、あなたのアカウントにアクセスできる人なら誰でも簡単にそのようなファイルを見つけることができることを理解してください。そのような目的で~/.sshのサブディレクトリを使用しました。これは、~/.sshのアクセス権が十分に制限されていない場合にsshが不平を言うという単純な理由によります。

ただし、ユーザー名やパスワードのこのようなちらつきを防ぐためにできることは他にもあります。

Obfuscating:スクリプトの編集中にユーザー名またはパスワードを誰にも読まれたくない場合は、テキストに挿入できますが、プレーンテキストではなく、難読化できます。難読化されたバージョンが十分に長く、それを見る誰かによるその記憶を妨げている場合、復号化の方法とキーが明白に見えても、それを知ることはできません。もちろん、これはまだあなたのアカウントにアクセスできる誰かによって簡単に回避されるでしょう。

GPGを使用

少し良いですが、システムのrootユーザーによる攻撃に対する完全な証拠ではありませんが、ユーザー名とパスワードのペアをファイルgpg publicで暗号化し、スクリプトがファイルのコンテンツを取得するようにすることもできます(可能であればプロンプトが表示されます)パスワードの場合、キャッシュ/期限切れでない場合)。私はggp-cardを使用するので、ラップトップを置いたままカードを引き出すと、ピンがまだキャッシュされていてもアクセスできません。少なくとも数分で20回実行する場合、ピンを1回だけ指定する必要があります。

セキュリティは常に利便性(設定と使用)に反比例しているようです。

1
Anthon

私もこの問題に遭遇しました。簡単な答えは、パスワードをスクリプトとは別に保存して、スクリプトを環境からパスワードにロードさせることです。どれがそれを行うのが最善かという疑問を投げかけますか?

理想的には、HashiCorp Vaultなどの外部サービスを使用して、シェル環境にプルすることができます。ただし、Vaultは設定がかなり複雑な獣であり、多くのエンタープライズ環境では、インストールできるものや、使用できるシェルのタイプさえ制限される場合があります。

このため、私は encpass.sh-シェルスクリプトで暗号化されたパスワードを使用するための軽量ソリューション を作成しました。これにより、ユーザーだけがアクセスできる非表示のディレクトリにシークレットを保存できます。これはPOSIX準拠のシェルで動作するはずであり、唯一の依存関係は、シークレットの暗号化を処理するためにOpenSSLをローカルボックスにインストールすることです。あなたがしなければならないすべてはあなたのスクリプトにそれを含めて、 "get_secret"関数を呼び出すことです。 MITライセンスがあるため、企業環境で使用できます。私の会社 Plyint LLC は、スクリプトを管理し、更新を時々リリースします。コピーします見やすくするために以下のコード。

#!/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() {
    if [ -n "$ENCPASS_CHECKS" ]; then
        return
    fi

    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

    if [ -z "$ENCPASS_HOME_DIR" ]; then
        ENCPASS_HOME_DIR=$(encpass_get_abs_filename ~)/.encpass
    fi

    if [ ! -d "$ENCPASS_HOME_DIR" ]; then
        mkdir -m 700 "$ENCPASS_HOME_DIR"
        mkdir -m 700 "$ENCPASS_HOME_DIR/keys"
        mkdir -m 700 "$ENCPASS_HOME_DIR/secrets"
    fi

    if [ "$(basename "$0")" != "encpass.sh" ]; then
        encpass_include_init "$1" "$2"
    fi

    ENCPASS_CHECKS=1
}

# Initializations performed when the script is included by another script
encpass_include_init() {
    if [ -n "$1" ] && [ -n "$2" ]; then
        ENCPASS_BUCKET=$1
        ENCPASS_SECRET_NAME=$2
    Elif [ -n "$1" ]; then
        ENCPASS_BUCKET=$(basename "$0")
        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"

    if [ ! -d "$ENCPASS_KEY_DIR" ]; then
        mkdir -m 700 "$ENCPASS_KEY_DIR"
    fi

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

encpass_get_private_key_abs_name() {
    ENCPASS_PRIVATE_KEY_ABS_NAME="$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key"

    if [ "$1" != "nogenerate" ]; then 
        if [ ! -f "$ENCPASS_PRIVATE_KEY_ABS_NAME" ]; then
            encpass_generate_private_key
        fi
    fi
}

encpass_get_secret_abs_name() {
    ENCPASS_SECRET_ABS_NAME="$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET/$ENCPASS_SECRET_NAME.enc"

    if [ "$3" != "nocreate" ]; then 
        if [ ! -f "$ENCPASS_SECRET_ABS_NAME" ]; then
            set_secret "$1" "$2"
        fi
    fi
}

get_secret() {
    encpass_checks "$1" "$2"
    encpass_get_private_key_abs_name
    encpass_get_secret_abs_name "$1" "$2"
    encpass_decrypt_secret
}

set_secret() {
    encpass_checks "$1" "$2"

    if [ "$3" != "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
    fi

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

        if [ ! -d "$ENCPASS_SECRET_DIR" ]; then
            mkdir -m 700 "$ENCPASS_SECRET_DIR"
        fi

        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" | openssl enc -aes-256-cbc -e -a -iv \
            "$ENCPASS_OPENSSL_IV" -K \
            "$(cat "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET/private.key")" 1>> \
                    "$ENCPASS_SECRET_DIR/$ENCPASS_SECRET_NAME.enc"
    else
        echo "Error: secrets do not match.  Please try again." >&2
        exit 1
    fi
}

encpass_get_abs_filename() {
    # $1 : relative filename
    filename="$1"
    parentdir="$(dirname "${filename}")"

    if [ -d "${filename}" ]; then
        cd "${filename}" && pwd
    Elif [ -d "${parentdir}" ]; then
        echo "$(cd "${parentdir}" && pwd)/$(basename "${filename}")"
    fi
}

encpass_decrypt_secret() {
    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 locked or decrypt command
            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
}


##########################################################
# COMMAND LINE MANAGEMENT SUPPORT
# -------------------------------
# If you don't need to manage the secrets for the scripts
# with encpass.sh you can delete all code below this point
# in order to significantly reduce the size of encpass.sh.
# This is useful if you want to bundle encpass.sh with
# your existing scripts and just need the retrieval
# functions.
##########################################################

encpass_show_secret() {
    encpass_checks
    ENCPASS_BUCKET=$1

    encpass_get_private_key_abs_name "nogenerate"

    if [ ! -z "$2" ]; then
        ENCPASS_SECRET_NAME=$2
        encpass_get_secret_abs_name "$1" "$2" "nocreate"
        if [ -z "$ENCPASS_SECRET_ABS_NAME" ]; then
            echo "No secret named $2 found for bucket $1."
            exit 1
        fi

        encpass_decrypt_secret
    else
        ENCPASS_FILE_LIST=$(ls -1 "$ENCPASS_HOME_DIR"/secrets/"$1")
        for ENCPASS_F in $ENCPASS_FILE_LIST; do
            ENCPASS_SECRET_NAME=$(basename "$ENCPASS_F" .enc)

            encpass_get_secret_abs_name "$1" "$ENCPASS_SECRET_NAME" "nocreate"
            if [ -z "$ENCPASS_SECRET_ABS_NAME" ]; then
                echo "No secret named $ENCPASS_SECRET_NAME found for bucket $1."
                exit 1
            fi

            echo "$ENCPASS_SECRET_NAME = $(encpass_decrypt_secret)"
        done
    fi
}

encpass_getche() {
        old=$(stty -g)
        stty raw min 1 time 0
        printf '%s' "$(dd bs=1 count=1 2>/dev/null)"
        stty "$old"
}

encpass_remove() {
    if [ ! -n "$ENCPASS_FORCE_REMOVE" ]; then
        if [ ! -z "$ENCPASS_SECRET" ]; then
            printf "Are you sure you want to remove the secret \"%s\" from bucket \"%s\"? [y/N]" "$ENCPASS_SECRET" "$ENCPASS_BUCKET"
        else
            printf "Are you sure you want to remove the bucket \"%s?\" [y/N]" "$ENCPASS_BUCKET"
        fi

        ENCPASS_CONFIRM="$(encpass_getche)"
        printf "\n"
        if [ "$ENCPASS_CONFIRM" != "Y" ] && [ "$ENCPASS_CONFIRM" != "y" ]; then
            exit 0
        fi
    fi

    if [ ! -z "$ENCPASS_SECRET" ]; then
        rm -f "$1"
        printf "Secret \"%s\" removed from bucket \"%s\".\n" "$ENCPASS_SECRET" "$ENCPASS_BUCKET"
    else
        rm -Rf "$ENCPASS_HOME_DIR/keys/$ENCPASS_BUCKET"
        rm -Rf "$ENCPASS_HOME_DIR/secrets/$ENCPASS_BUCKET"
        printf "Bucket \"%s\" removed.\n" "$ENCPASS_BUCKET"
    fi
}

encpass_save_err() {
    if read -r x; then
        { printf "%s\n" "$x"; cat; } > "$1"
    Elif [ "$x" != "" ]; then
        printf "%s" "$x" > "$1"
    fi
}

encpass_help() {
less << EOF
NAME:
    encpass.sh - Use encrypted passwords in Shell scripts

DESCRIPTION: 
    A lightweight solution for using encrypted passwords in Shell scripts 
    using OpenSSL. It 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, 
    within a script, 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.

    Subsequent calls to retrieve a secret will not Prompt for a secret to be 
    entered as the file with the encrypted value already exists.

    Note: By default, encpass.sh sets up a directory (.encpass) under the 
    user's home directory where keys and secrets will be stored.  This directory
    can be overridden by setting the environment variable ENCPASS_HOME_DIR to a
    directory of your choice.

    ~/.encpass (or the directory specified by ENCPASS_HOME_DIR) will contain 
    the following subdirectories:
      - keys (Holds the private key for each script/bucket)
      - secrets (Holds the secrets stored for each script/bucket)

USAGE:
    To use the encpass.sh script in an existing Shell script, source the script 
    and then call the get_secret function.

    Example:

        #!/bin/sh
        . encpass.sh
        password=\$(get_secret)

    When no arguments are passed to the get_secret function,
    then the bucket name is set to the name of the script and
    the secret name is set to "password".

    There are 2 other ways to call get_secret:

      Specify the secret name:
      Ex: \$(get_secret user)
        - bucket name = <script name>
        - secret name = "user"

      Specify both the secret name and bucket name:
      Ex: \$(get_secret personal user)
        - bucket name = "personal"
        - secret name = "user"

    encpass.sh also provides a command line interface to manage the secrets.
    To invoke a command, pass it as an argument to encpass.sh from the Shell.

        $ encpass.sh [COMMAND]

    See the COMMANDS section below for a list of available commands.  Wildcard
    handling is implemented for secret and bucket names.  This enables
    performing operations like adding/removing a secret to/from multiple buckets
        at once.

COMMANDS:
    add [-f] <bucket> <secret>
        Add a secret to the specified bucket.  The bucket will be created
        if it does not already exist. If a secret with the same name already
        exists for the specified bucket, then the user will be prompted to
        confirm overwriting the value.  If the -f option is passed, then the
        add operation will perform a forceful overwrite of the value. (i.e. no
        Prompt)

    list|ls [<bucket>]
        Display the names of the secrets held in the bucket.  If no bucket
        is specified, then the names of all existing buckets will be
        displayed.

    lock
        Locks all keys used by encpass.sh using a password.  The user
        will be prompted to enter a password and confirm it.  A user
        should take care to securely store the password.  If the password
        is lost then keys can not be unlocked.  When keys are locked,
        secrets can not be retrieved. (e.g. the output of the values
        in the "show" command will be encrypted/garbage)

    remove|rm [-f] <bucket> [<secret>]
        Remove a secret from the specified bucket.  If only a bucket is
        specified then the entire bucket (i.e. all secrets and keys) will
        be removed.  By default the user is asked to confirm the removal of
        the secret or the bucket.  If the -f option is passed then a 
        forceful removal will be performed.  (i.e. no Prompt)

    show [<bucket>] [<secret>]
        Show the unencrypted value of the secret from the specified bucket.
        If no secret is specified then all secrets for the bucket are displayed.

    update <bucket> <secret>
        Updates a secret in the specified bucket.  This command is similar
        to using an "add -f" command, but it has a safety check to only 
        proceed if the specified secret exists.  If the secret, does not
        already exist, then an error will be reported. There is no forceable
        update implemented.  Use "add -f" for any required forceable update
        scenarios.

    unlock
        Unlocks all the keys for encpass.sh.  The user will be prompted to 
        enter the password and confirm it.

    dir
        Prints out the current value of the ENCPASS_HOME_DIR environment variable.

    help|--help|usage|--usage|?
        Display this help message.
EOF
}

# Subcommands for cli support
case "$1" in
    add )
        shift
        while getopts ":f" ENCPASS_OPTS; do
            case "$ENCPASS_OPTS" in
                f ) ENCPASS_FORCE_ADD=1;;
            esac
        done

        encpass_checks

        if [ -n "$ENCPASS_FORCE_ADD" ]; then
            shift $((OPTIND-1))
        fi

        if [ ! -z "$1" ] && [ ! -z "$2" ]; then
            # Allow globbing
            # shellcheck disable=SC2027,SC2086
            ENCPASS_ADD_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
            if [ -z "$ENCPASS_ADD_LIST" ]; then
                ENCPASS_ADD_LIST="$1"
            fi

            for ENCPASS_ADD_F in $ENCPASS_ADD_LIST; do
                ENCPASS_ADD_DIR="$(basename "$ENCPASS_ADD_F")"
                ENCPASS_BUCKET="$ENCPASS_ADD_DIR"
                if [ ! -n "$ENCPASS_FORCE_ADD" ] && [ -f "$ENCPASS_ADD_F/$2.enc" ]; then
                    echo "Warning: A secret with the name \"$2\" already exists for bucket $ENCPASS_BUCKET."
                    echo "Would you like to overwrite the value? [y/N]"

                    ENCPASS_CONFIRM="$(encpass_getche)"
                    if [ "$ENCPASS_CONFIRM" != "Y" ] && [ "$ENCPASS_CONFIRM" != "y" ]; then
                        continue
                    fi
                fi

                ENCPASS_SECRET_NAME="$2"
                echo "Adding secret \"$ENCPASS_SECRET_NAME\" to bucket \"$ENCPASS_BUCKET\"..."
                set_secret "$ENCPASS_BUCKET" "$ENCPASS_SECRET_NAME" "reuse"
            done
        else
            echo "Error: A bucket name and secret name must be provided when adding a secret."
            exit 1
        fi
        ;;
    update )
        shift

        encpass_checks
        if [ ! -z "$1" ] && [ ! -z "$2" ]; then

            ENCPASS_SECRET_NAME="$2"
            # Allow globbing
            # shellcheck disable=SC2027,SC2086
            ENCPASS_UPDATE_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"

            for ENCPASS_UPDATE_F in $ENCPASS_UPDATE_LIST; do
                # Allow globbing
                # shellcheck disable=SC2027,SC2086
                if [ -f "$ENCPASS_UPDATE_F/"$2".enc" ]; then
                        ENCPASS_UPDATE_DIR="$(basename "$ENCPASS_UPDATE_F")"
                        ENCPASS_BUCKET="$ENCPASS_UPDATE_DIR"
                        echo "Updating secret \"$ENCPASS_SECRET_NAME\" to bucket \"$ENCPASS_BUCKET\"..."
                        set_secret "$ENCPASS_BUCKET" "$ENCPASS_SECRET_NAME" "reuse"
                else
                    echo "Error: A secret with the name \"$2\" does not exist for bucket $1."
                    exit 1
                fi
            done
        else
            echo "Error: A bucket name and secret name must be provided when updating a secret."
            exit 1
        fi
        ;;
    rm|remove )
        shift
        encpass_checks

        while getopts ":f" ENCPASS_OPTS; do
            case "$ENCPASS_OPTS" in
                f ) ENCPASS_FORCE_REMOVE=1;;
            esac
        done

        if [ -n "$ENCPASS_FORCE_REMOVE" ]; then
            shift $((OPTIND-1))
        fi

        if [ -z "$1" ]; then 
            echo "Error: A bucket must be specified for removal."
        fi

        # Allow globbing
        # shellcheck disable=SC2027,SC2086
        ENCPASS_REMOVE_BKT_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
        if [ ! -z "$ENCPASS_REMOVE_BKT_LIST" ]; then
            for ENCPASS_REMOVE_B in $ENCPASS_REMOVE_BKT_LIST; do

                ENCPASS_BUCKET="$(basename "$ENCPASS_REMOVE_B")"
                if [ ! -z "$2" ]; then
                    # Removing secrets for a specified bucket
                    # Allow globbing
                    # shellcheck disable=SC2027,SC2086
                    ENCPASS_REMOVE_LIST="$(ls -1p "$ENCPASS_REMOVE_B/"$2".enc" 2>/dev/null)"

                    if [ -z "$ENCPASS_REMOVE_LIST" ]; then
                        echo "Error: No secrets found for $2 in bucket $ENCPASS_BUCKET."
                        exit 1
                    fi

                    for ENCPASS_REMOVE_F in $ENCPASS_REMOVE_LIST; do
                        ENCPASS_SECRET="$2"
                        encpass_remove "$ENCPASS_REMOVE_F"
                    done
                else
                    # Removing a specified bucket
                    encpass_remove
                fi

            done
        else
            echo "Error: The bucket named $1 does not exist."
            exit 1
        fi
        ;;
    show )
        shift
        encpass_checks
        if [ -z "$1" ]; then
            ENCPASS_SHOW_DIR="*"
        else
            ENCPASS_SHOW_DIR=$1
        fi

        if [ ! -z "$2" ]; then
            # Allow globbing
            # shellcheck disable=SC2027,SC2086
            if [ -f "$(encpass_get_abs_filename "$ENCPASS_HOME_DIR/secrets/$ENCPASS_SHOW_DIR/"$2".enc")" ]; then
                encpass_show_secret "$ENCPASS_SHOW_DIR" "$2"
            fi
        else
            # Allow globbing
            # shellcheck disable=SC2027,SC2086
            ENCPASS_SHOW_LIST="$(ls -1d "$ENCPASS_HOME_DIR/secrets/"$ENCPASS_SHOW_DIR"" 2>/dev/null)"

            if [ -z "$ENCPASS_SHOW_LIST" ]; then
                if [ "$ENCPASS_SHOW_DIR" = "*" ]; then
                    echo "Error: No buckets exist."
                else
                    echo "Error: Bucket $1 does not exist."
                fi
                exit 1
            fi

            for ENCPASS_SHOW_F in $ENCPASS_SHOW_LIST; do
                ENCPASS_SHOW_DIR="$(basename "$ENCPASS_SHOW_F")"
                echo "$ENCPASS_SHOW_DIR:"
                encpass_show_secret "$ENCPASS_SHOW_DIR"
                echo " "
            done
        fi
        ;;
    ls|list )
        shift
        encpass_checks
        if [ ! -z "$1" ]; then
            # Allow globbing
            # shellcheck disable=SC2027,SC2086
            ENCPASS_FILE_LIST="$(ls -1p "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"

            if [ -z "$ENCPASS_FILE_LIST" ]; then
                # Allow globbing
                # shellcheck disable=SC2027,SC2086
                ENCPASS_DIR_EXISTS="$(ls -d "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
                if [ ! -z "$ENCPASS_DIR_EXISTS" ]; then
                    echo "Bucket $1 is empty."
                else
                    echo "Error: Bucket $1 does not exist."
                fi
                exit 1
            fi

            ENCPASS_NL=""
            for ENCPASS_F in $ENCPASS_FILE_LIST; do
                if [ -d "${ENCPASS_F%:}" ]; then
                    printf "$ENCPASS_NL%s\n" "$(basename "$ENCPASS_F")"
                    ENCPASS_NL="\n"
                else
                    printf "%s\n" "$(basename "$ENCPASS_F" .enc)"
                fi
            done
        else
            # Allow globbing
            # shellcheck disable=SC2027,SC2086
            ENCPASS_BUCKET_LIST="$(ls -1p "$ENCPASS_HOME_DIR/secrets/"$1"" 2>/dev/null)"
            for ENCPASS_C in $ENCPASS_BUCKET_LIST; do
                if [ -d "${ENCPASS_C%:}" ]; then
                    printf "\n%s" "\n$(basename "$ENCPASS_C")"
                else
                    basename "$ENCPASS_C" .enc
                fi
            done
        fi
        ;;
    lock )
        shift
        encpass_checks

        echo "************************!!!WARNING!!!*************************" >&2
        echo "* You are about to lock your keys with a password.           *" >&2
        echo "* You will not be able to use your secrets again until you   *" >&2
        echo "* unlock the keys with the same password. It is important    *" >&2
        echo "* that you securely store the password, so you can recall it *" >&2
        echo "* in the future.  If you forget your password you will no    *" >&2
        echo "* longer be able to access your secrets.                     *" >&2
        echo "************************!!!WARNING!!!*************************" >&2

        printf "\n%s\n" "About to lock keys held in directory $ENCPASS_HOME_DIR/keys/"

        printf "\nEnter Password to lock keys:" >&2
        stty -echo
        read -r ENCPASS_KEY_PASS
        printf "\nConfirm Password:" >&2
        read -r ENCPASS_CKEY_PASS
        printf "\n"
        stty echo

        if [ -z "$ENCPASS_KEY_PASS" ]; then
            echo "Error: You must supply a password value."
            exit 1
        fi

        if [ "$ENCPASS_KEY_PASS" = "$ENCPASS_CKEY_PASS" ]; then
            ENCPASS_NUM_KEYS_LOCKED=0
            ENCPASS_KEYS_LIST="$(ls -1d "$ENCPASS_HOME_DIR/keys/"*"/" 2>/dev/null)"
            for ENCPASS_KEY_F in $ENCPASS_KEYS_LIST; do

                if [ -d "${ENCPASS_KEY_F%:}" ]; then
                    ENCPASS_KEY_NAME="$(basename "$ENCPASS_KEY_F")"
                    ENCPASS_KEY_VALUE=""
                    if [ -f "$ENCPASS_KEY_F/private.key" ]; then
                        ENCPASS_KEY_VALUE="$(cat "$ENCPASS_KEY_F/private.key")"
                        if [ ! -f "$ENCPASS_KEY_F/private.lock" ]; then
                        echo "Locking key $ENCPASS_KEY_NAME..."
                        else
                          echo "Error: The key $ENCPASS_KEY_NAME appears to have been previously locked."
                            echo "       The current key file may hold a bad value. Exiting to avoid encrypting"
                            echo "       a bad value and overwriting the lock file."
                            exit 1
                        fi
                    else
                        echo "Error: Private key file ${ENCPASS_KEY_F}private.key missing for bucket $ENCPASS_KEY_NAME."
                        exit 1
                    fi
                    if [ ! -z "$ENCPASS_KEY_VALUE" ]; then
                        openssl enc -aes-256-cbc -pbkdf2 -iter 10000 -salt -in "$ENCPASS_KEY_F/private.key" -out "$ENCPASS_KEY_F/private.lock" -k "$ENCPASS_KEY_PASS"
                        if [ -f "$ENCPASS_KEY_F/private.key" ] && [ -f "$ENCPASS_KEY_F/private.lock" ]; then
                            # Both the key and lock file exist.  We can remove the key file now
                            rm -f "$ENCPASS_KEY_F/private.key"
                            echo "Locked key $ENCPASS_KEY_NAME."
                            ENCPASS_NUM_KEYS_LOCKED=$(( ENCPASS_NUM_KEYS_LOCKED + 1 ))
                        else
                            echo "Error: The key fle and/or lock file were not found as expected for key $ENCPASS_KEY_NAME."
                        fi
                    else
                        echo "Error: No key value found for the $ENCPASS_KEY_NAME key."
                        exit 1
                    fi
                fi
            done
            echo "Locked $ENCPASS_NUM_KEYS_LOCKED keys."
        else
            echo "Error: Passwords do not match."
        fi
        ;;
    unlock )
        shift
        encpass_checks

        printf "%s\n" "About to unlock keys held in the $ENCPASS_HOME_DIR/keys/ directory."

        printf "\nEnter Password to unlock keys: " >&2
        stty -echo
        read -r ENCPASS_KEY_PASS
        printf "\n"
        stty echo

        if [ ! -z "$ENCPASS_KEY_PASS" ]; then
            ENCPASS_NUM_KEYS_UNLOCKED=0
            ENCPASS_KEYS_LIST="$(ls -1d "$ENCPASS_HOME_DIR/keys/"*"/" 2>/dev/null)"
            for ENCPASS_KEY_F in $ENCPASS_KEYS_LIST; do

                if [ -d "${ENCPASS_KEY_F%:}" ]; then
                    ENCPASS_KEY_NAME="$(basename "$ENCPASS_KEY_F")"
                    echo "Unlocking key $ENCPASS_KEY_NAME..."
                    if [ -f "$ENCPASS_KEY_F/private.key" ] && [ ! -f "$ENCPASS_KEY_F/private.lock" ]; then
                        echo "Error: Key $ENCPASS_KEY_NAME appears to be unlocked already."
                        exit 1
                    fi

                    if [ -f "$ENCPASS_KEY_F/private.lock" ]; then
                        # Remove the failed file in case previous decryption attempts were unsuccessful
                        rm -f "$ENCPASS_KEY_F/failed" 2>/dev/null

                        # Decrypt key. Log any failure to the "failed" file.
                        openssl enc -aes-256-cbc -d -pbkdf2 -iter 10000 -salt \
                            -in "$ENCPASS_KEY_F/private.lock" -out "$ENCPASS_KEY_F/private.key" \
                            -k "$ENCPASS_KEY_PASS" 2>&1 | encpass_save_err "$ENCPASS_KEY_F/failed"

                        if [ ! -f "$ENCPASS_KEY_F/failed" ]; then
                            # No failure has occurred.
                          if [ -f "$ENCPASS_KEY_F/private.key" ] && [ -f "$ENCPASS_KEY_F/private.lock" ]; then
                              # Both the key and lock file exist.  We can remove the lock file now.
                              rm -f "$ENCPASS_KEY_F/private.lock"
                              echo "Unlocked key $ENCPASS_KEY_NAME."
                              ENCPASS_NUM_KEYS_UNLOCKED=$(( ENCPASS_NUM_KEYS_UNLOCKED + 1 ))
                          else
                              echo "Error: The key file and/or lock file were not found as expected for key $ENCPASS_KEY_NAME."
                          fi
                        else
                          printf "Error: Failed to unlock key %s.\n" "$ENCPASS_KEY_NAME"
                            printf "       Please view %sfailed for details.\n" "$ENCPASS_KEY_F"
                        fi
                    else
                        echo "Error: No lock file found for the $ENCPASS_KEY_NAME key."
                    fi
                fi
            done
            echo "Unlocked $ENCPASS_NUM_KEYS_UNLOCKED keys."
        else
            echo "No password entered."
        fi
        ;;
    dir )
        shift
        encpass_checks
        echo "ENCPASS_HOME_DIR=$ENCPASS_HOME_DIR"
        ;;
    help|--help|usage|--usage|\? )
        encpass_checks
        encpass_help
        ;;
    * )
        if [ ! -z "$1" ]; then
            echo "Command not recognized. See \"encpass.sh help\" for a list commands."
            exit 1
        fi
        ;;
esac
0
Alexander Nick

Bashスクリプトにパスワードを保存する方法はありますが、スクリプトを暗号化および難読化して、だれも実際にスクリプトを読み取ったり、実行したりできないようにする必要がありますデバッガーを使用して、それが何をしているかを正確に確認します。 bash/Shellスクリプトを暗号化して難読化し、実際に実行可能にするには、ここにコピーして貼り付けてみてください。

http://www.kinglazy.com/Shell-script-encryption-kinglazy-shieldx.htm

上記のページでは、スクリプトを送信するだけです(安心のために、最初にサンプルスクリプトを送信できます)。 Zipファイルが生成されます。ダウンロードリンクを右クリックして、提供されたURLをコピーします。次に、UNIXボックスに移動して、次の手順を実行します。

インストール:

  1. wgetリンク先のZIPファイル

  2. 新しくダウンロードしたZipファイルを解凍します

  3. cd/tmp/KingLazySHIELD

  4. ./install.sh/var/tmp/KINGLAZY/SHIELDX-(your-script-name)/ home /(your-username)-force

上記のインストールコマンドがあなたのために何をするかです:

  1. 暗号化されたバージョンのスクリプトが/ var/tmp/KINGLAZY/SHIELDX-(your-script-name)ディレクトリにインストールされます。

  2. この暗号化されたスクリプトへのリンクは、/ home /(your-username)の代わりに指定したディレクトリに配置されます。これにより、絶対パスを入力しなくてもスクリプトに簡単にアクセスできます。

  3. 誰もスクリプトを変更できないことを保証します-暗号化されたスクリプトを変更しようとすると、その操作が停止または削除されるまで操作できなくなります誰かがスクリプトを実行する以外にスクリプトで何かを行おうとしたときに通知するように設定することもできます...ハッキングまたは改ざんの試み。

  4. 誰もそれをコピーできないようにします。だれもスクリプトを人里離れた場所にコピーして、それをいじってみて、どのように機能するかを確認することはできません。スクリプトのすべてのコピーは、インストール(ステップ4)中に指定した元の場所へのリンクでなければなりません。

注:

これが、ユーザーに応答を促すインタラクティブスクリプトで機能するとは思わない。値はスクリプトにハードコーディングする必要があります。暗号化により、実際にこれらの値を誰も見ることができないため、心配する必要はありません。

0
AncientMinds

セキュリティを考慮しない別の解決策(資格情報を別のファイルまたはデータベースに保存する方が良いと思います)は、gpgでパスワードを暗号化してスクリプトに挿入することです。

私はusbに保管しているパスワードなしのgpgキーペアを使用しています。 (注:このキーペアをエクスポートする場合は、-armorを使用せず、バイナリ形式でエクスポートしてください)。

最初にパスワードを暗号化します。

echo -n "pAssw0rd" | gpg --armor --no-default-keyring --keyring /media/usb/key.pub --recipient [email protected] --encrypt

これは、標準出力にgpg暗号化パスワードを出力します。メッセージ全体をコピーし、これをスクリプトに追加します。

password=$(gpg --batch --quiet --no-default-keyring --secret-keyring /media/usb/key.priv --decrypt <<EOF 
-----BEGIN PGP MESSAGE-----

hQEMA0CjbyauRLJ8AQgAkZT5gK8TrdH6cZEy+Ufl0PObGZJ1YEbshacZb88RlRB9
h2z+s/Bso5HQxNd5tzkwulvhmoGu6K6hpMXM3mbYl07jHF4qr+oWijDkdjHBVcn5
0mkpYO1riUf0HXIYnvCZq/4k/ajGZRm8EdDy2JIWuwiidQ18irp07UUNO+AB9mq8
5VXUjUN3tLTexg4sLZDKFYGRi4fyVrYKGsi0i5AEHKwn5SmTb3f1pa5yXbv68eYE
lCVfy51rBbG87UTycZ3gFQjf1UkNVbp0WV+RPEM9JR7dgR+9I8bKCuKLFLnGaqvc
beA3A6eMpzXQqsAg6GGo3PW6fMHqe1ZCvidi6e4a/dJDAbHq0XWp93qcwygnWeQW
Ozr1hr5mCa+QkUSymxiUrRncRhyqSP0ok5j4rjwSJu9vmHTEUapiyQMQaEIF2e2S
/NIWGg==
=uriR
-----END PGP MESSAGE-----
EOF)

この方法で、USBがシステムにマウントされている場合にのみ、パスワードを復号化できます。もちろん、システムにキーをインポートすることもできます(安全性が低い、またはセキュリティがまったくない)。または、秘密キーをパスワードで保護することもできます(自動化できません)。

0
Juanu