Скрытие секрета от параметра командной строки в Unix - PullRequest
30 голосов
/ 30 сентября 2010

У меня есть скрипт, который запускает внутри себя команду с секретным параметром.Например:

#!/bin/bash
command-name secret

При выполнении команды я могу прочитать ps -ef | grep command-name, который является секретом.

Есть ли способ скрыть секрет таким образом, чтобы через ps -ef, параметр командной строки запутан?

Ответы [ 10 ]

9 голосов
/ 30 сентября 2010

Если секрет не меняется между выполнениями, используйте специальный файл конфигурации ".appsecrets".Установите права доступа файла только для чтения владельцем.Внутри файла установите переменную окружения для секрета.Файл должен находиться в домашнем каталоге пользователя, выполняющего команду.

#!/bin/bash  
#filename: .appsecrets
set SECRET=polkalover  

Загрузите файл конфигурации, чтобы установить переменную среды.

. ~/.appsecrets

То, что я видел, сделано:

1)
echo $SECRET | command

работает, если команда запрашивает парольиз стандартного ввода И если 'эхо' является встроенным в вашей оболочке.Мы использовали Korn.

2)
password=$ENV{"SECRET"};

работает, если у вас есть контроль над кодом (например, в Perl или C ++)

3)
. ./.app.config #sets the environment variables<br> isql -host [host] -user [user] -password <<SECRET<br> ${SQLPASSWORD}<br> SECRET

работает, если команда может принять секрет из стандартного ввода.Одно ограничение заключается в том, что строка << должна быть последним аргументом команды.Это может быть проблематично, если есть не необязательный аргумент, который должен появляться после -password

Преимущество этого подхода заключается в том, что вы можете расположить его так, чтобы секрет можно было скрыть в процессе производства.Используйте то же имя файла в рабочей среде, но оно будет находиться в домашнем каталоге учетной записи, которая запускает команду в рабочей среде.Затем вы можете заблокировать доступ к секрету, как если бы вы имели доступ к учетной записи root.Только определенные люди могут 'su' использовать учетную запись prod для просмотра или сохранения секрета, в то время как разработчики все еще могут запускать программу, потому что они используют свой собственный файл '.appsecret' в своем домашнем каталоге.

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

(WRONG WAY)
Один старый метод, который я видел, как администраторы БД использовалидолжен был установить SYBASE на "/opt/././././././././././././././././././././././././././././././././././sybase/bin".Поэтому их командные строки были такими длинными, что ps обрезал их.Но в Linux я думаю, что вы можете найти полную командную строку из /proc.

9 голосов
/ 21 января 2015
  1. Во-первых, вы НЕ можете скрывать аргументы командной строки.Они по-прежнему будут видны через ps aux и cat /proc/$YOUR_PROCESS_PID/cmdline во время запуска программы (до того, как программа сможет внести изменения во время выполнения в аргументы).Хорошей новостью является то, что вы все еще можете иметь секрет, используя альтернативы:

  2. Используйте переменные окружения.Если ваша программа может их прочитать, выполните следующие действия:

    mySecret='hello-neo' myCommand
    
  3. Используйте стандартный ввод:

    mySecret='hello-neo' printenv mySecret | myCommand
    
  4. Используйте дескриптор временного файла:

    myCommand <( mySecret='hello-neo' printenv mySecret )
    

В последнем случае ваша программа будет запускаться как myCommand /dev/fd/67, где содержимое /dev/fd/67 является вашим секретом (hello-neo в этом примере).


Во всех вышеперечисленных подходах с осторожностью оставляйте команду в истории команд bash (~/.bash_history).Вы можете избежать этого, либо запустив команду из скрипта (файла), либо каждый раз запрашивая пароль в интерактивном режиме:

    read mySecret
    myCommand  # approach 2
    printenv mySecret | myCommand  # approach 3
    myCommand <( printenv mySecret )  # approach 4
7 голосов
/ 30 сентября 2010

Единственный способ скрыть ваш секретный аргумент от ps - не предоставлять секрет в качестве аргумента.Один из способов сделать это - поместить секрет в файл и перенаправить дескриптор файла 3 для чтения файла, а затем удалить файл:

echo secret > x.$$
command 3<x.$$
rm -f x.$$

Не совсем ясно, что этобезопасный способ сохранить секрет;команда echo является встроенной оболочкой, поэтому она не должна появляться в выводе 'ps' (и любое появление будет мимолетным).Когда-то давным-давно echo не был встроенным - действительно, в MacOS X все еще есть /bin/echo, даже если он встроен во все оболочки.

ИзКонечно, это предполагает, что у вас есть источник command и вы можете изменить его так, чтобы он считывал секрет из предварительно открытого дескриптора файла, а не из аргумента командной строки.Если вы не можете изменить команду, вы полностью застряли - список 'ps' покажет информацию.

Еще один трюк, который вы можете использовать, если являетесь владельцем команды: вы можете захватить аргумент), запишите его в канал или файл (который сразу не связан) для себя, а затем повторно выполните команду без секретного аргумента;второй вызов знает, что, поскольку секрет отсутствует, он должен выглядеть там, где первый вызов скрывал секрет.Второй вызов (минус секрет) - это то, что появляется в выводе «ps» после небольшого интервала, необходимого для сокрытия секрета.Не так хорошо, как установка секретного канала с самого начала.Но это указывает на длину, к которой вам нужно идти.

Защелка аргумента изнутри программы - например, перезапись нулями - не скрывает аргумент от «ps».

4 голосов
/ 25 июня 2014

Я видел это в другом посте. Это самый простой способ в Linux.

Это изменяет часть памяти командной строки, которую видят все другие программы.

strncpy(argv[1], "randomtrash", strlen(argv[1]));

Вы также можете изменить имя процесса, но только при чтении из командной строки. Программы типа top покажут реальное имя процесса:

strncpy(argv[0], "New process name", strlen(argv[0]));

Не забудьте скопировать максимум strlen(argv[0]) байт, потому что, вероятно, больше не выделено места.

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

VasyaNovikov примечание: Пароль может быть перехвачен даже после вызова программы, но до того, как она начала выполнять описанные вами изменения.

4 голосов
/ 30 сентября 2010

Библиотека expect была создана частично для подобных вещей, поэтому вы все равно можете предоставить процессу пароль / другую конфиденциальную информацию, не передавая ее в качестве аргумента. Предполагая, что когда «секрет» не задан, программа, конечно, запрашивает его.

1 голос
/ 20 мая 2018

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

1 голос
/ 30 сентября 2010

Легкого пути нет.Посмотрите на этот вопрос, который я задал недавно:

Скрыть аргументы от ps

Является ли command вашей собственной программой?Вы можете попробовать зашифровать секрет и сделать расшифровку command перед использованием.

0 голосов
/ 28 января 2019

Вот один способ скрыть секрет в переменной окружения от ps:

#!/bin/bash
read -s -p "Enter your secret: " secret

umask 077 # nobody but the user can read the file x.$$ 
echo "export ES_PASSWORD=$secret" > x.$$
. x.$$ && your_awesome_command
rm -f x.$$ # Use shred, wipe or srm to securely delete the file


В выводе ps вы увидите что-то вроде этого:

$ps -ef | grep your_awesome_command
root     23134     1  0 20:55 pts/1    00:00:00  . x.$$ && your_awesome_command

Elastalert и Logstash являются примерами служб, которые могут получить доступ к паролям через переменные среды.

0 голосов
/ 20 декабря 2017

может быть, вы можете сделать так:

#include <boost/algorithm/string/predicate.hpp>
void hide(int argc, char** argv, std::string const & arg){
    for(char** current = argv; current != argv+ argc ;++current){
        if(boost::algorithm::starts_with(*current, "--"+arg)){
            bzero(*current, strlen(*current));
        }
    }
}
int main(int argc, char** argv){
   hide(argc,  argv, "password");
}
0 голосов
/ 30 сентября 2010

Если сценарий предназначен для запуска вручную, лучше всего прочитать его из STDIN

#!/bin/bash
read -s -p "Enter your secret: " secret

command "$secret"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...