Perl do с относительным путем, начинающимся с . или ..

Я пытаюсь использовать функцию Perl do EXPR в качестве анализатора конфигурации бедняка, используя второй файл .pl, который просто возвращает список в качестве информации о конфигурации. (Я думаю, что это, вероятно, идеальное использование для do, не в последнюю очередь потому, что я могу написать do or die в своем коде.) Вот пример:

main.pl

# Go read the config file
my %config = do './config.pl';

# do something with it
$web_object->login($config{username}, $config{password});

config.pl

# Configuration file for main script
(
  username => "username",
  password => "none_of_your_business",
  favorite_color => "0x0000FF",
);

Чтение Perldoc для do дает много полезных советов об относительных путях - поиск @INC и изменение %INC, специальные предупреждения о том, что 5.26 не выполняет поиск . больше и т. д. Но у него также есть эти биты:

# загрузить точно указанный файл (./ и ../ в специальном регистре)...


Использование do с относительным путем (кроме ./ и ../), например...

И затем он никогда не удосуживается объяснить обработку пути в особом случае для ./ или ../ - важное упущение!

Итак, мой вопрос (вопросы) — это все варианты того, что на самом деле происходит, когда вы do './file.pl';? Например...

  • Этот синтаксис все еще работает в 5.26, хотя CWD удален из @INC?
  • С чьей точки зрения это ./ в любом случае: двоичный файл Perl, исполняемый сценарий Perl, CWD из оболочки пользователя или что-то еще?
  • Существуют ли риски безопасности, о которых следует знать?
  • Это лучше или хуже, чем изменение @INC и просто использование базового имени файла?

Любое понимание ценится.


person Greg Kennedy    schedule 12.04.2018    source источник
comment
Re Кроме того, он никогда не удосужился объяснить обработку пути в особом случае для ./ или ../ — важное упущение!, да, do './stat.pl' во многом похоже на eval `cat stat.pl`;   -  person ikegami    schedule 12.04.2018
comment
Что касается с точки зрения ./ в любом случае, Perl просто передает путь к ОС, на которую . ссылается CWD.   -  person ikegami    schedule 12.04.2018
comment
Re Существуют ли риски безопасности, о которых нужно знать? Забудьте о рисках безопасности, как насчет того, чтобы заставить его работать вообще. Не делайте предположений о CWD. Решения. (И да, это угроза безопасности для сценариев setuid.)   -  person ikegami    schedule 12.04.2018
comment
Ответы на вопросы, я хотел бы добавить - почему вы хотите это сделать? Просто используйте полный путь правильно, как, например, в ссылке от ikegami.   -  person zdim    schedule 12.04.2018


Ответы (1)


Итак, для начала, я не уверен, что ваш config.pl действительно правильный подход - это не perl для начала, потому что он не компилируется. В любом случае, попытка оценить материал для «анализа конфигурации» в целом не является хорошим планом — он довольно подвержен неприятным сбоям и недостаткам безопасности, поэтому его следует зарезервировать на тот случай, когда это необходимо.

Я бы призвал вас сделать это по-другому:

Запишите его как модуль

Что-то вроде этого:

package MyConfig;

# Configuration file for main script
our %config = (
   username       => "username",
   password       => "none_of_your_business",
   favorite_color => "0x0000FF",
);

Затем вы можете в своем основном скрипте:

use MyConfig; #note - the file needs to be the same name, and in @INC

и получить к нему доступ как:

print $MyConfig::config{username},"\n"; 

Если вы не можете поместить его в существующий @INC — по каким-то причинам вы не можете этого сделать, FindBin позволяет вам использовать пути относительно местоположения вашего скрипта:

use FindBin; 
use lib "$FindBin::Bin"; 
use MyConfig;

Напишите свою «конфигурацию» в виде определенного парсируемого формата, а не исполняемого кода.

YAML

YAML очень хорошо подходит для файла конфигурации, в частности:

use YAML::XS;

open ( my $config_file, '<', 'config.yml' ) or die $!; 
my $config = Load ( do { local $/; <$config_file> });

print $config -> {username};

И ваш файл конфигурации выглядит так:

username: "username"
password: "password_here"
favourite_color: "green"
air_speed_of_unladen_swallow: "african_or_european?"

(YAML также поддерживает многомерные структуры данных, массивы и т. д. Однако вам это не нужно.)

JSON

JSON выглядит почти так же, только ввод:

{
  "username": "username",
  "password": "password_here",
  "favourite_color": "green",
  "air_speed_of_unladen_swallow": "african_or_european?"
}

Вы читаете его с:

use JSON;
open ( my $config_file, '<', 'config.json' ) or die $!; 
my $config = from_json ( do { local $/; <$config_file> });

Использование относительных путей к конфигу:

Вам вообще не нужно беспокоиться о @INC. Вы можете просто использовать на основе относительного пути... но лучше НЕ делать этого, а вместо этого использовать FindBin, что позволяет указать «относительно моего пути к сценарию», и это намного надежнее.

 use FindBin;
 open ( my $config_file, '<', "$FindBin::Bin/config.yml" ) or die $!; 

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

конкретные вопросы:

С чьей точки зрения это "./": бинарный файл Perl, исполняемый сценарий Perl, CWD из оболочки пользователя или что-то еще?

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

Существуют ли риски безопасности, о которых следует знать?

Каждый раз, когда вы «оцениваете» что-то, как если бы это был исполняемый код (и EXPR может быть таковым), существует риск безопасности. Это, вероятно, не так много, потому что скрипт будет работать от имени пользователя, а пользователь — это человек, который может вмешиваться в CWD. К основным рискам относятся:

  • user is in a 'different' directory where someone else has put a malicious thing for them to run. (e.g. imagine of 'config.pl' had rm -rf /* in it for example). Maybe there's a 'config.pl' in /tmp that they 'run' accidentally?
    • The thing you're evaling has a typo, and breaks the script in funky and unexpected ways. (E.g. maybe it redefines $[ and messes with program logic henceforth in ways that are hard to debug)
  • script делает что-либо в привилегированном контексте. Это не так, но посмотрите предыдущий пункт и представьте, если вы root или другой привилегированный пользователь.

Это лучше или хуже, чем изменение @INC и просто использование базового имени файла?

Имхо хуже. На самом деле просто не изменяйте @INC вообще и используйте полный путь или относительный, используя FindBin. И не делай eval вещей, когда в этом нет необходимости.

person Sobrique    schedule 12.04.2018
comment
связанные: stackoverflow.com/questions/5969417/ - person daxim; 16.04.2018
comment
Забавно, что do для разбора конфигурационного файла сейчас, по-видимому, не одобряют... потому что я взял эту идею именно из официальной документации Perl! perldoc.perl.org/functions/do.html (прокрутите вниз) - person Greg Kennedy; 01.05.2018
comment
Это пример того, как вы можете его использовать, не говоря уже о том, что вы должны это делать. И do, и eval имеют место - они делают позволяют запускать почти произвольный/указанный пользователем код. Делая это, вы вводите опасность в свой код - иногда это стоит риска, но для чего-то простого, например, "загрузить файл конфигурации"... просто не стоит "беспорядочно взрываться" во время выполнения, когда проще и безопаснее подход имеется. - person Sobrique; 01.05.2018