[英]PHP/SQL Database querying good practice and security
所以我是一個有點經驗豐富的php開發人員,自2007年以來一直在做“該死的事”。 但是,在保護我的應用程序方面,我仍然相對較差。 我不知道我知道的所有事情,我可以而且應該這樣做。
我已經選擇了保護PHP Web應用程序,並正在閱讀我的方式來測試一路上的東西。 我對與數據庫查詢有關的一般SO組有一些問題(主要是在mysql下):
創建將數據放入數據庫的應用程序時,mysql_real_escape_string和輸入數據的一般檢查(is_numeric等)是否足夠? 那些與sql注入不同的其他類型的攻擊呢?
有人可以解釋存儲過程和准備好的語句,而不是 - 你制作它們並調用它們。 我想知道它們是如何工作的,幕后的驗證是什么。
我在php4綁定環境中工作,php5暫時不是一個選項。 有沒有其他人曾經在這個位置,你做了什么來保護你的應用程序,而所有酷孩子都在使用這個甜蜜的新mysqli界面?
人們發現有哪些一般的良好做法是有利的,強調創建一個能夠承受升級和可能的遷移的基礎設施(比如將php4移到php5)。
注意:有一個搜索周圍找不到任何類似於這個打到php-mysql安全性的東西。
哈維爾的回答有一個owasp鏈接是一個好的開始。
還有一些事情你可以做更多:
關於SQL注入攻擊,您可以編寫一個函數來刪除輸入中的常見SQL語句,如“DROP”或“DELETE * WHERE”,如下所示:
* $ sqlarray = array(“DROP”,“或1 = 1”,“union select”,“SELECT * FROM”,“select host”,“create table”,“FROM users”,“users WHERE”); *
然后編寫將檢查此數組輸入的函數。 確保$ sqlarray中的任何內容都不是來自用戶的常見輸入。 (別忘了在這上面使用strtolower,謝謝lou)。
我不確定memcache是否適用於PHP 4,但是你可以使用memcache實現一些垃圾郵件保護,只允許在Y時間段內對process.php頁面X進行某些遠程IP訪問。
特權很重要。 如果您只需要插入權限(例如,訂單處理),那么您應該使用只有插入且可能具有選擇權限的用戶登錄訂單處理頁面上的數據庫。 這意味着即使SQL注入完成,它們也只能執行INSERT / SELECT查詢而不能刪除或重構。
將重要的php處理文件放在/ include等目錄中。 然后禁止所有IP訪問該/ include目錄。
在用戶的會話中使用用戶的代理+ remoteip + salt加鹽腌MD5,並在每個頁面加載時驗證正確的MD5在其cookie中。
禁止某些標題( http://www.owasp.org/index.php/Testing_for_HTTP_Methods_and_XST )。 禁止PUT(如果您不需要文件上傳)/ TRACE / CONNECT / DELETE標頭。
我的建議:
然后你可以這樣做:
$pdo_obj = new PDO( 'mysql:server=localhost; dbname=mydatabase',
$dbusername, $dbpassword );
$sql = 'SELECT column FROM table WHERE condition=:condition';
$params = array( ':condition' => 1 );
$statement = $pdo_obj->prepare( $sql,
array( PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY ) );
$statement->execute( $params );
$result = $statement->fetchAll( PDO::FETCH_ASSOC );
優點:
缺點:
我通常不使用PHP,因此我無法提供專門針對您的要求的建議,但我建議您查看OWASP頁面,特別是前10個漏洞報告: http : //www.owasp.org /index.php/Top_10_2007
在該頁面中,對於每個漏洞,您將獲得一些列表,您可以執行這些操作以避免在不同平台(.Net,Java,PHP等)中出現問題。
關於准備好的語句,它們的工作原理是讓數據庫引擎知道在特定查詢期間有多少參數和類型,使用這些信息,引擎可以理解哪些字符是實際參數的一部分,而不是應該被解析為SQL就像'(撇號)作為數據的一部分而不是'作為字符串分隔符。 抱歉,我無法提供針對PHP的更多信息,但希望這會有所幫助。
AFAIK,PHP / mySQL通常沒有參數化查詢。
使用sprintf()
和mysql_real_escape_string()
應該可以很好地工作。 如果為sprintf()
使用適當的格式字符串(例如,對於整數使用“%d”),那么你應該非常安全。
我可能錯了,但是在用戶提供的數據上使用mysql_real_escape_string
應該不夠嗎?
除非它們是數字,在這種情況下,您應該確保它們實際上是數字,而不是使用例如ctype_digit
或is_numeric
或sprintf
(使用%d
或%u
強制輸入數字)。
另外,為你的php腳本提供一個serarate mysql用戶,只能SELECT,INSERT,UPDATE和DELETE,這可能是一個好主意......
來自php.net的示例
示例#3“最佳實踐”查詢
在每個變量周圍使用mysql_real_escape_string()可以防止SQL注入。 此示例演示了查詢數據庫的“最佳實踐”方法,與Magic Quotes設置無關。
查詢現在將正確執行,SQL注入攻擊將無法正常工作。
<?php if (isset($_POST['product_name']) && isset($_POST['product_description']) && isset($_POST['user_id'])) { // Connect $link = mysql_connect('mysql_host', 'mysql_user', 'mysql_password'); if(!is_resource($link)) { echo "Failed to connect to the server\\n"; // ... log the error properly } else { // Reverse magic_quotes_gpc/magic_quotes_sybase effects on those vars if ON. if(get_magic_quotes_gpc()) { $product_name = stripslashes($_POST['product_name']); $product_description = stripslashes($_POST['product_description']); } else { $product_name = $_POST['product_name']; $product_description = $_POST['product_description']; } // Make a safe query $query = sprintf("INSERT INTO products (`name`, `description`, `user_id`) VALUES ('%s', '%s', %d)", mysql_real_escape_string($product_name, $link), mysql_real_escape_string($product_description, $link), $_POST['user_id']); mysql_query($query, $link); if (mysql_affected_rows($link) > 0) { echo "Product inserted\\n"; } } } else { echo "Fill the form properly\\n"; }
將存儲過程用於涉及寫入數據庫的任何活動,並對所有選擇使用綁定參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.