2. 型別處理不當
// 構造動態SQL語句 $sql = "select * from tbl where field = $_GET['user_id']"; // 執行SQL語句 $res = mysql_query($sql);
Mysql內建了一個命令,可以讀取檔案
Union all select load_file('/etc/passwd')-- select * from tbl where userid = 1 union all select load_file('etc/passwd')--
該命令會獲取資料庫管理員的密碼。
處理方法:
需要將用戶端傳過來的資料進行型別強制轉換,而後再查詢
$user_id = (int)$_GET['user_id']; "select * from tbl where userid = {$user_id}";
3. 查詢語句組織不當
user.php?table=user&
4. 錯誤處理不當
即將站點的錯誤資訊暴漏給使用者,這樣非常危險。
// 構造動態查詢語句 $getid = "select * from tbl where userid > 1"; // 執行SQL語句 $res = mysql_query($getid) or die('<pre>'.mysql_error().'</pre>'); 5. 多個提交處理不當 // 引數是否是一個字串 if(is_string($_GET["param"])){}
資料入庫時將轉換單引號、雙引號、反斜槓為實體
在入庫的時候如果不過濾 ' ""這樣的東西,這樣會使資料庫報錯,或者注入等問題。
先將字串用htmlspecialchars()轉換為實體後儲存到資料庫,然後從資料庫讀出來時htmlspecialchars_decode()轉為HTML標籤。
htmlspecialchars() 函數把一些預定義的字元轉換為 HTML 實體。
函數原型:
htmlspecialchars(string,quotestyle,character-set)
預定義的字元是:
& (和號) 成為 & 」 (雙引號) 成為 " ‘ (單引號) 成為 ' < (小於) 成為 < > (大於) 成為 >
htmlspecialchars_decode() 函數把一些預定義的 HTML 實體轉換為字元(和htmlspecialchars相反)。
函數原型:
htmlspecialchars_decode(string,quotestyle)
二、防止xss攻擊
什麼是xss攻擊?
和上邊的sql注入不同的是,xss攻擊是合法的字串,如經過htmlspecialchars()方法實體化後,可以儲存在資料庫中,但是,當存取含有該字串的內容頁面時,就會出現問題,如字串裡邊還有JavaScript,frame程式碼,原來的頁面就會被篡改。
比如你寫個留言本,有人去留言寫<script src="xx"></script><iframe>,這個被顯出來容易掛病毒都很容易,和資料庫無關。
XSS概念
XSS又稱CSS,全稱Cross SiteScript(跨站指令碼攻擊), XSS攻擊類似於SQL隱碼攻擊,是Web程式中常見的漏洞,XSS屬於被動式且用於用戶端的攻擊方式,所以容易被忽略其危害性。其原理是攻擊者向有XSS漏洞的網站中輸入(傳入)惡意的HTML程式碼,當使用者瀏覽該網站時,這段HTML程式碼會自動執行,從而達到攻擊的目的。如,盜取使用者Cookie資訊、破壞頁面結構、重定向到其它網站等。
理論上,只要存在能提供輸入的表單並且沒做安全過濾或過濾不徹底,都有可能存在XSS漏洞。
下面是一些最簡單並且比較常見的惡意字元XSS輸入:
1.XSS 輸入通常包含 JavaScript 指令碼,如彈出惡意警告框:<script>alert("XSS");</script>
2.XSS 輸入也可能是 HTML 程式碼段,譬如:
(1).網頁不停地重新整理 <meta http-equiv="refresh" content="0;">
(2).嵌入其它網站的連結 <iframe src=http://xxxx width=250 height=250></iframe>
除了通過正常途徑輸入XSS攻擊字元外,還可以繞過JavaScript校驗,通過修改請求達到XSS攻擊的目的,如下圖:
了解到XSS攻擊的原理和危害後,其實要預防也不難,下面提供一個簡單的PHP防止XSS攻擊的函數:
除了通過正常途徑輸入XSS攻擊字元外,還可以繞過JavaScript校驗,通過修改請求達到XSS攻擊的目的。
了解到XSS攻擊的原理和危害後,其實要預防也不難,下面提供一個簡單的PHP防止XSS攻擊的函數:
<?PHP /** * @blog http://www.digtime.cn * @param $string * @param $low 安全別級低 */ function clean_xss(&$string, $low = False) { if (! is_array ( $string )) { $string = trim ( $string ); $string = strip_tags ( $string ); $string = htmlspecialchars ( $string ); if ($low) { return True; } $string = str_replace ( array ('"', "", "'", "/", "..", "../", "./", "//" ), '', $string ); $no = '/%0[0-8bcef]/'; $string = preg_replace ( $no, '', $string ); $no = '/%1[0-9a-f]/'; $string = preg_replace ( $no, '', $string ); $no = '/[x00-x08x0Bx0Cx0E-x1Fx7F]+/S'; $string = preg_replace ( $no, '', $string ); return True; } $keys = array_keys ( $string ); foreach ( $keys as $key ) { clean_xss ( $string [$key] ); } } //just a test $str = 'codetc.com<meta http-equiv="refresh" content="0;">'; clean_xss($str); //如果你把這個注釋掉,你就知道xss攻擊的厲害了 echo $str; ?>
避免被XSS:
1.給使用者開放的編輯器儘量過濾掉危險的程式碼
如果是html編輯器,一般的做法是保留大部分程式碼,過濾部分可能存在危險的程式碼,如script, iframe等等
三、PHP MySQL 預處理語句
預處理語句對於防止 MySQL 注入是非常有用的。
預處理語句及系結引數
預處理語句用於執行多個相同的 SQL 語句,並且執行效率更高。
預處理語句的工作原理如下:
預處理:建立 SQL 語句模板並行送到資料庫。預留的值使用引數 "?" 標記 。例如:
INSERT INTO MyGuests (firstname, lastname, email) VALUES(?, ?, ?)
資料庫解析,編譯,對SQL語句模板執行查詢優化,並儲存結果不輸出。
執行:最後,將應用系結的值傳遞給引數("?" 標記),資料庫執行語句。應用可以多次執行語句,如果引數的值不一樣。
相比於直接執行SQL語句,預處理語句有兩個主要優點:
預處理語句大大減少了分析時間,只做了一次查詢(雖然語句多次執行)。
係結引數減少了伺服器頻寬,你只需要傳送查詢的引數,而不是整個語句。
預處理語句針對SQL隱碼攻擊是非常有用的,因為引數值傳送後使用不同的協定,保證了資料的合法性。
PDO預處理機制
可以使用多種方式實現預處理:指的是在系結資料進行執行的時候,可以有多種方式。
預處理語句中為變數
使用陣列指定預處理變數
1、準備預處理語句(傳送給伺服器,讓伺服器準備預處理語句)
PDOStatement PDO::prepare:類似exec將一條SQL語句傳送給Mysql伺服器 //PDO::prepare 能夠自動的準備一個預處理語句,使用者需要準備的只是預處理所要執行的語句 //需求:往學生表裏迴圈插入10條記錄 //PDO的預處理能夠自動的將對應的以:開始的變數給記錄下來,實際傳送給伺服器的是「?」 $sql1 = "insert into pro_student values(null,:s_name,:s_num,:s_gender,:s_age,:c_id)";
2、傳送預處理語句
$stmt = $pdo->prepare($sql1);
3、給預處理系結資料
$arr = array( ':s_name' => '房祖名', ':s_num' => 'itcast0013', ':s_gender' => 0, ':s_age' => 28, ':c_id' => 2 );
4、執行預處理:將要操作的資料傳送給預處理語句,再執行預處理語句
PDOStatement::execute([$array]):陣列用來傳遞對應的引數 $stmt->execute($arr); //執行預處理
PDO預處理原理
PDO的預防sql注入的機制也是類似於使用mysql_real_escape_string 進行跳脫,PDO 有兩種跳脫的機制,第一種是本地跳脫,這種跳脫的方式是使用單位元組字元集(PHP < 5.3.6)來跳脫的(單位元組與多位元組),來對輸入進行跳脫,但是這種跳脫方式有一些隱患。隱患主要是:在PHP版本小於5.3.6的時候,本地跳脫只能轉換單位元組的字元集,大於 5.3.6 的版本會根據 PDO 連線中指定的 charset 來跳脫。
第二種方式是PDO,首先將 sql 語句模板傳送給Mysql Server,隨後將繫結的字元變數再傳送給Mysql server,這裡的跳脫是在Mysql Server做的,它是根據你在連線PDO的時候,在charset裡指定的編碼格式來轉換的。這樣的跳脫方式更健全,同時還可以在又多次重複查詢的業務場景下,通過複用模板,來提高程式的效能。如果要設定Mysql Server 來跳脫的話,就要首先執行:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
原始連結方法:
<?php // PDO的使用 // http://blog.csdn.net/qq635785620/article/details/11284591 $dbh = new PDO('mysql:host=127.0.0.1:3306;dbname=mysql_safe', 'root', '518666'); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->exec('set names utf8'); $title = "我們的愛情"; $content = '你是/誰啊,大幾都"老梁"做做&>women<a>沒' . " 測試列印號'我是單引號'哈哈"; $user_id = 174742; $add_time = date("Y-m-d H:i:s"); $insert_sql = "insert into post_tbl (title, content, user_id, add_time) values (:x_title, :x_content, :x_user_id, :x_add_time)"; $stmt = $dbh->prepare($insert_sql); $stmt->execute(array('x_title'=>$title,':x_content'=> $content, ':x_user_id' => $user_id, ':x_add_time' => $add_time)); echo $dbh->lastinsertid();
可見這次PHP是將SQL模板和變數是分兩次傳送給MySQL的,由MySQL完成變數的跳脫處理,既然變數和SQL模板是分兩次傳送的,那麼就不存在SQL隱碼攻擊的問題了,但需要在DSN中指定charset屬性,如:
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root');
範例:
/** * 插入使用者的Token */ function photo_save_token($user_id, $token) { // 引數判斷 $user_id = (int)$user_id; $token = trim($token); if(empty($token) || empty($user_id)) return false; $sql = "replace into token_db.app_token_tbl ( user_id, token, t_date, last_open_time) values ( :x_user_id, :x_token, :x_t_date, :x_last_open_time)"; sqlSetParam($sql,"x_user_id",$user_id); sqlSetParam($sql,"x_token",$token); sqlSetParam($sql,"x_t_date",date('Y-m-d H:i:s')); sqlSetParam($sql,"x_last_open_time", time()); return mysql_query($sql); }
總結: 當呼叫 prepare() 時,查詢語句已經傳送給了資料庫伺服器,此時只有預留位置 ? 傳送過去,沒有使用者提交的資料;當呼叫到 execute()時,使用者提交過來的值才會傳送給資料庫,他們是分開傳送的,兩者獨立的,SQL攻擊者沒有一點機會。
小結
①、關於sql注入可以使用htmlspecialchars()或addslashes()方法,如果連線mysql,可以用mysql_real_escape_string(),還有在php.ini中設定magic_quotes_gpc開啟自動跳脫的擴充套件。
PHP環境開啟自動跳脫,PHP.INI中檢視
當magic_quotes_gpc=on 時將自動進行跳脫(預設是on),可在程式中用get_magic_quotes_gpc()檢查他的狀態
程式為:
if (get_magic_quotes_gpc()==1){ $name=stripcslashes($_POST["name"]); }else{ $name=$_POST["name"]; }
②、關於xss攻擊可以寫一個去處script,frame等程式碼的方法:
直接用這個函數editor_safe_replace代替htmlspecialchars,既保證安全又能用大部分html程式碼
function editor_safe_replace($content) { $content = trim($content); $tags = array( "'<iframe[^>]*?>.*?</iframe>'is", "'<frame[^>]*?>.*?</frame>'is", "'<script[^>]*?>.*?</script>'is", "'<head[^>]*?>.*?</head>'is", "'<title[^>]*?>.*?</title>'is", "'<meta[^>]*?>'is", "'<link[^>]*?>'is", ); // 1.先過濾掉含有xss攻擊的程式碼 $content = preg_replace($tags, "", $content); // strip_tags過濾掉全部HTML標籤(script,iframe,head,a 等標籤)和上邊的正則方法類似 // $content = strip_tags($content); // 2.入庫時,防止sql注入,轉為HTML實體儲存在資料庫,單雙引號都轉 $content = htmlspecialchars($content, ENT_QUOTES); // 3.替換反斜槓 $content = preg_replace("//", "\", $content); // 4.替換斜槓 $content = preg_replace("///", "/", $content); return $content; }
所以,對於PHP的安全而言,一定要對使用者提交的資料進行過濾校驗處理,即先防止SQL隱碼攻擊,後再進行XSS過濾,這兩個都需要兩手一起抓,且兩手都要硬,否則,你的網站將會存在很大的安全風險。
以上就是php安全問題思考的詳細內容,更多請關注TW511.COM其它相關文章!