簡體   English   中英

在PHP中轉義Python字符串的最佳方法是什么?

[英]What is the best way to escape Python strings in PHP?

我有一個PHP應用程序,需要輸出python腳本,更具體地說是一堆變量賦值語句,例如。

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

需要編寫subject_prefix等的內容以接受用戶輸入。 因此,我需要轉義字符串的內容。 編寫類似下面的內容不會減少它。 只要有人使用引號或換行符或其他我不知道的其他內容,我們就會被塞滿,這很危險:

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

所以。 有任何想法嗎?

(由於時間限制,無法使用Python重寫應用程序。:P)

幾年后編輯:

這是用於Web應用程序(用PHP編寫)和Mailman(用Python編寫)之間的集成。 我無法修改后者的安裝,因此我需要想出一種以其語言進行交談的方法來管理其配置。

這也是一個非常糟糕的主意。

不要嘗試用PHP編寫此函數。 您將不可避免地出錯,並且您的應用程序將不可避免地具有任意遠程執行漏洞。

首先,考慮一下您實際要解決的問題。 我想您只是想從PHP到Python獲取數據。 您可能會嘗試編寫.ini文件而不是.py文件。 Python具有出色的ini語法解析器ConfigParser 您可以在PHP中編寫明顯但可能不正確的引號函數,如果(讀:何時)弄錯了,則不會發生任何嚴重的情況。

您也可以編寫一個XML文件。 對於我來說,PHP和Python的XML解析器和發射器太多了,我什至不在這里列出。

如果我真的不能說服您這是一個可怕的想法,那么您至少可以使用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") '; os.system("do bad stuff") 現在,這種天真的攻擊不會完全起作用,因為Python不會讓單引號的字符串在行的中間結束,並且system()調用中的引號本身也會被引號,但是如果攻擊者設法將換行符(\\)插入正確的位置並使用os.system(map(chr, ...))類的東西os.system(map(chr, ...))然后他們就可以注入一些將要運行的代碼。

我選擇只讀取一個塊,如果有更多輸出,就放棄,而不是繼續讀取和累積,因為Python源文件的行長也有限制。 就我所知,這可能是另一個攻擊媒介。 Python並非旨在防止任意人在您的系統上編寫任意源代碼,因此該領域不太可能被審計。

在這個簡單的示例中,我不得不考慮所有這些事實,這只是為什么您不應該將python源代碼用作數據交換格式的另一個示例。

我需要對此進行編碼,以使用“ python escaping”轉義 “ ntriples”格式的字符串。

以下函數采用utf-8字符串,並將其返回以python(或ntriples格式)轉義。 如果提供非法的utf-8數據,它可能會做些奇怪的事情。 它不了解xFFFF之后的Unicode字符。 它不會(當前)將字符串用雙引號引起來。

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;
    }
}

我將從標准化我在python中使用的字符串類型開始,以使用三引號引起來的字符串(“”“)。這應減少輸入中流浪引號引起的問題。您仍然需要對其進行轉義當然,但是它應該減少所關注的問題的數量。

我為逃避字符串所做的操作在某種程度上取決於我擔心滑入的內容以及它們再次被打印出的上下文。 如果您只是擔心引號引起問題,則可以簡單地檢查和出現“”,然后將它們轉義。另一方面,如果我擔心輸入本身是惡意的(並且是用戶輸入,那么您應該),那么我將看一下strip_tags()或其他類似功能的選項。

另一個選擇可能是將數據作為數組或對象導出為JSON字符串,並稍微修改python代碼以處理新輸入。 盡管通過JSON進行轉義並不是100%防彈,但它仍然比自己的轉義例程更好。

如果JSON字符串格式錯誤,您將能夠處理錯誤。

有一個用於Python編碼和解碼JSON的軟件包: python-json 3.4

我建議編寫一個帶有兩個參數的函數:要轉義的文本和字符串所在的引號類型。然后,例如,如果引號類型為單引號,則該函數將轉義字符串中的單引號以及任何其他需要轉義的字符(反斜杠?)。

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;
}

我假設對於單引號字符串,您要轉義單引號,對於雙引號字符串,您要轉義雙引號...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM