2010-04-04 32 views
11

我試圖保護自己免受SQL注入和正在使用:解碼mysql_real_escape_string(),用於輸出HTML

mysql_real_escape_string($string); 

在發佈HTML,它看起來是這樣的:

<span class="\&quot;className\&quot;"> 
<p class="\&quot;pClass\&quot;" id="\&quot;pId\&quot;"></p> 
</span> 

我不知道real_escape_string增加了多少其他變體,所以不想只替換一些而錯過其他變體......我如何將它解碼爲正確格式化的HTML,如下所示:

html_entity_decode(stripslashes($string)); 
+0

如果用戶可以控制$ string,那麼這是一個XSS漏洞。 – rook 2010-04-16 18:17:18

回答

12

mysql_real_escape_string()手冊會告訴你哪些字符轉義:

mysql_real_escape_string()調用 MySQL的庫函數 mysql_real_escape_string,其中 預規劃反斜槓以下 字符:\ X00,\ n,\ r, \,',「和 \ x1a。

您可以通過將這些轉義字符替換爲非轉義形式來成功反轉轉義。

mysql_real_escape_string()不應該用來淨化HTML,儘管...在輸出網頁數據之前沒有理由使用它。它只應用於您將要放入數據庫的數據。您的消毒過程應該是這個樣子:

輸入

  1. 接受來自表單或HTTP請求
  2. 用戶輸入創建使用數據庫查詢mysql_real_escape_string()

輸出

  1. 打印

使用不同的數據庫驅動程序,如MySQLiPDO將允許你使用準備好的語句,它採取逃避的護理之前獲取數據從數據庫

  • 貫穿htmlspecialchars()任何用戶定義的數據爲您提供最多的投入。但是,如果你不能切換或利用這些,那麼肯定使用mysql_real_escape_string() ......只是在插入數據之前使用它。

  • +0

    我會通過'mysql_real_escape_string'建議準備好的語句(例如http://www.php.net/manual/en/class.pdostatement.php)。而'htmlspecialchars'並不總是正確的選擇。有時白名單是一個更好的選擇。 – 2010-04-04 02:31:04

    +0

    注意!如果您有'magic_quotes',即使使用PDO,您也需要在將字符串放入數據庫之前使用'stripslashes()'以避免雙斜槓。 – mrserge 2015-08-14 18:26:48

    +0

    但是沒有現代系統應該有magic_quotes。該功能已被棄用多年。 – 2016-08-04 14:17:35

    7

    你搞砸了一切。

    mysql_real_escape_string不需要任何解碼。

    如果你用斜槓得到你的數據,這意味着它已經被兩次逃脫。而不是剝去額外的斜槓,你應該不加它們。

    更何況,無論逃逸過時,並且你應該

    使用預處理語句

    ,而不是任何逃生繩。

    所以,永遠不要逃避,永遠不要解碼。
    問題解決了。

    +0

    $ query =「INSERT INTO table SET html ='$ html'」;不是標準的SQL,你最好使用INSERT INTO table(html)VALUES('content');這適用於所有數據庫,而不僅僅是MySQL。 – 2010-04-04 10:33:25

    +0

    @Frank Heikens但我正在使用MySQL。我使用了大量的mysql特定功能。請告訴我不要使用PHP,因爲它在任何地方都不支持。多麼無稽之談! – 2010-04-04 14:37:24

    7

    mysql_real_escape_string用於在將用戶提供的數據存儲到數據庫時防止SQL注入,但更好的方法是使用PDO(例如)使用數據綁定。我總是推薦使用它來代替亂七八糟的東西。

    這就是說,關於如何顯示它的問題 - 數據存儲之後,當您檢索數據時,數據是完整且有效的,無需「未轉義」。除非你添加了你自己的轉義序列,所以請不要這樣做。

    -2

    我想了一些其他的答案錯過了明顯的問題...

    您正在使用的輸入的內容mysql_real_escape_string(你應該在不使用預處理語句)。

    你的問題是與輸出。

    目前的問題是您正在調用html_entity_decode。只需用stripslashes即可恢復原始文本。 html_entity_decode是什麼搞亂你的報價等,因爲它正在改變它們。你實際上想要輸出html,而不僅僅是純文本(當你使用html_entities等)。你正在解碼你想要編碼的東西。

    如果您只想顯示文本版本,則可以使用實體。如果您擔心錯誤標籤,請使用striptags並僅允許使用您想要的標籤(例如b,i等)。

    最後,請記住按照正確的順序進行編碼和解碼。如果你運行mysql_real_escape_String(htmlentities($ str)),那麼你需要運行html_entity_decode(stripslashes($ str))。操作順序很重要。

    更新:我沒有意識到,html_entity_decode也會去掉斜槓。該頁面沒有清楚記錄,我從來沒有發現過。儘管我仍然會自動運行它,因爲我提供的大多數html都是作爲實體保留的,甚至當我不這樣做時,我更願意根據具體情況在db類之外做出該決定。那樣,我知道斜線已經消失了。

    看起來原來的海報正在運行htmlentities(或者他的輸入程序,就像tinymce正在爲他做的那樣),並且他想要把它變回內容。所以,html_entity_decode($ Str)應該是所有必需的。

    +1

    你錯了。他不需要去掉斜線。 Ne需要正確添加它。做治癒,不是症狀。 – 2010-04-04 03:15:34

    +0

    他需要去掉斜線,因爲他第一次跑脫線。他編碼它,現在他需要解碼它以擺脫輸出中的斜槓。因此出現在"之前。 – Cryophallion 2010-04-04 03:17:21

    +1

    你不知道事情是如何工作的。所以最好禁止回答,直到你學到一些東西。不需要剝離。親自嘗試一下。 – 2010-04-04 03:20:29

    0

    不知道是怎麼回事與格式化,因爲我可以看到它,但你的HTML表單

    <span class="\&quot;className\&quot;"> 
    <p class="\&quot;pClass\&quot;" id="\&quot;pId\&quot;"></p> 
    </span> 
    

    應該是簡單的;

    <span class="className"> 
    <p class="pClass" id="pId"></p> 
    </span> 
    

    當你把它找回來,你把它放進你逃避它使用mysql_real_escape_string(),以使數據庫之前,請確保您不會受到SQL注入攻擊。

    因此,您正在逃避準備放置文本下一步的值。

    當你把它從數據庫中拿出來(或者把它作爲html顯示給用戶的任何東西),那麼你可以再次使用htmlentities()等等來保護你的用戶XSS攻擊。

    這形成了咒語FIEO的EO部分,Filter Input,Escape Output,您應該在眼瞼內側紋身。

    +0

    你確定他希望這個表格能夠逃脫嗎?我深表懷疑。如果有人使用HTML格式,他們通常希望它工作,而不是可見標籤。 – 2010-04-04 14:39:55

    -1

    我想知道爲什麼這個例程沒有附帶的解碼器例程。它可能被MySQL解釋爲完全相同的方式,就好像它沒有被轉義一樣。當你做一個$row=mysql_fetch_array($res, MYSQL_ASSOC)';

    0

    那麼,我用這種舊時尚的方式刺了一刀,到目前爲止我無法看到我的方法有什麼問題。顯然這有點粗糙,但它完成了工作:

    function mysql_unreal_escape_string($string) { 
        $characters = array('x00', 'n', 'r', '\\', '\'', '"','x1a'); 
        $o_chars = array("\x00", "\n", "\r", "\\", "'", "\"", "\x1a"); 
        for ($i = 0; $i < strlen($string); $i++) { 
         if (substr($string, $i, 1) == '\\') { 
          foreach ($characters as $index => $char) { 
           if ($i <= strlen($string) - strlen($char) && substr($string, $i + 1, strlen($char)) == $char) { 
            $string = substr_replace($string, $o_chars[$index], $i, strlen($char) + 1); 
            break; 
           } 
          } 
         } 
        } 
        return $string; 
    } 
    

    這應該涵蓋大多數情況。

    -1

    即使這是一個老問題... 我已經有了比彼得克雷格相同的問題。其實我必須處理一箇舊的CMS。爲了防止SQL注入,所有$ _POST和$ _GET值都是「sql-escaped」。不幸的是,這是在一箇中心點完成的,所以你所有的模塊正在接收所有數據sql-escaped!在某些情況下,您希望直接顯示這些數據,以免遇到問題:如何在不從數據庫中獲取它的情況下顯示sql轉義的字符串? 答案是: 使用stripcslashes(NOT的stripslashes !!)

    http://php.net/manual/en/function.stripcslashes.php

    -1

    使用下面的函數,以除去斜線而表示HTML頁上:

    stripslashes()函數;

    例如。 $ html = stripslashes($ html); 或 $ html = stripslashes($ row [「fieldname」]);