1. SQL 注入
創(chuàng)新互聯(lián)是一家專業(yè)從事網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)的網(wǎng)絡(luò)公司。作為專業(yè)網(wǎng)站建設(shè)公司,創(chuàng)新互聯(lián)依托的技術(shù)實(shí)力、以及多年的網(wǎng)站運(yùn)營經(jīng)驗(yàn),為您提供專業(yè)的成都網(wǎng)站建設(shè)、成都全網(wǎng)營銷及網(wǎng)站設(shè)計(jì)開發(fā)服務(wù)!
SQL 注入是對(duì)您網(wǎng)站最大的威脅之一,如果您的數(shù)據(jù)庫受到別人的 SQL 注入的攻擊的話,別人可以轉(zhuǎn)出你的數(shù)據(jù)庫,也許還會(huì)產(chǎn)生更嚴(yán)重的后果。
網(wǎng)站要從數(shù)據(jù)庫中獲取動(dòng)態(tài)數(shù)據(jù),就必須執(zhí)行 SQL 語句,舉例如下:
<?php $username = $_GET['username']; $query = "SELECT * FROM users WHERE username = '$username'";
攻擊者控制通過 GET 和 POST 發(fā)送的查詢(或者例如 UA 的一些其他查詢)。一般情況下,你希望查詢戶名為「 peter 」的用戶產(chǎn)生的 SQL 語句如下:
SELECT * FROM users WHERE username = 'peter'
但是,攻擊者發(fā)送了特定的用戶名參數(shù),例如:' OR '1'='1
這就會(huì)導(dǎo)致 SQL 語句變成這樣:
SELECT * FROM users WHERE username = 'peter' OR '1' = '1'
這樣,他就能在不需要密碼的情況下導(dǎo)出你的整個(gè)用戶表的數(shù)據(jù)了。
那么,我們?nèi)绾畏乐惯@類事故的發(fā)生呢?主流的解決方法有兩種。轉(zhuǎn)義用戶輸入的數(shù)據(jù)或者使用封裝好的語句。轉(zhuǎn)義的方法是封裝好一個(gè)函數(shù),用來對(duì)用戶提交的數(shù)據(jù)進(jìn)行過濾,去掉有害的標(biāo)簽。但是,我不太推薦使用這個(gè)方法,因?yàn)楸容^容易忘記在每個(gè)地方都做此處理。
下面,我來介紹如何使用 PDO 執(zhí)行封裝好的語句( mysqi 也一樣):
$username = $_GET['username']; $query = $pdo->prepare('SELECT * FROM users WHERE username = :username'); $query->execute(['username' => $username]); $data = $query->fetch();
動(dòng)態(tài)數(shù)據(jù)的每個(gè)部分都以:做前綴。然后將所有參數(shù)作為數(shù)組傳遞給執(zhí)行函數(shù),看起來就像 PDO 為你轉(zhuǎn)義了有害數(shù)據(jù)一樣。
幾乎所有的數(shù)據(jù)庫驅(qū)動(dòng)程序都支持封裝好的語句,沒有理由不使用它們!養(yǎng)成使用他們的習(xí)慣,以后就不會(huì)忘記了。
2. XSS
XSS 又叫 CSS (Cross Site Script) ,跨站腳本攻擊。它指的是惡意攻擊者往 Web 頁面里插入惡意 html 代碼,當(dāng)用戶瀏覽該頁之時(shí),嵌入其中 Web 里面的 html 代碼會(huì)被執(zhí)行,從而達(dá)到惡意攻擊用戶的特殊目的。
下面以一個(gè)搜索頁面為例子:
<body> <?php $searchQuery = $_GET['q']; /* some search magic here */ ?> <h2>You searched for: <?php echo $searchQuery; ?></h2> <p>We found: Absolutely nothing because this is a demo</p> </body>
因?yàn)槲覀儼延脩舻膬?nèi)容直接打印出來,不經(jīng)過任何過濾,非法用戶可以拼接 URL:
search.php?q=%3Cscript%3Ealert(1)%3B%3C%2Fscript%3E
PHP 渲染出來的內(nèi)容如下,可以看到 Javascript 代碼會(huì)被直接執(zhí)行:
<body> <h2>You searched for: <script>alert(1);</script></h2> <p>We found: Absolutely nothing because this is a demo</p> </body>
問:JS 代碼被執(zhí)行有什么大不了的?
Javascript 可以:
● 偷走你用戶瀏覽器里的 Cookie;
● 通過瀏覽器的記住密碼功能獲取到你的站點(diǎn)登錄賬號(hào)和密碼;
● 盜取用戶的機(jī)密信息;
● 你的用戶在站點(diǎn)上能做到的事情,有了 JS 權(quán)限執(zhí)行權(quán)限就都能做,也就是說 A 用戶可以模擬成為任何用戶;
● 在你的網(wǎng)頁中嵌入惡意代碼;
問:如何防范此問題呢?
好消息是比較先進(jìn)的瀏覽器現(xiàn)在已經(jīng)具備了一些基礎(chǔ)的 XSS 防范功能,不過請(qǐng)不要依賴與此。
正確的做法是堅(jiān)決不要相信用戶的任何輸入,并過濾掉輸入中的所有特殊字符。這樣就能消滅絕大部分的 XSS 攻擊:
<?php $searchQuery = htmlentities($searchQuery, ENT_QUOTES);
或者你可以使用模板引擎 Twig ,一般的模板引擎都會(huì)默認(rèn)為輸出加上 htmlentities 防范。
如果你保持了用戶的輸入內(nèi)容,在輸出時(shí)也要特別注意,在以下的例子中,我們?cè)试S用戶填寫自己的博客鏈接:
<body> <a href="<?php echo $homepageUrl; ?>">Visit Users homepage</a> </body>
以上代碼可能第一眼看不出來有問題,但是假設(shè)用戶填入以下內(nèi)容:
#" onclick="alert(1)
會(huì)被渲染為:
<body> <a href="#" onclick="alert(1)">Visit Users homepage</a> </body>
永遠(yuǎn)永遠(yuǎn)不要相信用戶輸入的數(shù)據(jù),或者,永遠(yuǎn)都假設(shè)用戶的內(nèi)容是有攻擊性的,態(tài)度端正了,然后小心地處理好每一次的用戶輸入和輸出。
另一個(gè)控制 XSS 攻擊的方法是提供一個(gè) CSP Meta 標(biāo)簽,或者標(biāo)頭信息,更多詳情請(qǐng)見:
https://phpdelusions.net/pdo/sql_injection_example
另外設(shè)置 Cookie 時(shí),如果無需 JS 讀取的話,請(qǐng)必須設(shè)置為 "HTTP ONLY"。這個(gè)設(shè)置可以令 JavaScript 無法讀取 PHP 端種的 Cookie。
3. XSRF/CSRF
CSRF 是跨站請(qǐng)求偽造的縮寫,它是攻擊者通過一些技術(shù)手段欺騙用戶去訪問曾經(jīng)認(rèn)證過的網(wǎng)站并運(yùn)行一些操作。
雖然此處展示的例子是 GET 請(qǐng)求,但只是相較于 POST 更容易理解,并非防護(hù)手段,兩者都不是私密的 Cookies 或者多步表單。
假如你有一個(gè)允許用戶刪除賬戶的頁面,如下所示:
<?php //delete-account.php $confirm = $_GET['confirm']; if($confirm === 'yes') { //goodbye }
攻擊者可以在他的站點(diǎn)上構(gòu)建一個(gè)觸發(fā)這個(gè) URL 的表單(同樣適用于 POST 的表單),或者將 URL 加載為圖片誘惑用戶點(diǎn)擊:
<img src="https://example.com/delete-account.php?confirm=yes" />
用戶一旦觸發(fā),就會(huì)執(zhí)行刪除賬戶的指令,眨眼你的賬戶就消失了。
防御這樣的攻擊比防御 XSS 與 SQL 注入更復(fù)雜一些。
最常用的防御方法是生成一個(gè) CSRF 令牌加密安全字符串,一般稱其為 Token,并將 Token 存儲(chǔ)于 Cookie 或者 Session 中。
每次你在網(wǎng)頁構(gòu)造表單時(shí),將 Token 令牌放在表單中的隱藏字段,表單請(qǐng)求服務(wù)器以后會(huì)根據(jù)用戶的 Cookie 或者 Session 里的 Token 令牌比對(duì),校驗(yàn)成功才給予通過。
由于攻擊者無法知道 Token 令牌的內(nèi)容(每個(gè)表單的 Token 令牌都是隨機(jī)的),因此無法冒充用戶。
<?php /* 你嵌入表單的頁面 */ ?> <form action="/delete-account.php" method="post"> <input type="hidden" name="csrf" value="<?php echo $_SESSION['csrf']; ?>"> <input type="hidden" name="confirm" value="yes" /> <input type="submit" value="Delete my account" /> </form> ## <?php //delete-account.php $confirm = $_POST['confirm']; $csrf = $_POST['csrf']; $knownGoodToken = $_SESSION['csrf']; if($csrf !== $knownGoodToken) { die('Invalid request'); } if($confirm === 'yes') { //goodbye }
請(qǐng)注意,這是個(gè)非常簡(jiǎn)單的示例,你可以加入更多的代碼。如果你使用的是像 Symfony 這樣的 PHP 框架,那么自帶了 CSRF 令牌的功能。
你還可以查看關(guān)于 OWASP 更詳細(xì)的問題和更多防御機(jī)制的文章:
https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.md
4. 不充分的密碼哈希
大部分的 Web 應(yīng)用需要保存用戶的認(rèn)證信息。如果密碼哈希做的足夠好,在你的網(wǎng)站被攻破時(shí),即可保護(hù)用戶的密碼不被非法讀取。
首先,最不應(yīng)該做的事情,就是把用戶密碼明文儲(chǔ)存起來。大部分的用戶會(huì)在多個(gè)網(wǎng)站上使用同一個(gè)密碼,這是不可改變的事實(shí)。當(dāng)你的網(wǎng)站被攻破,意味著用戶的其他網(wǎng)站的賬號(hào)也被攻破了。
其次,你不應(yīng)該使用簡(jiǎn)單的哈希算法,事實(shí)上所有沒有專門為密碼哈希優(yōu)化的算法都不應(yīng)使用。哈希算法如 MD5 或者 SHA 設(shè)計(jì)初衷就是執(zhí)行起來非???。這不是你需要的,密碼哈希的終極目標(biāo)就是讓黑客花費(fèi)無窮盡的時(shí)間和精力都無法破解出來密碼。
另外一個(gè)比較重要的點(diǎn)是你應(yīng)該為密碼哈希加鹽(Salt),加鹽處理避免了兩個(gè)同樣的密碼會(huì)產(chǎn)生同樣哈希的問題。
以下使用 MD5 來做例子,所以請(qǐng)千萬不要使用 MD5 來哈希你的密碼, MD5 是不安全的。
假如我們的用戶 user1 和 user315 都有相同的密碼 ilovecats123,這個(gè)密碼雖然看起來是強(qiáng)密碼,有字母有數(shù)字,但是在數(shù)據(jù)庫里,兩個(gè)用戶的密碼哈希數(shù)據(jù)將會(huì)是相同的:5e2b4d823db9d044ecd5e084b6d33ea5 。
如果一個(gè)如果黑客拿下了你的網(wǎng)站,獲取到了這些哈希數(shù)據(jù),他將不需要去暴力破解用戶 user315 的密碼。我們要盡量讓他花大精力來破解你的密碼,所以我們對(duì)數(shù)據(jù)進(jìn)行加鹽處理:
<?php //warning: !!這是一個(gè)很不安全的密碼哈希例子,請(qǐng)不要使用!! $password = 'cat123'; $salt = random_bytes(20); $hash = md5($password . $salt);
最后在保存你的唯一密碼哈希數(shù)據(jù)時(shí),請(qǐng)不要忘記連 $salt 也已經(jīng)保存,否則你將無法驗(yàn)證用戶。
在當(dāng)下,最好的密碼哈希選項(xiàng)是 bcrypt,這是專門為哈希密碼而設(shè)計(jì)的哈希算法,同時(shí)這套哈希算法里還允許你配置一些參數(shù)來加大破解的難度。
新版的 PHP 中也自帶了安全的密碼哈希函數(shù) password_hash
,此函數(shù)已經(jīng)包含了加鹽處理。對(duì)應(yīng)的密碼驗(yàn)證函數(shù)為 password_verify
用來檢測(cè)密碼是否正確。password_verify
還可有效防止 時(shí)序攻擊.
以下是使用的例子:
<?php //user signup $password = $_POST['password']; $hashedPassword = password_hash($password, PASSWORD_DEFAULT); //login $password = $_POST['password']; $hash = '1234'; //load this value from your db if(password_verify($password, $hash)) { echo 'Password is valid!'; } else { echo 'Invalid password.'; }
需要澄清的一點(diǎn)是:密碼哈希并不是密碼加密。哈希(Hash)是將目標(biāo)文本轉(zhuǎn)換成具有相同長(zhǎng)度的、不可逆的雜湊字符串(或叫做消息摘要),而加密(Encrypt)是將目標(biāo)文本轉(zhuǎn)換成具有不同長(zhǎng)度的、可逆的密文。顯然他們之間最大的區(qū)別是可逆性,在儲(chǔ)存密碼時(shí),我們要的就是哈希這種不可逆的屬性。
5. LFI
LFI (本地文件包含) 是一個(gè)用戶未經(jīng)驗(yàn)證從磁盤讀取文件的漏洞。
我經(jīng)常遇到編程不規(guī)范的路由代碼示例,它們不驗(yàn)證過濾用戶的輸入。我們用以下文件為例,將它要渲染的模板文件用 GET 請(qǐng)求加載。
<body> <?php $page = $_GET['page']; if(!$page) { $page = 'main.php'; } include($page); ?> </body>
由于 Include 可以加載任何文件,不僅僅是 PHP,攻擊者可以將系統(tǒng)上的任何文件作為包含目標(biāo)傳遞。
index.php?page=../../etc/passwd
這將導(dǎo)致 /etc/passwd 文件被讀取并展示在瀏覽器上。
要防御此類攻擊,你必須仔細(xì)考慮允許用戶輸入的類型,并刪除可能有害的字符,如輸入字符中的 “.” “/” “\”。
如果你真的想使用像這樣的路由系統(tǒng)(我不建議以任何方式),你可以自動(dòng)附加 PHP 擴(kuò)展,刪除任何非 [a-zA-Z0-9-_] 的字符,并指定從專用的模板文件夾中加載,以免被包含任何非模板文件。
我在不同的開發(fā)文檔中,多次看到造成此類漏洞的 PHP 代碼。從一開始就要有清晰的設(shè)計(jì)思路,允許所需要包含的文件類型,并刪除掉多余的內(nèi)容。你還可以構(gòu)造要讀取文件的絕對(duì)路徑,并驗(yàn)證文件是否存在來作為保護(hù),而不是任何位置都給予讀取。
6. 中間人攻擊
MITM (中間人) 攻擊不是針對(duì)服務(wù)器直接攻擊,而是針對(duì)用戶進(jìn)行,攻擊者作為中間人欺騙服務(wù)器他是用戶,欺騙用戶他是服務(wù)器,從而來攔截用戶與網(wǎng)站的流量,并從中注入惡意內(nèi)容或者讀取私密信息,通常發(fā)生在公共 WiFi 網(wǎng)絡(luò)中,也有可能發(fā)生在其他流量通過的地方,例如 ISP 運(yùn)營商。
對(duì)此的唯一防御是使用 HTTPS,使用 HTTPS 可以將你的連接加密,并且無法讀取或者篡改流量。你可以從 Let's Encrypt 獲取免費(fèi)的 SSL 證書,或從其他供應(yīng)商處購買,這里不詳細(xì)介紹如何正確配置 WEB 服務(wù)器,因?yàn)檫@與應(yīng)用程序安全性無關(guān),且在很大程度上取決于你的設(shè)置。
你還可以采取一些措施使 HTTPS 更安全,在 WEB 服務(wù)器配置加上 Strict-Transport-Security 標(biāo)示頭,此頭部信息告訴瀏覽器,你的網(wǎng)站始終通過 HTTPS 訪問,如果未通過 HTTPS 將返回錯(cuò)誤報(bào)告提示瀏覽器不應(yīng)顯示該頁面。
然而,這里有個(gè)明顯的問題,如果瀏覽器之前從未訪問過你的網(wǎng)站,則無法知道你使用此標(biāo)示頭,這時(shí)候就需要用到 Hstspreload。
可以在此注冊(cè)你的網(wǎng)站:
https://hstspreload.org/
你在此處提交的所有網(wǎng)站都將被標(biāo)記為僅 HTTPS,并硬編碼到 Google Chrome、FireFox、Opera、Safari、IE11 和 Edge 的源代碼中。
你還可以在 DNS 配置中添加 Certification Authority Authorization (CAA) record
,可以僅允許一個(gè)證書頒發(fā)機(jī)構(gòu)(例如: Let's encrypt)發(fā)布你的域名證書,這進(jìn)一步提高了用戶的安全性。
7. 命令注入
這可能是服務(wù)器遇到的最嚴(yán)重的攻擊,命令注入的目標(biāo)是欺騙服務(wù)器執(zhí)行任意 Shell 命令
你如果使用 shell_exec 或是 exec 函數(shù)。讓我們做一個(gè)小例子,允許用戶簡(jiǎn)單的從服務(wù)器 Ping 不同的主機(jī)。
<?php $targetIp = $_GET['ip']; $output = shell_exec("ping -c 5 $targetIp");
輸出將包括對(duì)目標(biāo)主機(jī) Ping 5 次。除非采用 sh 命令執(zhí)行 Shell 腳本,否則攻擊者可以執(zhí)行想要的任何操作。
ping.php?ip=8.8.8.8;ls -l /etc
Shell 將執(zhí)行 Ping 和由攻擊者拼接的第二個(gè)命令,這顯然是非常危險(xiǎn)的。
感謝 PHP 提供了一個(gè)函數(shù)來轉(zhuǎn)義 Shell 參數(shù)。
escapeshellarg 轉(zhuǎn)義用戶的輸入并將其封裝成單引號(hào)。
<?php $targetIp = escapeshellarg($_GET['ip']); $output = shell_exec("ping -c 5 $targetIp");
現(xiàn)在你的命令應(yīng)該是相當(dāng)安全的,就個(gè)人而言,我仍然避免使用 PHP 調(diào)用外部命令,但這完全取決于你自己的喜好。
另外,我建議進(jìn)一步驗(yàn)證用戶輸入是否符合你期望的形式。
8. XXE
XXE (XML 外部實(shí)體) 是一種應(yīng)用程序使用配置不正確的 XML 解析器解析外部 XML 時(shí),導(dǎo)致的本地文件包含攻擊,甚至可以遠(yuǎn)程代碼執(zhí)行。
XML 有一個(gè)鮮為人知的特性,它允許文檔作者將遠(yuǎn)程和本地文件作為實(shí)體包含在其 XML 文件中。
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY passwd SYSTEM "file:///etc/passwd" >]> <foo>&passwd;</foo>
就像這樣, /etc/passwd 文件內(nèi)容被轉(zhuǎn)儲(chǔ)到 XML 文件中。
如果你使用 libxml 可以調(diào)用 libxml_disable_entity_loader
來保護(hù)自己免受此類攻擊。使用前請(qǐng)仔細(xì)檢查 XML 庫的默認(rèn)配置,以確保配置成功。
9. 在生產(chǎn)環(huán)境中不正確的錯(cuò)誤報(bào)告暴露敏感數(shù)據(jù)
如果你不小心,可能會(huì)在生產(chǎn)環(huán)境中因?yàn)椴徽_的錯(cuò)誤報(bào)告泄露了敏感信息,例如:文件夾結(jié)構(gòu)、數(shù)據(jù)庫結(jié)構(gòu)、連接信息與用戶信息。
你是不希望用戶看到這個(gè)的吧?
一般根據(jù)你使用的框架或者 CMS ,配置方法會(huì)有不同的變化。通常框架具有允許你將站點(diǎn)更改為某種生產(chǎn)環(huán)境的設(shè)置。這樣會(huì)將所有用戶可見的錯(cuò)誤消息重定向到日志文件中,并向用戶顯示非描述性的 500 錯(cuò)誤,同時(shí)允許你根據(jù)錯(cuò)誤代碼檢查。
但是你應(yīng)該根據(jù)你的 PHP 環(huán)境設(shè)置: error_reporting
與 display_errors
.
10. 配置文件
PHP配置文件下的Register Globals
如果設(shè)為on, 會(huì)自動(dòng)將表單提交的參數(shù)設(shè)為全局變量, 也就是無需手動(dòng)聲明變量, 自動(dòng)將提交的數(shù)組KEY作為變量名, VALUE作為變量值, 這樣存在的隱患是用戶如果知道某個(gè)關(guān)鍵變量名的作用, 這個(gè)變量就可被這個(gè)用戶操控, 所以, 最好是設(shè)為OFF.
以上就是10 個(gè) PHP 常見安全問題的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注創(chuàng)新互聯(lián)其它相關(guān)文章!
本文題目:PHP中常見的安全問題
分享鏈接:http://aaarwkj.com/article34/igcspe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、網(wǎng)站營銷、標(biāo)簽優(yōu)化、動(dòng)態(tài)網(wǎng)站、靜態(tài)網(wǎng)站、品牌網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)