我编写了一个 shell 脚本,它将连接数据库以执行一些操作
这是我的示例代码
#!/usr/bin/ksh
. /home/ram/.profile
sqlplus username/pwd@TNS<<EOF
select sysdate from dual;
exit;
EOF
我在系统中使用这段代码AIX
,我想要密码进行加密。
shell中有没有命令,我听说crypt
命令有一些安全问题
破解 crypt(1) 加密的程序随处可见。 Bob Baldwin 的 Crypt Breaker's Workbench [2] 于 1984-1985 年编写,是一种交互式工具,可提供必须由用户纠正的连续明文猜测。 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
我想知道有什么安全方法可以在 shell 中加密密码吗?
答案1
答案2
假设你的user
andpass
存储在user.txt
andpass.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 shell 运行的服务帐户来执行。
此时您担心的是 SSH 密钥管理,并且有许多工具可以提供帮助这。本地唯一可以获取私钥的人是具有 root 访问权限的用户,在这种情况下,您的加密密码存储对他们来说也不安全。
另一个好处是,脚本可以置于远程版本控制之下,而身份验证则留给实现细节,而不是如果代码泄漏到其实现的机器之外,则无法从脚本中提取内容。
一些数据库已经支持证书身份验证(例如 Postgresql),但使用 SSH 隧道适用于任何具有命令行客户端的数据库。我已经用它来对 MySQL 和 Postgresql 进行脚本化备份,它的作用就像一个魅力。
答案4
我遇到了类似的问题,希望有一个简单但安全的解决方案来在 shell 脚本中存储加密的秘密。我想出的最好的解决方案是将加密的密码存储在我的用户的主目录中,然后将它们读入我的脚本中。计算机上的 root 用户可能会访问这些机密,但除此之外它们是安全的。这样做的好处是允许您在代码存储库中分发或存储脚本,而无需公开您的凭据。
这个解决方案已经加班演变成我公司(Plyint -https://plyint.com)认为。您可以下载 shell 脚本,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