Каков наилучший способ избежать строк Python в PHP? - PullRequest
2 голосов
/ 13 октября 2008

У меня есть PHP-приложение, которое должно выводить скрипт на Python, более конкретно, набор операторов присваивания переменных, например.

subject_prefix = 'This String From User Input'
msg_footer = """This one too."""

Содержимое subject_prefix и др. Должно быть написано для ввода данных пользователем; поэтому мне нужно экранировать содержимое строк. Написание чего-то вроде следующего не приведет к сокращению; мы напичканы, как только кто-то использует цитату или новую строку или что-то еще, о чем я не знаю, это может быть опасно:

echo "subject_prefix = '".$subject_prefix."'\n";

Так. Есть идеи?

(Перезапись приложения в Python невозможна из-за временных ограничений.: P)

Редактировать, годы спустя:

Это было для интеграции между веб-приложением (написанным на PHP) и Mailman (написанным на Python). Я не мог изменить установку последнего, поэтому мне нужно было найти способ говорить на его языке, чтобы управлять его конфигурацией.

Это была также действительно плохая идея.

Ответы [ 5 ]

2 голосов
/ 14 октября 2008

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

Во-первых, подумайте, какую проблему вы на самом деле решаете. Я полагаю, вы просто пытаетесь получить данные из PHP в Python. Вы можете попытаться написать файл .ini, а не файл .py. Python имеет отличный синтаксический анализатор ini, ConfigParser . Вы можете написать очевидную и потенциально неверную функцию цитирования в PHP, и ничего серьезного не произойдет, если (читай: когда) вы ошибетесь.

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

Если я действительно не смогу убедить вас в том, что это ужасная, ужасная идея, то вы можете по крайней мере использовать уже существующую функцию, которая есть в Python для такой вещь: repr().

Вот удобная функция PHP, которая запустит скрипт Python, чтобы сделать это для вас:

<?php

function py_escape($input) {
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w")
        );
    $process = proc_open(
        "python -c 'import sys; sys.stdout.write(repr(sys.stdin.read()))'",
        $descriptorspec, $pipes);
    fwrite($pipes[0], $input);
    fclose($pipes[0]);
    $chunk_size = 8192;
    $escaped = fread($pipes[1], $chunk_size);
    if (strlen($escaped) == $chunk_size) {
        // This is important for security.
        die("That string's too big.\n");
    }
    proc_close($process);
    return $escaped;
}

// Example usage:
$x = "string \rfull \nof\t crappy stuff";
print py_escape($x);

Проверка chunk_size предназначена для предотвращения атаки, в результате которой ваши входные данные заканчиваются двумя действительно длинными строками, которые выглядят как ("hello " + ("." * chunk_size)) и '; os.system("do bad stuff") соответственно. Теперь эта наивная атака не будет работать точно, потому что Python не допустит, чтобы строка в одинарных кавычках заканчивалась в середине строки, и эти кавычки в вызове system() сами будут заключены в кавычки, но если злоумышленнику удастся получить продолжение строки ("\") в нужном месте и использовать что-то вроде os.system(map(chr, ...)), тогда они могут внедрить некоторый код, который будет выполняться.

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

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

0 голосов
/ 28 ноября 2009

Мне нужно было закодировать это, чтобы экранировать строку в формате "ntriples", которая использует python, экранирующий .

Следующая функция берет строку utf-8 и возвращает ее экранированную для python (или в формате ntriples). Он может делать странные вещи, если ему даны неверные данные utf-8. Он не понимает символов Юникода после xFFFF. Он (в настоящее время) не заключает строку в двойные кавычки.

Функция uniord взята из комментария на php.net.

function python_string_escape( $string ) {
    $string = preg_replace( "/\\\\/", "\\\\", $string ); # \\ (first to avoid string re-escaping)
    $string = preg_replace( "/\n/", "\\n", $string ); # \n
    $string = preg_replace( "/\r/", "\\r", $string ); # \r 
    $string = preg_replace( "/\t/", "\\t", $string ); # \t 
    $string = preg_replace( "/\"/", "\\\"", $string ); # \"
    $string = preg_replace( "/([\x{00}-\x{1F}]|[\x{7F}-\x{FFFF}])/ue",
                            "sprintf(\"\\u%04X\",uniord(\"$1\"))",
                            $string );
    return $string;
}

function uniord($c) {
    $h = ord($c{0});
    if ($h <= 0x7F) {
        return $h;
    } else if ($h < 0xC2) {
        return false;
    } else if ($h <= 0xDF) {
        return ($h & 0x1F) << 6 | (ord($c{1}) & 0x3F);
    } else if ($h <= 0xEF) {
        return ($h & 0x0F) << 12 | (ord($c{1}) & 0x3F) << 6 | (ord($c{2}) & 0x3F);
    } else if ($h <= 0xF4) {
        return ($h & 0x0F) << 18 | (ord($c{1}) & 0x3F) << 12 | (ord($c{2}) & 0x3F) << 6 | (ord($c{3}) & 0x3F);
    } else {
        return false;
    }
}
0 голосов
/ 13 октября 2008

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

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

0 голосов
/ 13 октября 2008

Другим вариантом может быть экспорт данных в виде массива или объекта в виде строки JSON и незначительное изменение кода Python для обработки нового ввода. Хотя выход через JSON не является на 100% пуленепробиваемым, он все равно будет лучше, чем собственный выход из подпрограмм.

И вы сможете обрабатывать ошибки, если строка JSON неверно отформатирована.

Для Python существует пакет для кодирования и декодирования JSON: python-json 3.4

0 голосов
/ 13 октября 2008

Я предлагаю написать функцию, которая будет принимать два аргумента: экранируемый текст и тип кавычек, в котором находится строка. Затем, например, если тип кавычек - одинарные кавычки, функция экранирует одинарные кавычки. в строке и любых других символах, которые необходимо экранировать (обратный слеш?).

function escape_string($text, $type) {
    // Escape backslashes for all types of strings?
    $text = str_replace('\\', '\\\\', $text);

    switch($type) {
        case 'single':
            $text = str_replace("'", "\\'", $text);
            break;
        case 'double':
            $text = str_replace('"', '\\"', $text);
            break;
        // etc...
    }

    return $text;
}

Я предполагаю, что для строк в одинарных кавычках вы хотите экранировать одинарные кавычки, а в случае строк в двойных кавычках вы хотите экранировать двойные кавычки ...

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