日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > php >内容正文

php

php防止sql注入的方法

發(fā)布時間:2023/12/10 php 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php防止sql注入的方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一.什么是SQL注入式攻擊?

????????所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字符串,欺騙服務(wù)器執(zhí)行惡意的SQL命令。在某些表單中,用戶輸入的內(nèi)容直接用來構(gòu)造(或者影響)動態(tài)SQL命令,或作為存儲過程的輸入?yún)?shù),這類表單特別容易受到SQL注入式攻擊。

例如一個簡單的登錄表單(這里把密碼寫成明文方便說明):?
?
當(dāng)在表單中填寫這樣的語句進行提交登錄時會出現(xiàn)這樣的SQL語句

select * from t_admin where admin_name='xxx' and admin_pwd='xxx'' or '1'

這樣會查詢出所有的用戶信息,所有存在不安全隱患

二.常見的SQL注入式攻擊過程類如:

⑴ 某個php Web應(yīng)用有一個登錄頁面,這個登錄頁面控制著用戶是否有權(quán)訪問應(yīng)用,它要求用戶輸入一個名稱和密碼

⑵ 登錄頁面中輸入的內(nèi)容將直接用來構(gòu)造動態(tài)的SQL命令,或者直接用作存儲過程的參數(shù)

⑶ 攻擊者在用戶名字和密碼輸入框中輸入"'或'1'='1"之類的內(nèi)容

⑷ 用戶輸入的內(nèi)容提交給服務(wù)器之后,服務(wù)器運行上面的php代碼構(gòu)造出查詢用戶的SQL命令,但由于攻擊者輸入的內(nèi)容非常特殊,所以最后得到的SQL命令變成:SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'.

⑸ 服務(wù)器執(zhí)行查詢或存儲過程,將用戶輸入的身份信息和服務(wù)器中保存的身份信息進行對比

⑹ 由于SQL命令實際上已被注入式攻擊修改,已經(jīng)不能真正驗證用戶身份,所以系統(tǒng)會錯誤地授權(quán)給攻擊者

如果攻擊者知道應(yīng)用會將表單中輸入的內(nèi)容直接用于驗證身份的查詢,他就會嘗試輸入某些特殊的SQL字符串篡改查詢改變其原來的功能,欺騙系統(tǒng)授予訪問權(quán)限。

系統(tǒng)環(huán)境不同,攻擊者可能造成的損害也不同,這主要由應(yīng)用訪問數(shù)據(jù)庫的安全權(quán)限決定。如果用戶的帳戶具有管理員或其他比較高級的權(quán)限,攻擊者就可能對數(shù)據(jù)庫的表執(zhí)行各種他想要做的操作,包括添加、刪除或更新數(shù)據(jù),甚至可能直接刪除表。

三.常用的SQL注入方式

1. 使用單引號及or關(guān)鍵字

SELECT * FROM Users WHERE Username='$username' AND Password='$password'

?我們針對上面的SQL語句分析,發(fā)現(xiàn)如果用下面的測試數(shù)據(jù)就能夠進行SQL注入了?
?username=1′or′1′=′1password=1’or’1’=’1?
?看看整個SQL查詢語句變成:?

?SELECT * FROM Users WHERE Username='1' OR '1'='1' AND Password='1'OR '1'='1'

?假設(shè)參數(shù)值是通過GET方法傳遞到服務(wù)器的,且域名為www.example.com 那么我們的訪問請求就是:
http://www.example.com/index.php?username=1‘%20or%20’1’%20=%20’1password=1’%20or%20’1’%20=%20’1?
? 對上面的SQL語句作簡單分析后我們就知道由于該語句永遠為真,所以肯定會返回一些數(shù)據(jù),在這種情況下實際上并未驗證用戶名和密碼,并且在某些系統(tǒng)中,用戶表的第一行記錄是管理員,那這樣造成的后果則更為嚴重。

2. 使用括號

SELECT * FROM Users WHERE((Username='$username')AND(Password=MD5('$password')))

?在這個例子中,存在兩個問題,一個是括號的用法,還有一個是MD5哈希函數(shù)的用法。對于第一個問題,我們很容找出缺少的右括號解決,對于第二個問題,我們可以想辦法使第二個條件失效。我們在查詢語句的最后加上一個注釋符以表示后面的都是注釋,常見的注釋起始符是/*(在Oracle中是–),也就是說,我們用如下的用戶名和密碼:?
?username=1′or′1′=′1′))/?password = foo??那么整條SQL語句就變?yōu)?#xff1a;?

? SELECT * FROM Users WHERE(( Username='1'or '1'='1'))/*')AND (Password=MD5('$password')))

??那么看看URL請求就變?yōu)?#xff1a;?
?http://www.example.com/index.php?username=1‘%20or%20’1’%20=%20’1’))/*&password=foo?
?#####

3.Union查詢SQL注入測試 ??
??Union查詢SQL注入測試 ? 還有一種測試是利用Union的,利用Union可以連接查詢,從而從其他表中得到信息,假設(shè)如下查詢:?

? SELECT Name, Phone, Address FROM Users WHERE Id=$id

?然后我們設(shè)置id的值為:?
?$id =1 UNION ALL SELECT creditCardNumber,1,1 FROM CreditCarTable ,?那么整體的查詢就變?yōu)?#xff1a;?

?SELECT Name, Phone,Address FROM Users WHERE Id=1 UNION ALL SELECT creaditCardNumber,1,1 FROM CreditCarTable

?顯示這就能得到所有信用卡用戶的信息。 ??盲目SQL注入測試 ? 在上面我們提到過盲SQL注入,即bind SQL Injection,它意味著對于某個操作我們得不到任何信息,通常這是由于程序員已經(jīng)編寫了特定的出錯返回頁面,從而隱藏了數(shù)據(jù)庫結(jié)構(gòu)的信息。 ??

但利用推理方法,有時候我們能夠恢復(fù)特定字段的值。這種方法通常采用一組對服務(wù)器的布爾查詢,依據(jù)返回的結(jié)果來推斷結(jié)果的含義。仍然延續(xù)上面的www.example.com有一個參數(shù)名為id, 那么我們輸入以下url請求:?
??http://www.exampe.com/index.php?id=1’?
?顯然由于語法錯誤,我們會得到一個預(yù)先定義好的出錯頁面,假設(shè)服務(wù)器上的查詢語句為 :
?SELECT field1,field2,field3 FROM Users WHERE Id=’Id′假設(shè)我們想要的用戶名字段的值,那么通過一些函數(shù),我們就可以逐字符的讀取用戶名的值。在這里我們使用以下的函數(shù):SUBSTRING(text,start,length),ASCII(char),LENGTH(text)?我們定義id為:引用Id=1’ AND ASCII(SUBSTRING(username,1,1))=97 AND ‘1’=’1?
?那么最終的SQL查詢語句為:?

SELECT field1,field2,field3 FROM Users WHERE Id='1' AND ASCII(SUBSTRING(username,1,1))=97 AND '1'='1'

?那么,如果在數(shù)據(jù)庫中有用戶名的第一字符的ASCII碼為97的話,那么我們就能得到一個真值u,那么就繼續(xù)尋找該用戶名的下一個字符;如果沒有的話,那么我們就增猜測第一個字符的ASCII碼為98的用戶名,這樣反復(fù)下去就能判斷出合法的用戶名

四.如何防范?

只要在利用表單輸入的內(nèi)容構(gòu)造SQL命令之前,把所有輸入內(nèi)容過濾一番就可以了。過濾輸入內(nèi)容可以按多種方式進行:

?(1)對于動態(tài)構(gòu)造SQL查詢的場合,可以使用下面的技術(shù):

? 第一:替換單引號,即把所有單獨出現(xiàn)的單引號改成兩個單引號,防止攻擊者修改SQL命令的含義。再來看前面的例子,“SELECT * from Users WHERE login = ''' or ''1''=''1' AND password = ''' or ''1''=''1'”顯然會得到與“SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'”不同的結(jié)果

??第二:刪除用戶輸入內(nèi)容中的所有連字符,防止攻擊者構(gòu)造出類如“SELECT * from Users WHERE login = 'mas' AND password =''”之類的查詢,因為這類查詢的后半部分已經(jīng)被注釋掉,不再有效,攻擊者只要知道一個合法的用戶登錄名稱,根本不需要知道用戶的密碼就可以順利獲得訪問權(quán)限

第三:對于用來執(zhí)行查詢的數(shù)據(jù)庫帳戶,限制其權(quán)限。用不同的用戶帳戶執(zhí)行查詢、插入、更新、刪除操作。由于隔離了不同帳戶可執(zhí)行的操作,因而也就防止了原本用于執(zhí)行SELECT命令的地方卻被用于執(zhí)行INSERT、UPDATE或DELETE命令

?(2)用存儲過程來執(zhí)行所有的查詢。SQL參數(shù)的傳遞方式將防止攻擊者利用單引號和連字符實施攻擊。此外,它還使得數(shù)據(jù)庫權(quán)限可以限制到只允許特定的存儲過程執(zhí)行,所有的用戶輸入必須遵從被調(diào)用的存儲過程的安全上下文,這樣就很難再發(fā)生注入式攻擊了。

?(3)限制表單或查詢字符串輸入的長度。如果用戶的登錄名字最多只有10個字符,那么不要認可表單中輸入的10個以上的字符,這將大大增加攻擊者在SQL命令中插入有害代碼的難度

?(4)檢查用戶輸入的合法性,確信輸入的內(nèi)容只包含合法的數(shù)據(jù)。數(shù)據(jù)檢查應(yīng)當(dāng)在客戶端和服務(wù)器端都執(zhí)行,之所以要執(zhí)行服務(wù)器端驗證,是為了彌補客戶端驗證機制脆弱的安全性??

?在客戶端,攻擊者完全有可能獲得網(wǎng)頁的源代碼,修改驗證合法性的腳本(或者直接刪除腳本),然后將非法內(nèi)容通過修改后的表單提交給服務(wù)器。因此,要保證驗證操作確實已經(jīng)執(zhí)行,唯一的辦法就是在服務(wù)器端也執(zhí)行驗證。你可以使用許多內(nèi)建的驗證對象,例如RegularExpressionValidator,它們能夠自動生成驗證用的客戶端腳本,當(dāng)然你也可以插入服務(wù)器端的方法調(diào)用。如果找不到現(xiàn)成的驗證對象,你可以通過CustomValidator自己創(chuàng)建一個。

?(5) 將用戶登錄名稱、密碼等數(shù)據(jù)加密保存。加密用戶輸入的數(shù)據(jù),然后再將它與數(shù)據(jù)庫中保存的數(shù)據(jù)比較,這相當(dāng)于對用戶輸入的數(shù)據(jù)進行了“消毒”處理,用戶輸入的數(shù)據(jù)不再對數(shù)據(jù)庫有任何特殊的意義,從而也就防止了攻擊者注入SQL命令

(6) 檢查提取數(shù)據(jù)的查詢所返回的記錄數(shù)量。如果程序只要求返回一個記錄,但實際返回的記錄卻超過一行,那就當(dāng)作出錯處理。

?(7)使用預(yù)處理語句

常用SQL注入的解決方案

1.添加圖形碼進行驗證

添加圖形碼在一定程序上增加代碼的安全性,給機器強制破解有一定的攔截作用,但不能阻止所有的攻擊,故還是需要在程序上進行安全性考慮

2.使用預(yù)備義語句和參數(shù)化查詢

使用預(yù)處理語句和參數(shù)化查詢。預(yù)處理語句和參數(shù)分別發(fā)送到數(shù)據(jù)庫服務(wù)器進行解析,參數(shù)將會被當(dāng)作普通字符處理。這種方式使得攻擊者無法注入惡意的SQL。常用的方式有兩種

2.1 使用PDO(PHP Data Objects )

$stmt = $pdo->prepare('SELECT * FROM t_admin WHERE admin_name = :name'); $stmt->execute(array('name' => $name)); foreach ($stmt as $row) {// do something with $row }

注意,在默認情況使用PDO并沒有讓MySQL數(shù)據(jù)庫執(zhí)行真正的預(yù)處理語句(原因見下文)。為了解決這個問題,你應(yīng)該禁止PDO模擬預(yù)處理語句。一個正確使用PDO創(chuàng)建數(shù)據(jù)庫連接的例子如下

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

2.2 使用MySQLi

$stmt = $dbConnection->prepare('SELECT * FROM t_admin WHERE admin_name = ?'); $stmt->bind_param('s', $name); $stmt->execute(); $result = $stmt->get_result(); while ($row = $result->fetch_assoc()) {// do something with $row }

3.對用戶傳遞的參數(shù)進行處理

我們知道Web上提交數(shù)據(jù)有兩種方式,一種是get、一種是post,那么很多常見的sql注射就是從get方式入手的,而且注射的語句里面一定是包含一些sql語句的,因為沒有sql語句,那么如何進行,sql語句有四大句:select 、update、delete、insert,那么我們?nèi)绻谖覀兲峤坏臄?shù)據(jù)中進行過濾是不是能夠避免這些問題呢??
于是我們使用正則就構(gòu)建如下函數(shù):

<?phpfunction inject_check($sql_str) { return eregi('select|insert|update|delete|');}function verify_id($id=null) { if (!$id) { exit('沒有提交參數(shù)!'); } // 是否為空判斷 elseif (inject_check($id)) { exit('提交的參數(shù)非法!'); } // 注射判斷 elseif (!is_numeric($id)) { exit('提交的參數(shù)非法!'); } // 數(shù)字判斷 $id = intval($id); // 整型化 return $id; } ?>

那么我們就能夠進行校驗了,于是我們上面的程序代碼就變成了下面的:

<?php if (inject_check($_GET['id'])) { exit('你提交的數(shù)據(jù)非法,請檢查后重新提交!'); } else { $id = verify_id($_GET['id']); // 這里引用了我們的過濾函數(shù),對$id進行過濾 echo '提交的數(shù)據(jù)合法,請繼續(xù)!'; } ?>

好,問題到這里似乎都解決了,但是我們有沒有考慮過post提交的數(shù)據(jù),大批量的數(shù)據(jù)呢??
比如一些字符可能會對數(shù)據(jù)庫造成危害,比如 ’ _ ‘, ’ %’,這些字符都有特殊意義,那么我們?nèi)绻M行控制呢?還有一點,就是當(dāng)我們的php.ini里面的magic_quotes_gpc = off的時候,那么提交的不符合數(shù)據(jù)庫規(guī)則的數(shù)據(jù)都是不會自動在前面加’ ‘的,那么我們要控制這些問題,于是構(gòu)建如下函數(shù):

<?php function str_check( $str ) { if (!get_magic_quotes_gpc()) // 判斷magic_quotes_gpc是否打開 { $str = addslashes($str); // 進行過濾 } $str = str_replace("_", "\_", $str); // 把 '_'過濾掉 $str = str_replace("%", "\%", $str); // 把' % '過濾掉 return $str; } ?> 最后,再考慮提交一些大批量數(shù)據(jù)的情況,比如發(fā)貼,或者寫文章、新聞,我們需要一些函數(shù)來幫我們過濾和進行轉(zhuǎn)換,再上面函數(shù)的基礎(chǔ)上,對提交的數(shù)據(jù)進行引號轉(zhuǎn)義及將HTML標(biāo)簽轉(zhuǎn)換成HTML實體,可以構(gòu)建如下函數(shù): <?php function post_check($post) { if (!get_magic_quotes_gpc()) // 判斷magic_quotes_gpc是否為打開 { $post = addslashes($post); // 進行magic_quotes_gpc沒有打開的情況對提交數(shù)據(jù)的過濾 } $post = str_replace("_", "\_", $post); // 把 '_'過濾掉 $post = str_replace("%", "\%", $post); // 把' % '過濾掉 $post = nl2br($post); // 回車轉(zhuǎn)換 $post= htmlspecialchars($post); // html標(biāo)記轉(zhuǎn)換 return $post; } ?>或者根據(jù)API文檔中的: TP框架防止sql注入:

對于WEB應(yīng)用來說,SQL注入攻擊無疑是首要防范的安全問題,系統(tǒng)底層對于數(shù)據(jù)安全方面本身進行了很多的處理和相應(yīng)的防范機制,例如:

  • $User?=?M("User");?// 實例化User對象
  • $User->find($_GET["id"]);
  • 即便用戶輸入了一些惡意的id參數(shù),系統(tǒng)也會強制轉(zhuǎn)換成整型,避免惡意注入。這是因為,系統(tǒng)會對數(shù)據(jù)進行強制的數(shù)據(jù)類型檢測,并且對數(shù)據(jù)來源進行數(shù)據(jù)格式轉(zhuǎn)換。而且,對于字符串類型的數(shù)據(jù),ThinkPHP都會進行escape_string處理(real_escape_string,mysql_escape_string),如果你采用PDO方式的話,還支持參數(shù)綁定。

    通常的安全隱患在于你的查詢條件使用了字符串參數(shù),然后其中一些變量又依賴由客戶端的用戶輸入。

    要有效的防止SQL注入問題,我們建議:

    • 查詢條件盡量使用數(shù)組方式,這是更為安全的方式;
    • 如果不得已必須使用字符串查詢條件,使用預(yù)處理機制;
    • 使用自動驗證和自動完成機制進行針對應(yīng)用的自定義過濾;
    • 如果環(huán)境允許,盡量使用PDO方式,并使用參數(shù)綁定。

    查詢條件預(yù)處理

    where方法使用字符串條件的時候,支持預(yù)處理(安全過濾),并支持兩種方式傳入預(yù)處理參數(shù),例如:

  • $Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();
  • // 或者
  • $Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();
  • 模型的query和execute方法 同樣支持預(yù)處理機制,例如:

  • $model->query('select * from user where id=%d and status=%d',$id,$status);
  • //或者
  • $model->query('select * from user where id=%d and status=%d',array($id,$status));
  • execute方法用法同query方法。

    總結(jié)

    以上是生活随笔為你收集整理的php防止sql注入的方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。