最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

PHP+SQL 注入攻擊的技術實現(xiàn)以及預防辦法

 更新時間:2011年01月27日 22:54:46   作者:  
最近在折騰 PHP + MYSQL 的編程。了解了一些 PHP SQL 注入攻擊的知識,總結一下經(jīng)驗。在我看來,引發(fā) SQL 注入攻擊的主要原因,是因為以下兩點原因

1. php 配置文件 php.ini 中的 magic_quotes_gpc 選項沒有打開,被置為 off
2. 開發(fā)者沒有對數(shù)據(jù)類型進行檢查和轉(zhuǎn)義
  不過事實上,第二點最為重要。我認為, 對用戶輸入的數(shù)據(jù)類型進行檢查,向 MYSQL 提交正確的數(shù)據(jù)類型,這應該是一個 web 程序員最最基本的素質(zhì)。但現(xiàn)實中,常常有許多小白式的 Web 開發(fā)者忘了這點, 從而導致后門大開。
  為什么說第二點最為重要?因為如果沒有第二點的保證,magic_quotes_gpc 選項,不論為 on,還是為 off,都有可能引發(fā) SQL 注入攻擊。下面來看一下技術實現(xiàn):
 一. magic_quotes_gpc = Off 時的注入攻擊
  magic_quotes_gpc = Off 是 php 中一種非常不安全的選項。新版本的 php 已經(jīng)將默認的值改為了 On。但仍有相當多的服務器的選項為 off。畢竟,再古董的服務器也是有人用的。
  當magic_quotes_gpc = On 時,它會將提交的變量中所有的 '(單引號)、"(雙號號)、\(反斜線)、空白字符,都為在前面自動加上 \。下面是 php 的官方說明:

復制代碼 代碼如下:

magic_quotes_gpc boolean
Sets the magic_quotes state for GPC (Get/Post/Cookie) operations. When magic_quotes are on, all ' (single-quote), " (double quote), \ (backslash) and NUL's are escaped with a backslash automatically

如果沒有轉(zhuǎn)義,即 off 情況下,就會讓攻擊者有機可乘。以下列測試腳本為例:
復制代碼 代碼如下:

<?
if ( isset($_POST["f_login"] ) )
{
// 連接數(shù)據(jù)庫...
// ...代碼略...

// 檢查用戶是否存在
$t_strUname = $_POST["f_uname"];
$t_strPwd = $_POST["f_pwd"];
$t_strSQL = "SELECT * FROM tbl_users WHERE username='$t_strUname' AND password = '$t_strPwd' LIMIT 0,1";

if ( $t_hRes = mysql_query($t_strSQL) )
{
// 成功查詢之后的處理. 略...
}
}
?>
<html><head><title>sample test</title></head>
<body>
<form method=post action="">
Username: <input type="text" name="f_uname" size=30><br>
Password: <input type=text name="f_pwd" size=30><br>

<input type="submit" name="f_login" value="登錄">
</form>
</body>

在這個腳本中,當用戶輸入正常的用戶名和密碼,假設值分別為 zhang3、abc123,則提交的 SQL 語句如下:
復制代碼 代碼如下:

SELECT * FROM tbl_users
WHERE username='zhang3' AND password = 'abc123' LIMIT 0,1

如果攻擊者在 username 字段中輸入:zhang3' OR 1=1 #,在 password 輸入 abc123,則提交的 SQL 語句變成如下:
復制代碼 代碼如下:

SELECT * FROM tbl_users
WHERE username='zhang3' OR 1=1 #' AND password = 'abc123' LIMIT 0,1

由于 # 是 mysql中的注釋符, #之后的語句不被執(zhí)行,實現(xiàn)上這行語句就成了:
復制代碼 代碼如下:

SELECT * FROM tbl_users
WHERE username='zhang3' OR 1=1

這樣攻擊者就可以繞過認證了。如果攻擊者知道數(shù)據(jù)庫結構,那么它構建一個 UNION SELECT,那就更危險了:
  假設在 username 中輸入:zhang3 ' OR 1 =1 UNION select cola, colb,cold FROM tbl_b #
  在password 輸入: abc123,
  則提交的 SQL 語句變成:
復制代碼 代碼如下:

SELECT * FROM tbl_users
WHERE username='zhang3 '
OR 1 =1 UNION select cola, colb,cold FROM tbl_b #' AND password = 'abc123' LIMIT 0,1

這樣就相當危險了。如果agic_quotes_gpc選項為 on,引號被轉(zhuǎn)義,則上面攻擊者構建的攻擊語句就會變成這樣,從而無法達到其目的:
復制代碼 代碼如下:

SELECT * FROM tbl_users
WHERE username='zhang3\' OR 1=1 #'
AND password = 'abc123'
LIMIT 0,1
SELECT * FROM tbl_users
WHERE username='zhang3 \' OR 1 =1 UNION select cola, colb,cold FROM tbl_b #'
AND password = 'abc123' LIMIT 0,1

二. magic_quotes_gpc = On 時的注入攻擊
  當 magic_quotes_gpc = On 時,攻擊者無法對字符型的字段進行 SQL 注入。這并不代表這就安全了。這時,可以通過數(shù)值型的字段進行SQL注入。
  在最新版的 MYSQL 5.x 中,已經(jīng)嚴格了數(shù)據(jù)類型的輸入,已默認關閉自動類型轉(zhuǎn)換。數(shù)值型的字段,不能是引號標記的字符型。也就是說,假設 uid 是數(shù)值型的,在以前的 mysql 版本中,這樣的語句是合法的:
復制代碼 代碼如下:

INSERT INTO tbl_user SET uid="1";
SELECT * FROM tbl_user WHERE uid="1";

在最新的 MYSQL 5.x 中,上面的語句不是合法的,必須寫成這樣:
復制代碼 代碼如下:

INSERT INTO tbl_user SET uid=1;
SELECT * FROM tbl_user WHERE uid=1;

這樣我認為是正確的。因為作為開發(fā)者,向數(shù)據(jù)庫提交正確的符合規(guī)則的數(shù)據(jù)類型,這是最基本的要求。
  那么攻擊者在 magic_quotes_gpc = On 時,他們怎么攻擊呢?很簡單,就是對數(shù)值型的字段進行 SQL 注入。以下列的 php 腳本為例:
復制代碼 代碼如下:

<?
if ( isset($_POST["f_login"] ) )
{
// 連接數(shù)據(jù)庫...
// ...代碼略...
// 檢查用戶是否存在
$t_strUid = $_POST["f_uid"];
$t_strPwd = $_POST["f_pwd"];
$t_strSQL = "SELECT * FROM tbl_users WHERE uid=$t_strUid AND password = '$t_strPwd' LIMIT 0,1";
if ( $t_hRes = mysql_query($t_strSQL) )
{
// 成功查詢之后的處理. 略...
}
}
?>
<html><head><title>sample test</title></head>
<body>
<form method=post action="">
User ID: <input type="text" name="f_uid" size=30><br>
Password: <input type=text name="f_pwd" size=30><br>
<input type="submit" name="f_login" value="登錄">
</form>
</body>

上面這段腳本要求用戶輸入 userid 和 password 登入。一個正常的語句,用戶輸入 1001和abc123,提交的 sql 語句如下:
SELECT * FROM tbl_users WHERE userid=1001 AND password = 'abc123' LIMIT 0,1
  如果攻擊者在 userid 處,輸入:1001 OR 1 =1 #,則注入的sql語句如下:
SELECT * FROM tbl_users WHERE userid=1001 OR 1 =1 # AND password = 'abc123' LIMIT 0,1
  攻擊者達到了目的。
 三. 如何防止 PHP SQL 注入攻擊
  如何防止 php sql 注入攻擊?我認為最重要的一點,就是要對數(shù)據(jù)類型進行檢查和轉(zhuǎn)義。總結的幾點規(guī)則如下:
php.ini 中的 display_errors 選項,應該設為 display_errors = off。這樣 php 腳本出錯之后,不會在 web 頁面輸出錯誤,以免讓攻擊者分析出有作的信息。
調(diào)用 mysql_query 等 mysql 函數(shù)時,前面應該加上 @,即 @mysql_query(...),這樣 mysql 錯誤不會被輸出。同理以免讓攻擊者分析出有用的信息。另外,有些程序員在做開發(fā)時,當 mysql_query出錯時,習慣輸出錯誤以及 sql 語句,例如:
復制代碼 代碼如下:

$t_strSQL = "SELECT a from b....";
if ( mysql_query($t_strSQL) )
{
// 正確的處理
}
else
{
echo "錯誤! SQL 語句:$t_strSQL \r\n錯誤信息".mysql_query();
exit;
}

這種做法是相當危險和愚蠢的。如果一定要這么做,最好在網(wǎng)站的配置文件中,設一個全局變量或定義一個宏,設一下 debug 標志:
復制代碼 代碼如下:

全局配置文件中:
define("DEBUG_MODE",0); // 1: DEBUG MODE; 0: RELEASE MODE
//調(diào)用腳本中:
$t_strSQL = "SELECT a from b....";
if ( mysql_query($t_strSQL) )
{
// 正確的處理
}
else
{
if (DEBUG_MODE)
echo "錯誤! SQL 語句:$t_strSQL \r\n錯誤信息".mysql_query();
exit;
}

對提交的 sql 語句,進行轉(zhuǎn)義和類型檢查。
 四. 我寫的一個安全參數(shù)獲取函數(shù)
  為了防止用戶的錯誤數(shù)據(jù)和 php + mysql 注入 ,我寫了一個函數(shù) PAPI_GetSafeParam(),用來獲取安全的參數(shù)值:
復制代碼 代碼如下:

define("XH_PARAM_INT",0);
define("XH_PARAM_TXT",1);
function PAPI_GetSafeParam($pi_strName, $pi_Def = "", $pi_iType = XH_PARAM_TXT)
{
if ( isset($_GET[$pi_strName]) )
$t_Val = trim($_GET[$pi_strName]);
else if ( isset($_POST[$pi_strName]))
$t_Val = trim($_POST[$pi_strName]);
else
return $pi_Def;
// INT
if ( XH_PARAM_INT == $pi_iType)
{
if (is_numeric($t_Val))
return $t_Val;
else
return $pi_Def;
}
// String
$t_Val = str_replace("&", "&amp;",$t_Val);
$t_Val = str_replace("<", "&lt;",$t_Val);
$t_Val = str_replace(">", "&gt;",$t_Val);
if ( get_magic_quotes_gpc() )
{
$t_Val = str_replace("\\\"", "&quot;",$t_Val);
$t_Val = str_replace("\\''", "&#039;",$t_Val);
}
else
{
$t_Val = str_replace("\"", "&quot;",$t_Val);
$t_Val = str_replace("'", "&#039;",$t_Val);
}
return $t_Val;
}

在這個函數(shù)中,有三個參數(shù):
復制代碼 代碼如下:

$pi_strName: 變量名
$pi_Def: 默認值
$pi_iType: 數(shù)據(jù)類型。取值為 XH_PARAM_INT, XH_PARAM_TXT, 分別表示數(shù)值型和文本型。

如果請求是數(shù)值型,那么調(diào)用 is_numeric() 判斷是否為數(shù)值。如果不是,則返回程序指定的默認值。
  簡單起見,對于文本串,我將用戶輸入的所有危險字符(包括HTML代碼),全部轉(zhuǎn)義。由于 php 函數(shù) addslashes()存在漏洞,我用 str_replace()直接替換。get_magic_quotes_gpc() 函數(shù)是 php 的函數(shù),用來判斷 magic_quotes_gpc 選項是否打開。
  剛才第二節(jié)的示例,代碼可以這樣調(diào)用:
復制代碼 代碼如下:

<?
if ( isset($_POST["f_login"] ) )
{
// 連接數(shù)據(jù)庫...
// ...代碼略...
// 檢查用戶是否存在
$t_strUid = PAPI_GetSafeParam("f_uid", 0, XH_PARAM_INT);
$t_strPwd = PAPI_GetSafeParam("f_pwd", "", XH_PARAM_TXT);
$t_strSQL = "SELECT * FROM tbl_users WHERE uid=$t_strUid AND password = '$t_strPwd' LIMIT 0,1";
if ( $t_hRes = mysql_query($t_strSQL) )
{
// 成功查詢之后的處理. 略...
}
}
?>

這樣的話,就已經(jīng)相當安全了。PAPI_GetSafeParam的代碼有點長,但犧牲這點效率,對保證安全,是值得的。希望大家多批評指正。:)

相關文章

  • PHP代碼覆蓋率統(tǒng)計詳解

    PHP代碼覆蓋率統(tǒng)計詳解

    這篇文章主要介紹了PHP代碼覆蓋率統(tǒng)計詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-07-07
  • php頁面消耗內(nèi)存過大的處理辦法

    php頁面消耗內(nèi)存過大的處理辦法

    是因為php頁面消耗的最大內(nèi)存默認是為 8M (在PHP的ini件里可以看到) ,如果文件太大 或圖片太大 在讀取的時候 會發(fā)生錯誤。
    2013-03-03
  • php的socket編程詳解

    php的socket編程詳解

    socket的英文原義是“孔”或“插座”。作為BSD UNIX的進程通信機制,取后一種意思。用于描述IP地址和端口,是一個通信鏈的句柄。在Internet上的主機一般運行了多個服務軟件,同時提供幾種服務。每種服務都打開一個Socket并綁定到一個端口上,不同的端口對應于不同的服務
    2016-11-11
  • PHP 輸出緩沖控制(Output Control)詳解

    PHP 輸出緩沖控制(Output Control)詳解

    本文主要介紹PHP 輸出緩沖控制,這里提供了詳細的相關資料及簡單示例代碼,幫助大家學習參考,有興趣的小伙伴可以參考下
    2016-08-08
  • PHP使用enqueue/amqp-lib實現(xiàn)rabbitmq任務處理

    PHP使用enqueue/amqp-lib實現(xiàn)rabbitmq任務處理

    這篇文章主要為大家詳細介紹了PHP如何使用enqueue/amqp-lib實現(xiàn)rabbitmq任務處理,文中的示例代碼講解詳細,感興趣的小伙伴可以學習一下
    2024-03-03
  • 解析php時間戳與日期的轉(zhuǎn)換

    解析php時間戳與日期的轉(zhuǎn)換

    本篇文章是對php中時間戳與日期的轉(zhuǎn)換進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • PHP 文件編程綜合案例-文件上傳的實現(xiàn)

    PHP 文件編程綜合案例-文件上傳的實現(xiàn)

    本篇文章是對PHP中文件上傳的實現(xiàn)代碼進行了詳細的分析介紹,需要的朋友參考下
    2013-07-07
  • PHP實現(xiàn)獲取客戶端IP并獲取IP信息

    PHP實現(xiàn)獲取客戶端IP并獲取IP信息

    這篇文章主要介紹了PHP實現(xiàn)獲取客戶端IP并獲取IP信息的方法示例,非常實用,有需要的小伙伴快來參考下吧。
    2015-03-03
  • php中批量刪除Mysql中相同前綴的數(shù)據(jù)表的代碼

    php中批量刪除Mysql中相同前綴的數(shù)據(jù)表的代碼

    Mysql如何批量刪除相同前綴的數(shù)據(jù)表,原理就是讀取數(shù)據(jù)中的所有表,查找class_開頭的表,如果開頭是這個,就刪除。
    2011-07-07
  • php如何調(diào)用webservice應用介紹

    php如何調(diào)用webservice應用介紹

    Web Service也叫XML Web Service WebService是一種可以接收從Internet或者Intranet上的其它系統(tǒng)中傳遞過來的請求,輕量級通訊技術,接下來將詳細介紹php如何調(diào)用webservice,需要的朋友可以了解下
    2012-11-11

最新評論

博客| 中阳县| 循化| 哈尔滨市| 威海市| 岢岚县| 泾源县| 小金县| 肇源县| 兴化市| 新巴尔虎右旗| 延川县| 莫力| 呼图壁县| 佛冈县| 五寨县| 象山县| 开原市| 建瓯市| 定边县| 读书| 舟曲县| 普兰店市| 垣曲县| 景宁| 怀柔区| 石狮市| 东城区| 页游| 霍山县| 清丰县| 宜城市| 桐乡市| 永德县| 宜君县| 英山县| 宽城| 罗甸县| 怀集县| 东乡族自治县| 白朗县|