Python3 — Очистка пользовательского ввода для использования в оболочке

#python-3.x #bash #shell #input #sanitization

Вопрос:

Я занят написанием скрипта Python3, который требует ввода данных пользователем, ввод используется в качестве параметров в командах, передаваемых в оболочку.

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

Пример 1:

 import subprocess  user_input = '/tmp/file.txt' subprocess.Popen(['cat', user_input])  

Это выведет содержимое ‘/tmp/file.txt’

Пример 2:

 import subprocess  user_input = '/tmp/file.txt amp;amp; rm -rf /' subprocess.Popen(['cat', user_input])  

Результаты (как и ожидалось):

 cat: /tmp/file.txt amp;amp; rm -rf /: No such file or directory  

Является ли это приемлемым методом очистки входных данных? Есть ли что-нибудь еще, согласно лучшей практике, что я должен делать в дополнение к этому?

Комментарии:

1. Нет, не из досье. Ввод осуществляется через интерактивное меню в терминале. Я просто упростил свой вопрос. Переменная «user_input» просто представляет все, что пользователь предположительно ввел в приложение.

Ответ №1:

Подход, который вы выбрали,

 import subprocess user_input = 'string' subprocess.Popen(['command', user_input])  

довольно хорош, так как command статичен и user_input передается как один единственный аргумент command . До тех пор, пока ты не сделаешь что-нибудь действительно глупое, например

 subprocess.Popen(['bash', '-c', user_input])  

ты должен быть в безопасности.


Для команд, требующих нескольких аргументов, я бы рекомендовал вам запросить несколько входных данных у пользователя, например, сделайте это

 user_input1='file1.txt' user_input2='file2.txt' subprocess.Popen(['cp', user_input1, user_input2])  

вместо этого

 user_input="file1.txt file2.txt" subprocess.Popen(['cp']   user_input.split())  

Если вы хотите еще больше повысить безопасность, вы можете:

  • явно задано shell=False (чтобы вы никогда не выполняли команды оболочки; это уже текущее значение по умолчанию, но значения по умолчанию могут меняться со временем):
     subprocess.Popen(['command', user_input], shell=False)  
  • используйте абсолютные пути для command (для предотвращения внедрения вредоносных исполняемых файлов через PATH ):
     subprocess.Popen(['/usr/bin/command', user_input])  
  • явно проинструктируйте команды, которые его поддерживают, чтобы остановить параметры синтаксического анализа, например
     subprocess.Popen(['rm', '--', user_input1, user_input2])  
  • сделайте как можно больше изначально, например cat /tmp/file.txt , вместо этого можно было бы использовать несколько строк кода Python (что также повысило бы переносимость, если бы это было фактором).