Довольно способ хранения конфиденциальной информации из зарегистрированной командной строки в Ruby?

У меня есть длинная команда, которую я строю с лопатами (<<), с намерением в конечном итоге запустить system(command). Я хотел бы зарегистрировать командную строку, чтобы убедиться, что она построена правильно, перед выполнением команды. Однако команда должна содержать учетные данные, которые я не хочу регистрировать. Я ищу элегантный способ удовлетворить оба требования (1. запишите мясо командной строки, 2. не регистрируйте его учетные данные, которые он содержит).

Это то, что у меня есть сейчас:

command = ""
public = ""

[command, public].each {|str| str << "command_name"}
[command, public].each {|str| str << " -a a"}
[command, public].each {|str| str << " -b b"}
[command, public].each {|str| str << " -c c"}
command << " -d d"
command << " -e e"
[command, public].each {|str| str << " -f f"}
command << " -g g"
[command, public].each {|str| str << " -h h"}
[command, public].each {|str| str << " -i i"}

puts command
=> command_name -a a -b b -c c -d d -e e -f f -g g -h h -i i
puts public
=> command_name -a a -b b -c c -f f -h h -i i

system(command)

Оригинальный вопрос из переполнения стека

11 голосов | спросил CHK 23 PMpWed, 23 Apr 2014 18:40:16 +040040Wednesday 2014, 18:40:16

3 ответа


17

Я вижу еще две проблемы безопасности с этим кодом.

  1. Выполнение строки, а не массива команд и параметров

    При создании командной строки программно опасно создавать ее как строку, особенно когда любой из параметров поступает из пользовательского ввода. При вызове Kernel#system со строкой, оболочка интерпретирует командную строку; при вызове с массивом ядро ​​операционной системы выполняет команду напрямую.

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

    В качестве иллюстрации следующий код будет делать больше, чем просто установить пароль на "hello":

    password_file = '.htpasswd'
    username = 'CHK'
    password = 'hello; touch me; grep; unzip; strip; finger; fsck -y; more; yes; yes; yes; umount; sleep'
    command = "htpasswd -b -c #{password_file} #{username} #{password}"
    system(command)
    

    Практика более безопасных вычислений! Это не уязвимо для выполнения произвольной команды:

    command = ['htpasswd', '-b', '-c', password_file, username, password]
    system(*command)
    
  2. Передача конфиденциальной информации в командной строке

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

    По этой причине все разумные команды должны предлагать альтернативный механизм приема секретной информации. Например, рекомендуемый способ использования htpasswd , так как Apache 2.4 должен читать пароль со стандартного ввода.

    command = ['htpasswd', '-i', '-c', password_file, username]
    IO.popen(command, mode='w') do |htpasswd|
      htpasswd.puts(password)
    end
    

    Аналогично, вот пример того, как безопасно указать кодовую фразу для GnuPG (на Python) .

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

ответил 200_success 23 PMpWed, 23 Apr 2014 23:35:24 +040035Wednesday 2014, 23:35:24
7

Кажется, что вы многократно выполняете много операций как для «команды», так и «public». То, как связаны эти переменные, заставляет меня думать, что они должны быть частью одного и того же объекта. Например:

class Command
  attr_reader :command, :loggable

  def initialize(command)
    @command = command
    @loggable = command
  end

  def concat(option)
    @command << ' ' + option
    @loggable << ' ' + option
  end
  alias_method :<<, :concat

  def concat_private(option)
    @command << ' ' + option
  end

  alias_method :to_s, :command
  alias_method :to_str, :command
end

command = Command.new('echo')
command << '-a this'
command << '-b that'
command.concat_private '--password asdf'

system(command)

Этот подход также делает ваш код более надежным, дает вам гибкость добавления дополнительных методов в Command, если возникнет такая необходимость.

ответил Ajedi32 23 PMpWed, 23 Apr 2014 21:12:00 +040012Wednesday 2014, 21:12:00
2

Я полностью согласен со всем, что сказал @ 200_success, но если вы хотите получить конфиденциальное информационное решение, я бы предложил нечто большее в строках html_safe - специализированная строка, которая создается по умолчанию и отображается только при явной просьбе:

class PrivateString < String
  alias to_private_s to_s

  def to_s
    '*******'
  end

  def concat(other)
    if other.respond_to?(:to_private_s)
      super(other.to_private_s)
    else
      super
    end
  end

  alias << concat
end

class String
  def private
    PrivateString.new(self)
  end

  alias unsafe_concat concat

  def concat(other)
    if other.respond_to?(:to_private_s)
      unsafe_concat(other.to_s)
    else
      unsafe_concat(other)
    end
  end

  alias << concat
end

Теперь ваш код будет выглядеть так:

command = "".private
public = ""

[command, public].each {|str| str << "command_name"}
[command, public].each {|str| str << " -a a"}
[command, public].each {|str| str << " -b b"}
[command, public].each {|str| str << " -c c"}
[command, public].each {|str| str << " -d d".private}
[command, public].each {|str| str << " -e e".private}
[command, public].each {|str| str << " -f f"}
[command, public].each {|str| str << " -g g".private}
[command, public].each {|str| str << " -h h"}
[command, public].each {|str| str << " -i i"}

puts command
=> command_name -a a -b b -c c -d d -e e -f f -g g -h h -i i
puts public
=> command_name -a a -b b -c c************** -f f******* -h h -i i

system(command)

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

ответил Uri Agassi 24 AMpThu, 24 Apr 2014 11:11:45 +040011Thursday 2014, 11:11:45

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132