摘要:利用和產(chǎn)生原因主要就是一些數(shù)據(jù)沒有經(jīng)過嚴(yán)格的驗證,然后直接拼接去查詢。導(dǎo)致漏洞產(chǎn)生,比如因為沒有對做數(shù)據(jù)類型驗證,注入者可提交任何類型的數(shù)據(jù),比如等不安全的數(shù)據(jù)。如果按照下面方式寫,就安全一些。把轉(zhuǎn)換成類型,就可以去掉不安全的東西。
利用Mysqli和PDO
產(chǎn)生原因
主要就是一些數(shù)據(jù)沒有經(jīng)過嚴(yán)格的驗證,然后直接拼接 SQL 去查詢。導(dǎo)致漏洞產(chǎn)生,比如:
$id = $_GET["id"]; $sql = "SELECT name FROM users WHERE id = $id";
因為沒有對 $_GET["id"] 做數(shù)據(jù)類型驗證,注入者可提交任何類型的數(shù)據(jù),比如 " and 1= 1 or " 等不安全的數(shù)據(jù)。如果按照下面方式寫,就安全一些。
$id = intval($_GET["id"]); $sql = "SELECT name FROM users WHERE id = $id";
把 id 轉(zhuǎn)換成 int 類型,就可以去掉不安全的東西。
驗證數(shù)據(jù)
防止注入的第一步就是驗證數(shù)據(jù),可以根據(jù)相應(yīng)類型進(jìn)行嚴(yán)格的驗證。比如 int 類型直接同過 intval 進(jìn)行轉(zhuǎn)換就行:
$id =intval( $_GET["id"]);
字符處理起來比較復(fù)雜些,首先通過 sprintf 函數(shù)格式話輸出,確保它是一個字符串。然后通過一些安全函數(shù)去掉一些不合法的字符,比如:
$str = addslashes(sprintf("%s",$str));
//也可以用 mysqli_real_escape_string 函數(shù)替代addslashes
這樣處理以后會比較安全。當(dāng)然還可以進(jìn)一步去判斷字符串長度,去防止「緩沖區(qū)溢出攻擊」比如:
$str = addslashes(sprintf("%s",$str)); $str = substr($str,0,40); //最大長度為40
參數(shù)化綁定
參數(shù)化綁定,防止 SQL 注入的又一道屏障。php MySQLi 和 PDO 均提供這樣的功能。比如 MySQLi 可以這樣去查詢:
$mysqli = new mysqli("localhost", "my_user", "my_password", "world"); $stmt = $mysqli->prepare("INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)"); $code = "DEU"; $language = "Bavarian"; $official = "F"; $percent = 11.2; $stmt->bind_param("sssd", $code, $language, $official, $percent);
PDO 的更是方便,比如:
/* Execute a prepared statement by passing an array of values */ $sql = "SELECT name, colour, calories FROM fruit WHERE calories < :calories AND colour = :colour"; $sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); $sth->execute(array(":calories" => 150, ":colour" => "red")); $red = $sth->fetchAll(); $sth->execute(array(":calories" => 175, ":colour" => "yellow")); $yellow = $sth->fetchAll();
我們多數(shù)使用 php 的框架進(jìn)行編程,所以最好不要自己拼寫 SQL,按照框架給定參數(shù)綁定進(jìn)行查詢。遇到較為復(fù)雜的 SQL 語句,一定要自己拼寫的時候,一定要注意嚴(yán)格的判斷。沒有用 PDO 或者 MySQLi 也可以自己寫個 prepared,比如 wordprss db 查詢語句,可以看出也是經(jīng)過嚴(yán)格的類型驗證。
function prepare( $query, $args ) { if ( is_null( $query ) ) return; // This is not meant to be foolproof -- but it will catch obviously incorrect usage. if ( strpos( $query, "%" ) === false ) { _doing_it_wrong( "wpdb::prepare" , sprintf ( __( "The query argument of %s must have a placeholder." ), "wpdb::prepare()" ), "3.9" ); } $args = func_get_args(); array_shift( $args ); // If args were passed as an array (as in vsprintf), move them up if ( isset( $args[ 0] ) && is_array( $args[0]) ) $args = $args [0]; $query = str_replace( ""%s"", "%s" , $query ); // in case someone mistakenly already singlequoted it $query = str_replace( ""%s"", "%s" , $query ); // doublequote unquoting $query = preg_replace( "|(?總結(jié)
安全性很重要,也可以看出一個人基本功,項目漏洞百出,擴(kuò)展性和可維護(hù)性再好也沒有用。平時多留意,樹立安全意識,養(yǎng)成一種習(xí)慣,一些基本的安全當(dāng)然也不會占用用 coding 的時間。養(yǎng)成這個習(xí)慣,即便在項目急,時間短的情況一下,依然可以做的質(zhì)量很高。不要等到自己以后負(fù)責(zé)的東西,數(shù)據(jù)庫都被拿走了,造成損失才重視。共勉!
雖然國內(nèi)很多PHP程序員仍在依靠addslashes防止SQL注入,還是建議大家加強(qiáng)中文防止SQL注入的檢查。addslashes的問題在于黑客可以用0xbf27來代替單引號,而addslashes只是將0xbf27修改為0xbf5c27,成為一個有效的多字節(jié)字符,其中的0xbf5c仍會被看作是單引號,所以addslashes無法成功攔截。
當(dāng)然addslashes也不是毫無用處,它是用于單字節(jié)字符串的處理,多字節(jié)字符還是用mysql_real_escape_string吧。
另外對于php手冊中g(shù)et_magic_quotes_gpc的舉例:
if (!get_magic_quotes_gpc()) { $lastname = addslashes($_POST[‘lastname’]); } else { $lastname = $_POST[‘lastname’]; }最好對magic_quotes_gpc已經(jīng)開放的情況下,還是對$_POST[’lastname’]進(jìn)行檢查一下。
再說下mysql_real_escape_string和mysql_escape_string這2個函數(shù)的區(qū)別:
mysql_real_escape_string 必須在(PHP 4 >= 4.3.0, PHP 5)的情況下才能使用。否則只能用 mysql_escape_string ,兩者的區(qū)別是:mysql_real_escape_string 考慮到連接的當(dāng)前字符集,而mysql_escape_string 不考慮。
總結(jié)一下:
addslashes() 是強(qiáng)行加;
mysql_real_escape_string() 會判斷字符集,但是對PHP版本有要求;
mysql_escape_string不考慮連接的當(dāng)前字符集。
服務(wù)端配置方面
(1) 打開php的安全模式
php的安全模式是個非常重要的內(nèi)嵌的安全機(jī)制,能夠控制一些php中的函數(shù),比如system(),
同時把很多文件操作函數(shù)進(jìn)行了權(quán)限控制,也不允許對某些關(guān)鍵文件的文件,比如/etc/passwd,
但是默認(rèn)的php.ini是沒有打開安全模式的,我們把它打開:
safe_mode = on(2) 用戶組安全
當(dāng)safe_mode打開時,safe_mode_gid被關(guān)閉,那么php腳本能夠?qū)ξ募M(jìn)行訪問,而且相同
組的用戶也能夠?qū)ξ募M(jìn)行訪問。建議設(shè)置為:
safe_mode_gid = off如果不進(jìn)行設(shè)置,可能我們無法對我們服務(wù)器網(wǎng)站目錄下的文件進(jìn)行操作了,比如我們需要
對文件進(jìn)行操作的時候。(3) 安全模式下執(zhí)行程序主目錄
如果安全模式打開了,但是卻是要執(zhí)行某些程序的時候,可以指定要執(zhí)行程序的主目錄:safe_mode_exec_dir = D:/usr/bin一般情況下是不需要執(zhí)行什么程序的,所以推薦不要執(zhí)行系統(tǒng)程序目錄,可以指向一個目錄,
然后把需要執(zhí)行的程序拷貝過去,比如:safe_mode_exec_dir = D:/tmp/cmd但是,我更推薦不要執(zhí)行任何程序,那么就可以指向我們網(wǎng)頁目錄:
safe_mode_exec_dir = D:/usr/www(4) 安全模式下包含文件
如果要在安全模式下包含某些公共文件,那么就修改一下選項:safe_mode_include_dir = D:/usr/www/include/其實一般php腳本中包含文件都是在程序自己已經(jīng)寫好了,這個可以根據(jù)具體需要設(shè)置。
(5) 控制php腳本能訪問的目錄
使用open_basedir選項能夠控制PHP腳本只能訪問指定的目錄,這樣能夠避免PHP腳本訪問
不應(yīng)該訪問的文件,一定程度上限制了phpshell的危害,我們一般可以設(shè)置為只能訪問網(wǎng)站目錄:open_basedir = D:/usr/www(6) 關(guān)閉危險函數(shù)
如果打開了安全模式,那么函數(shù)禁止是可以不需要的,但是我們?yōu)榱税踩€是考慮進(jìn)去。比如,
我們覺得不希望執(zhí)行包括system()等在那的能夠執(zhí)行命令的php函數(shù),或者能夠查看php信息的
phpinfo()等函數(shù),那么我們就可以禁止它們:disable_functions = system,passthru,exec,shell_exec,popen,phpinfo如果你要禁止任何文件和目錄的操作,那么可以關(guān)閉很多文件操作
disable_functions = chdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir, rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chown以上只是列了部分不叫常用的文件處理函數(shù),你也可以把上面執(zhí)行命令函數(shù)和這個函數(shù)結(jié)合,
就能夠抵制大部分的phpshell了。(7) 關(guān)閉PHP版本信息在http頭中的泄漏
我們?yōu)榱朔乐购诳瞳@取服務(wù)器中php版本的信息,可以關(guān)閉該信息斜路在http頭中:expose_php = Off比如黑客在 telnet www.12345.com 80 的時候,那么將無法看到PHP的信息。
(8) 關(guān)閉注冊全局變量
在PHP中提交的變量,包括使用POST或者GET提交的變量,都將自動注冊為全局變量,能夠直接訪問,
這是對服務(wù)器非常不安全的,所以我們不能讓它注冊為全局變量,就把注冊全局變量選項關(guān)閉:register_globals = Off當(dāng)然,如果這樣設(shè)置了,那么獲取對應(yīng)變量的時候就要采用合理方式,比如獲取GET提交的變量var,
那么就要用$_GET["var"]來進(jìn)行獲取,這個php程序員要注意。(9) 打開magic_quotes_gpc來防止SQL注入
SQL注入是非常危險的問題,小則網(wǎng)站后臺被入侵,重則整個服務(wù)器淪陷,
所以一定要小心。php.ini中有一個設(shè)置:magic_quotes_gpc = Off這個默認(rèn)是關(guān)閉的,如果它打開后將自動把用戶提交對sql的查詢進(jìn)行轉(zhuǎn)換,
比如把 " 轉(zhuǎn)為 '等,這對防止sql注射有重大作用。所以我們推薦設(shè)置為:magic_quotes_gpc = On(10) 錯誤信息控制
一般php在沒有連接到數(shù)據(jù)庫或者其他情況下會有提示錯誤,一般錯誤信息中會包含php腳本當(dāng)
前的路徑信息或者查詢的SQL語句等信息,這類信息提供給黑客后,是不安全的,所以一般服務(wù)器建議禁止錯誤提示:display_errors = Off如果你卻是是要顯示錯誤信息,一定要設(shè)置顯示錯誤的級別,比如只顯示警告以上的信息:
error_reporting = E_WARNING & E_ERROR當(dāng)然,我還是建議關(guān)閉錯誤提示。
(11) 錯誤日志
建議在關(guān)閉display_errors后能夠把錯誤信息記錄下來,便于查找服務(wù)器運(yùn)行的原因:log_errors = On同時也要設(shè)置錯誤日志存放的目錄,建議根apache的日志存在一起:
error_log = D:/usr/local/apache2/logs/php_error.log注意:給文件必須允許apache用戶的和組具有寫的權(quán)限。
MYSQL的降權(quán)運(yùn)行
新建立一個用戶比如mysqlstartnet user mysqlstart fuckmicrosoft /add net localgroup users mysqlstart /del不屬于任何組
如果MYSQL裝在d:mysql ,那么,給 mysqlstart 完全控制 的權(quán)限
然后在系統(tǒng)服務(wù)中設(shè)置,MYSQL的服務(wù)屬性,在登錄屬性當(dāng)中,選擇此用戶 mysqlstart 然后輸入密碼,確定。
重新啟動 MYSQL服務(wù),然后MYSQL就運(yùn)行在低權(quán)限下了。
如果是在windos平臺下搭建的apache我們還需要注意一點,apache默認(rèn)運(yùn)行是system權(quán)限,
這很恐怖,這讓人感覺很不爽.那我們就給apache降降權(quán)限吧。net user apache fuckmicrosoft /add net localgroup users apache /delok.我們建立了一個不屬于任何組的用戶apche。
我們打開計算機(jī)管理器,選服務(wù),點apache服務(wù)的屬性,我們選擇log on,選擇this account,我們填入上面所建立的賬戶和密碼,
重啟apache服務(wù),ok,apache運(yùn)行在低權(quán)限下了。
實際上我們還可以通過設(shè)置各個文件夾的權(quán)限,來讓apache用戶只能執(zhí)行我們想讓它能干的事情,給每一個目錄建立一個多帶帶能讀寫的用戶。
這也是當(dāng)前很多虛擬主機(jī)提供商的流行配置方法哦,不過這種方法用于防止這里就顯的有點大材小用了。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/28150.html
摘要:參考中如何防止注入?yún)?shù)化查詢?yōu)槭裁茨軌蚍乐棺⑷肷厦嫣峁┑馁Y料比較多,下面根據(jù)自己的理解整理出來。使用的預(yù)處理參數(shù)化查詢可以有效防止注入。我們在上面預(yù)處理參數(shù)化查詢是在中進(jìn)行防注入操作的,其實也內(nèi)置了一個預(yù)處理的模擬器,叫做。 由于segmentfault在處理特殊字符時也并非完美,所以下面文章中有些符號被轉(zhuǎn)換了,請到本人博客下載原文txt http://www.yunxi365.cn/...
閱讀 2575·2023-04-25 17:33
閱讀 652·2021-11-23 09:51
閱讀 2956·2021-07-30 15:32
閱讀 1404·2019-08-29 18:40
閱讀 1949·2019-08-28 18:19
閱讀 1469·2019-08-26 13:48
閱讀 2245·2019-08-23 16:48
閱讀 2280·2019-08-23 15:56