Perl регулярное выражение в качестве пользовательского ввода ввода (очистка) - PullRequest
1 голос
/ 01 мая 2019

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

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

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

Пример: * * один тысяча двадцать-одна # Allow short range of special chars to be left unescaped # to let regex work, while at the same time prevent possible # command injection or premature regex termination my $mask = $in{'mask'}; sub quotemeta_dangerous { my ($string) = @_; $string = quotemeta($string); $string =~ s/\\\\/\\/g; $string =~ s/\\\+/+/g; $string =~ s/\\\*/*/g; $string =~ s/\\\$/\$/g; $string =~ s/\\\^/\^/g; $string =~ s/\\\(/\(/g; $string =~ s/\\\)/\)/g; $string =~ s/\\\{/\{/g; $string =~ s/\\\}/\}/g; $string =~ s/\\\[/\[/g; $string =~ s/\\\]/\]/g; $string =~ s/\\\?/?/g; $string =~ s/\\\././g; $string =~ s/\\\-/-/g; return $string; } my $sanitized_mask = quotemeta_dangerous($mask); if ($filename =~ /$sanitized_mask/) { # matched } Вопросы:

  1. Поможет ли мое решение, приведенное выше, безопасно достичь моих целей, учитывая упомянутые, важные примечания. Каковы потенциальные риски, которые я не вижу здесь?

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

Пример:

$file_contents =~ s/\Q$text_to_find\E/$text_to_replace_with/g;

Можно ли избежать $text_to_replace_with здесь как угрозу безопасности, когда передается от пользователя как есть?

1 Ответ

3 голосов
/ 01 мая 2019
  1. Я не уверен, что вы подразумеваете под прекращено .Что касается запуска произвольного Perl-кода, вы не можете сделать это из пользовательского ввода (если только программа не разрешит это явно с помощью, например, eval() или use re 'eval').Если бы вы могли просто внедрить код Perl из пользовательского ввода, ваша функция не защитила бы его: он пропускает, например, (?{system+qq(rm -rf ~)}) в работоспособной форме (работоспособной, то есть если бы она была частью кода, а не входными данными).

    Что вы можете сделать с регулярным выражением пользовательского ввода, так это создать DoS: заставить его потреблять много ресурсов ЦП и зависать.Ваша функция не защищает от этого.Например, попробуйте:

    'aaaaaaaaaa' =~ /(((\1?[a-z]*)*)*)*[b-z]/
    

    Или с еще более длинной цепочкой.(Возможно, есть способы сократить этот код; я просто собирал случайные биты, чтобы посмотреть, быстро ли они закончили сопоставление.)

    Если вы хотите защититься от этого, взгляните на RE2 :

    RE2 был разработан и реализован с явной целью - иметь возможность обрабатывать регулярные выражения от ненадежных пользователей без риска.

    Вы можете использовать его вВаш код , выполнив

    {
        use re::engine::RE2 -strict => 1;
        # now regexes compiled in this scope will use the RE2 engine
        ...
    }
    
  2. Это легко ответить.Здесь нет опасности;$text_to_replace_with просто рассматривается как строка.

    (Если вы хотите создать опасность, вам нужно либо

    • /e и eval(), либо
    • /ee, что одно и то же.

    Технически вам не нужно /e, но это все равно оставляет очень заметный eval() в вашем коде. Опять же, вы не можетеатакуйте его как пользователя; вы должны закодировать его.)

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