思維新建站官網(wǎng):www.inspinovation.cn
文|何掌柜
對于很多 web 應(yīng)用來說,簡單地轉(zhuǎn)義 HTML 是不夠的。 你可能想完全去除任何HTML,或者允許一小部分子集的 HTML 存在。 若是如此,則使用 HTML Purifier 庫。
HTML Purifier 是一個經(jīng)過充分測試但效率比較低的庫。 這就是為什么如果你的需求并不復(fù)雜就應(yīng)使用htmlentities(), 因?yàn)樗男室斓枚唷?/p>
HTML Purifier 相比 strip_tags() 是有優(yōu)勢的, 因?yàn)樗趦艋?HTML 之前會對其校驗(yàn)。 這意味著如果用戶輸入無效 HTML,HTML Purifier 相比 strip_tags() 更能保留 HTML 的原意。 HTML Purifier 高度可定制,允許你為 HTML 的一個子集建立白名單來允許這個 HTML 子集的實(shí)體存在輸出中。
但其缺點(diǎn)就是相當(dāng)?shù)穆?,它要求一些設(shè)置,在一個共享主機(jī)的環(huán)境里可能是不可行的。 其文檔通常也復(fù)雜而不易理解。 以下示例是一個基本的使用配置。 查看文檔閱讀 HTML Purifier 提供的更多更高級的特性。
示例
// Include the HTML Purifier library
require_once('htmlpurifier-4.4.0/HTMLPurifier.auto.php');
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = '
Mua-ha-ha! Twiddling my evil mustache...
';
// Set up the HTML Purifier object with the default configuration.
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
$safeHtml = $purifier->purify($evilHtml);
// $safeHtml is now sanitized. You can output $safeHtml to your users without fear!
?>
陷阱
以錯誤的字符編碼使用 htmlentities() 會造成意想不到的輸出。 在調(diào)用該函數(shù)時(shí)始終確認(rèn)指定了一種字符編碼,并且該編碼與將被凈化的字符串的編碼相匹配。 更多細(xì)節(jié)請查看 UTF-8 一節(jié)。
使用 htmlentities() 時(shí),始終包含 ENT_QUOTES 和字符編碼參數(shù)。 默認(rèn)情況下,htmlentities() 不會對單引號編碼。多愚蠢的默認(rèn)做法!
HTML Purifier 對于復(fù)雜的 HTML 效率極其的低??梢钥紤]設(shè)置一個緩存方案如APC來保存經(jīng)過凈化的結(jié)果以備后用。
因思維新專注于高端網(wǎng)站訂制開發(fā),不僅僅為您建設(shè)網(wǎng)站,還為您做網(wǎng)絡(luò)營銷。
.文件系統(tǒng)安全
php如果具有root權(quán)限,且在腳本中允許用戶刪除文件,那么用戶提交數(shù)據(jù),不進(jìn)行過濾,就非常有可能刪除系統(tǒng)文件
<?php// 從用戶目錄中刪除指定的文件$username = $_POST['user_submitted_name'];$userfile = $_POST['user_submitted_filename'];$homedir = "/home/$username";unlink ("$homedir/$userfile");echo "The file has been deleted!";?>
上面的代碼,假設(shè)用戶提交的$userfile值是 ../etc/,那么/etc目錄就會被刪除
防范文件系統(tǒng)攻擊,策略如下:
只給php有限的權(quán)限
用戶提交上來的變量要監(jiān)測和過濾,不能包含文件路徑等特殊字符
盡量避免使用PHP操作文件(刪除),如果有這方面的需求,那用戶可刪除文件也必須是系統(tǒng)生成的隨機(jī)名稱,不可被用戶控制
2.數(shù)據(jù)庫安全
數(shù)據(jù)庫安全主要防范的是sql injection,即sql注入攻擊,提升數(shù)據(jù)庫安全的策略如下:
不用使用root帳號或者數(shù)據(jù)庫所有者帳號連接數(shù)據(jù)庫,連接數(shù)據(jù)庫限定連接用戶的ip
使用php的pdo擴(kuò)展,有效防止sql注入,除了安全方面的優(yōu)勢,php的pdo擴(kuò)展在性能方面有有很大優(yōu)勢
請參看 http://php.net/manual/en/pdo.prepared-statements.php
對一些敏感信息進(jìn)行加密,常見的比如對密碼進(jìn)行加密
3.用戶數(shù)據(jù)過濾
對用戶數(shù)據(jù)過濾,可以防范XSS和CSRF攻擊
使用白名單(用戶輸入是固定模式)的方式
比如用戶名只能使用數(shù)字字母,那么可以使用函數(shù)ctype_alnum判斷
對用戶輸入使用函數(shù) htmlentities或者h(yuǎn)tmlspecialchars進(jìn)行處理,輸入url不允許傳入非http協(xié)議
用戶身份驗(yàn)證使用令牌 token(csrf)
http://htmlpurifier.org/ HTML Purifier 是開源的防范xss攻擊的有效解決方案,
4.其他安全策略
線上環(huán)境關(guān)閉錯誤報(bào)告(error_reporting,dislay_erros,可在php.ini中配置error_log路徑,記錄錯誤信息,這樣有助于發(fā)現(xiàn)可能的用戶攻擊)
Register Globals,棄用(移除)的特性,不要使用
魔術(shù)引號特性,不要開啟,在PHP-5.4中已經(jīng)被移除
盡量使用PHP的最新版本,最新版本修復(fù)了已知的很多安全漏洞和bug
代碼中嚴(yán)格遵守上述策略,基本能保證代碼不會有太多的安全漏洞,能防范常見攻擊。
如果想要學(xué)習(xí)交流PHP的朋友,可以關(guān)注小編,私信【學(xué)習(xí)交流】手機(jī)用戶可以直接私信,電腦端尚未開放此功能,需要下載app,我已經(jīng)設(shè)置了自動回復(fù),具體后續(xù)會自動回復(fù)各位。
2018 年將至,一般程序員(特別是 Web 開發(fā)程序員)應(yīng)當(dāng)拋棄過去開發(fā)PHP程序的很多不好的習(xí)慣和觀念了。雖然部分人不以為意,但是這確實(shí)是事實(shí)。
這個指南應(yīng)該以重點(diǎn)部分作為 PHP: The Right Way 安全章節(jié)的補(bǔ)充,而不是以一般的 PHP 編程話題。
PHP 版本#
請?jiān)?2018 年使用 PHP 7.2, 并且計(jì)劃 2019 年初切換到 PHP 7.3。
PHP 7.2 已于 2017 年 11 月 30 日發(fā)布。
寫這篇文章的時(shí)候,只有 7.1 和 7.2 版本還在被 PHP 官方積極維護(hù),而 5.6 和 7.0 只在大概1年內(nèi)提供安全補(bǔ)丁更新。
對于其他官方不維護(hù)的 PHP 版本,雖然某些操作系統(tǒng)會提供長期支持和維護(hù),但這其實(shí)通常是有害的。尤其是他們提供安全支持補(bǔ)丁卻沒有版本號,這使得很難解釋系統(tǒng)的安全性(僅僅知道 PHP 版本)。
因此,無論其他供應(yīng)商提出了什么承諾,如果可以,你就應(yīng)該在任何時(shí)候都堅(jiān)決地使用官方提供支持的 PHP 版本。這樣,盡管最終是一個短暫的安全版本,但一個不斷致力于升級的版本,總會讓你收獲一些意外的驚喜。
依賴管理#
人生苦短,我用 Composer
在 PHP 生態(tài)中,Composer 是最先進(jìn)的依賴管理方案。我們推薦 PHP: The Right Way 中關(guān)于依賴管理的完整章節(jié)。
如果你沒有使用 Composer 來管理應(yīng)用的依賴,最終(hopefully later but most likely sooner)會導(dǎo)致應(yīng)用里某個依賴會嚴(yán)重過時(shí),然后老舊版本中的漏洞會被利用于計(jì)算機(jī)犯罪。
重要: 開發(fā)軟件時(shí),時(shí)常記得保持依賴的更新。幸運(yùn)地,這只需一行命令:
composer update
如果你正在使用某些專業(yè)的,需要使用 PHP 擴(kuò)展(C 語言編寫),那你不能使用 Composer 管理,而需要 PECL 。
推薦擴(kuò)展#
不管你正在編寫什么,你總會受益于這些依賴。這是除了大多數(shù) PHP 程序員的推薦(PHPUnit, PHP-CS-Fixer, ...)外的補(bǔ)充。
roave/security-advisories
Roave's security-advisories 使用 Friends of PHP repository 確保你的項(xiàng)目沒有依賴一些已知易受攻擊的依賴。
composer require roave/security-advisories:dev-master
或者,你可以上傳你的composer.lock文件到 Sensio Labs ,作為例行自動化漏洞評估工作流的一部分,以提醒發(fā)現(xiàn)任何過時(shí)的軟件包。
vimeo/psalm
Psalm 是一個幫助你識別代碼里可能存在 bugs 的靜態(tài)分析工具。還有其他很好的靜態(tài)分析工具(例如 Phan 和 PHPStan 都很棒),但當(dāng)你發(fā)現(xiàn)你需要支持 PHP 5,Psalm 將是 PHP 5.4+ 的首選。
使用 Psalm 挺簡單:
如果你是第一次在現(xiàn)有代碼庫運(yùn)行,可能會看到很多紅色錯誤。但除非你在構(gòu)建像 WordPress 那么大的程序,否則努力通過所有測試絕不是艱巨的。
無論使用哪種靜態(tài)分析工具,我們都推薦你能將他加入到持續(xù)集成工作流(Continuous Integration workflow)中,以便在每次更改代碼中運(yùn)行。
HTTPS 和瀏覽器安全#
HTTPS, which should be tested, and security headers .
2018 年,不安全的 HTTP 網(wǎng)站將不再被接受。幸運(yùn)的是,由于 ACME 協(xié)議 和 Let's Encrypt certificate authority,免費(fèi)的 TLS 證書成為了可能。
將 ACME 集成到你的服務(wù)器,小菜一碟。
Caddy: 自動加入。
Apache: 很快作為mod_md可用。在此之前,網(wǎng)上很多高質(zhì)量教程。
Nginx: 相對簡單。
你也許會想,“好,我已經(jīng)有 TLS 證書了,為了網(wǎng)站變得安全和快速,得花些時(shí)間折騰配置信息?!?/p>
不!Mozilla做了件好事情!。你可以根據(jù)網(wǎng)站的目標(biāo)受眾,使用配置生成器生成推薦套件。
如果你希望網(wǎng)站安全,HTTPS ( HTTP over TLS ) 是絕對不能妥協(xié)的。使用 HTTPS 立刻就能消除多種攻擊(中間人攻擊、竊聽、重放攻擊以及若干允許用戶模仿的會話形式的攻擊)。
安全頭#
在服務(wù)器使用 HTTPS 確實(shí)為用戶提供了許多安全性和性能方面的好處,但也還能通過利用某些瀏覽器的安全功能來進(jìn)一步提升安全性。而這大部分會涉及到響應(yīng)內(nèi)容的安全頭。
1、Content-Security-Policy
你需要該 Header ,因?yàn)樗峁┝藢τ跒g覽器是否允許加載內(nèi)部和外部資源的細(xì)化控制,從而為跨域腳本攻擊漏洞提供了有效防御層。
參閱 CSP-Builder,以便快速簡便地部署/管理內(nèi)容安全策略(Content Security Policies)。
為了更加深入的分析, Scott Helme's introduction to Content-Security-Policy headers,會是一個很好的引導(dǎo)。
2、Expect-CT
你需要該 Header ,因?yàn)樗芡ㄟ^強(qiáng)制某些不良行為者將其錯誤證書的證據(jù)頒發(fā)到可公開驗(yàn)證的僅可追加的數(shù)據(jù)結(jié)構(gòu),從而針對流氓/受損的證書頒發(fā)機(jī)構(gòu)增加一層防護(hù)。
優(yōu)先設(shè)置為enforce,max-age=30。只要你有足夠的自信該 Header 不會造成服務(wù)中斷,增加max-age吧。
3、Referrer-Policy
你需要該 Header ,因?yàn)樗试S你控制用戶的行為信息是否泄露給第三方。
同樣地,Scott Helme 提供了一篇關(guān)于Referrer-Policy Header 介紹好文。
除非有理由允許更加寬松的設(shè)置,否則請?jiān)O(shè)置為same-origin或no-referrer。
4、Strict-Transport-Security
你需要該 Header ,因?yàn)樗嬖V瀏覽器通過 HTTPS 而不是不安全的 HTTP ,將 future requests 設(shè)為同源。
在第一次部署時(shí),將其設(shè)置為max-age = 30,然后當(dāng)你確信沒有任何內(nèi)容會中斷時(shí),將此值增加到某個較大的值(例如 31536000)。
5、X-Content-Type-Options
你需要該 Header ,因?yàn)?MIME 類型的混淆可能會導(dǎo)致不可預(yù)知的結(jié)果,包括奇怪的允許 XSS 漏洞的邊緣情況。這最好伴隨著一個標(biāo)準(zhǔn)的 Content-Type Header 。
除非需要默認(rèn)的行為(例如文件的下載),否則請?jiān)O(shè)置為nosniff。
6、X-Frame-Options
你需要該 Header ,因?yàn)樗试S你防止點(diǎn)擊劫持。
設(shè)置為DENY (或者SAMEORIGIN, 但僅僅當(dāng)你使用<frame>元素的時(shí)候)。
7、X-XSS-Protection
你需要該 Header ,因?yàn)樗鼏⒂昧艘恍┠J(rèn)情況下未啟用的瀏覽器反 XSS 功能。
設(shè)置為1; mode=block。
同樣,如果你使用 PHP 的內(nèi)置會話管理功能(建議使用),則可能需要這樣調(diào)用session_start():
這會強(qiáng)制你的應(yīng)用在發(fā)送會話標(biāo)識符時(shí)使用 HTTP-Only 和 Secure 標(biāo)志,從而防止 XSS 攻擊竊取用戶的 Cookie ,并強(qiáng)制它們分別通過 HTTPS 發(fā)送。 我們之前在 2015 年的博客文章中介紹了安全的 PHP 會話。
子資源完整性#
在將來的某個時(shí)候,你也許會使用 CDN 來加載網(wǎng)站的公共 JavaScript/CSS 庫。安全工程師已經(jīng)遇見了這存在一個明顯的風(fēng)險(xiǎn),如果很多網(wǎng)站使用 CDN 提供內(nèi)容,Hack 和替換 CDN(獲得了 CDN 的控制權(quán))就可以注入(惡意)代碼到成千上萬的網(wǎng)站。
查閱子資源完整性吧。
子資源完整性(SRI,Subresource integrity)允許你將希望 CDN 服務(wù)的文件的內(nèi)容進(jìn)行哈希處理。目前實(shí)行的 SRI 只允許使用安全的密碼散列函數(shù),這意味著攻擊者不可能生成與原始文件哈希相同的惡意版本資源。
一個真實(shí)例子: Bootstrap v4-alpha uses SRI in their CDN example snippet
文檔關(guān)系#
Web 開發(fā)人員經(jīng)常在超鏈接上設(shè)置目標(biāo)屬性(例如,target ="_ blank"在新窗口中打開鏈接)。但是,如果你沒有傳遞rel ="noopener"標(biāo)簽,則可以允許目標(biāo)頁面控制當(dāng)前頁面。
不要這樣做:
這會讓http://example.com頁面能控制當(dāng)前頁面。
而應(yīng)該這樣做:
通過這樣在新窗口打開https://example.com,當(dāng)前窗口的控制權(quán)也不會授予可能的惡意第三方。
可以更加深入研究。
開發(fā)安全的 PHP 程序#
如果應(yīng)用程序安全性對你來說是一個新話題,請從應(yīng)用程序安全性簡介開始吧。
大多數(shù)安全專家指出,開發(fā)者可以使用 OWASP Top 10 等資源開始著手。
但是,大多數(shù)常見的漏洞也可以是相同高等級的安全問題(例如代碼和數(shù)據(jù)沒有完全分離、邏輯不嚴(yán)謹(jǐn)和健全、操作環(huán)境不安全或是可破譯的密碼協(xié)議等)。
我們的假設(shè)是,應(yīng)該授予安全新手知道一些更簡單、基礎(chǔ)的安全知識和問題,并如何解決這些問題,應(yīng)該是一個更好的、長遠(yuǎn)的安全工程。
因此,我們避免推薦十大或二十大安全清單。
數(shù)據(jù)庫注入#
避免 PHP 程序存在 SQL 注入。
如果你是自己編寫 SQL 代碼,請確保使用prepared語句,并且從網(wǎng)絡(luò)或文件系統(tǒng)提供的信息都作為參數(shù)傳遞,而不是字符串拼接的形式。此外,確保你沒有使用模擬的prepared語句。
為了達(dá)到好的效果,可以使用 EasyDB 。
不要這樣做:
應(yīng)該這樣做:
還有其他數(shù)據(jù)庫抽象層提供了相同的安全性(EasyDB實(shí)際上是在使用 PDO ,但在實(shí)際的prepare語句前避免了prepared語句模擬)。 只要用戶輸入不會影響查詢的結(jié)構(gòu),就很安全(包括存儲過程)。
文件上傳#
深入:如何安全地允許用戶上傳文件?
接受文件上傳是一個冒險(xiǎn)的提議,但只要采取一些基本的預(yù)防措施,是能保證安全的。也就是說,允許文件直接上傳的話,這些文件可能會被意外的允許執(zhí)行或解釋。上傳的文件應(yīng)該是只讀(read-only)或讀寫(read-write)的,永遠(yuǎn)不應(yīng)該可執(zhí)行(executable)。
如果你的網(wǎng)站根目錄是/var/www/example.com,請不要保存上傳文件在/var/www/example.com/uploaded_files。
而應(yīng)該保存到一個不能直接訪問的目錄(例如:/var/www/example.com-uploaded/),以免意外地將其作為服務(wù)器端腳本執(zhí)行,并獲得執(zhí)行遠(yuǎn)程代碼的后門。
一個更加簡潔的方法是將網(wǎng)站根目錄往下移動一個層級(即:/var/www/example.com/public)。
如何安全地下載這些上傳文件也是一個問題。
直接訪問 SVG 圖像類型時(shí),將在用戶瀏覽器執(zhí)行 JavaScript 代碼。盡管它的MIME類型中的image/前綴具有誤導(dǎo)性,但是這是正確的。
正如前面提及的,MIME 類型嗅探可能導(dǎo)致類型混淆攻擊。請參閱X-Content-Type-Options。
如果你放棄前面關(guān)于如何安全地存儲上傳文件的建議,攻擊者就會通過上傳 .php 或 .phtml 文件,直接在瀏覽器中訪問文件來執(zhí)行任意代碼,從而完全控制服務(wù)器。
跨站腳本#
關(guān)于 PHP 中的跨站腳本攻擊,你想知道的都在這里
同樣地,預(yù)防 XSS 和 SQL 注入是一樣簡單的。我們有簡單而易用的 API 來分離文檔結(jié)構(gòu)(structure of a document)和填充的數(shù)據(jù)。
然而,實(shí)際上還有很多 Web 開發(fā)程序員仍是通過生成一大串 HTML 代碼作為響應(yīng)的形式開發(fā)。并且,這不是 PHP 獨(dú)有的現(xiàn)實(shí),這是所有 Web 開發(fā)程序員都應(yīng)該重視的。
減少 XSS 漏洞不失為一個好方法??傊?,前面談及的瀏覽器安全的章節(jié)就顯得十分相關(guān)了。簡言之:
盡量避免輸出和輸入(Always escape on output, never on input)。如果你把已清洗的數(shù)據(jù)(sanitized data)保存在數(shù)據(jù)庫,然后在其它地方被發(fā)現(xiàn)了 SQL 注入漏洞,攻擊者將通過惡意程序污染這些受信任的已清洗數(shù)據(jù)(trusted-to-be-sanitized record),從而繞開 XSS 保護(hù)。
如果你的框架有一個提供自動上下文過濾的模板引擎,那就使用它吧。這些工作可由框架安全地做到。
echo htmlentities($ string,ENT_QUOTES | ENT_HTML5,'UTF-8') 是一種安全、有效的方法阻止UTF-8編碼的網(wǎng)頁上的所有 XSS 攻擊,但不是任何 HTML 都有效。
如果你的環(huán)境要求你使用 Markdown 而不是 HTML ,那就不要使用 HTML 了。
如果你需要使用原生 HTML(沒有使用模板引擎),參閱第一點(diǎn),并且使用 HTML Purifier 吧。HTML Purifier 不適合轉(zhuǎn)義為 HTML 屬性上下文(HTML attribute context)。
跨站請求偽造#
跨站請求偽造(CSRF)是一種混淆的代理攻擊,通過誘導(dǎo)用戶的瀏覽器代表攻擊者執(zhí)行惡意的 HTTP 請求(使用的是該用戶的權(quán)限)。
這在一般情況下是很容易解決的,只需兩步:
使用 HTTPS 。這是先決條件。沒有 HTTPS 的話,任何保護(hù)措施都是脆弱的,雖然 HTTPS 本身并不防御 CSRF 。
增加基本的 Challenge-response authentication。
為每個表單添加一個隱藏的表單屬性。
填充一個密碼安全的隨機(jī)值(稱為令牌)。
驗(yàn)證是否提供了隱藏的表單屬性,以及是否匹配上期望值。
我們寫了一個名為 Anti-CSRF 的庫,并且:
你可以使每個令牌只能使用一次,以防止重放攻擊。
多個令牌存儲在后端。
一旦令牌獲取完,令牌會循環(huán)使用。
每個令牌可以綁定特定的 URL 。
如果某個令牌泄露了,它不能在不同的上下文使用。
令牌可以綁定特定的 IP 地址。
v2.1 后,令牌可以重復(fù)使用(例如供 Ajax 使用)。
如果你沒有使用防止 CSRF 漏洞的框架,請將 Anti-CSRF 放在一邊。在不久的將來,SameSite cookies將允許我們更簡單地避免CSRF攻擊。
XML 攻擊 (XXE, XPath Injection)#
在處理大量 XML 的應(yīng)用程序中存在兩個主要的漏洞:
XML External Entities (XXE)
XPath 注入
除此之外, XXE 攻擊可用作包含攻擊代碼的本地/遠(yuǎn)程文件的啟動器。
早期版本的 Google Docs 被著名于 XXE ,但除了在很大程度上使用 XML 的商業(yè)應(yīng)用程序之外,基本聞所未聞。
針對 XXE 襲擊的主要緩解措施:
除 XML 文檔外,XPath注入與 SQL 注入非常相似。
幸運(yùn)的是,將用戶輸入傳遞給 XPath 查詢的情況在 PHP 生態(tài)中非常罕見。
而不幸的是,這也意味著 PHP 生態(tài)中不存在可用的最佳避免措施(預(yù)編譯和參數(shù)化 XPath 查詢)。最好的辦法是在任何涉及 XPath 查詢的數(shù)據(jù)上設(shè)置允許使用的字符白名單。
白名單總會比黑名單更安全。
反序列化和 PHP 對象注入#
深入: 在PHP中安全地實(shí)現(xiàn)(反)序列化
如果你將不可信的數(shù)據(jù)傳遞給unserialize(),則通常是這兩個結(jié)果之一:
PHP 對象注入,它能用于啟動 POP 鏈(POP chain)并觸發(fā)其他誤用對象的漏洞。
PHP 解釋器本身的內(nèi)存損壞。
大多數(shù)開發(fā)人員更喜歡使用JSON序列化,這是對其軟件安全狀況的顯著改進(jìn)。但請記住,json_decode()容易受到散列沖突拒絕服務(wù)(Hash-DoS)攻擊。不幸的是,PHP的Hash-DOS問題還沒有得到徹底解決。
從djb33遷移到Siphash,對于字符串輸入,哈希輸出的最高位設(shè)置為 1 ,對于整數(shù)輸入設(shè)置為 0 ,使用CSPRNG提供的請求密鑰,將完全解決這些攻擊。
不幸的是, PHP 團(tuán)隊(duì)還沒有準(zhǔn)備好放棄他們已經(jīng)在 PHP 7 系列中取得的性能提升,所以很難說服他們放棄 djb33 (這是非??斓话踩模?贊成 SipHash (這也是快速的,但不像 djb33 那么快,但更安全)。 如果性能受到重大影響,可能會阻礙未來版本的采用,但也影響了安全性。
因此,最好的辦法是:
使用JSON,因?yàn)樗萿nserialize()更安全。
在任何可能的地方,確保輸入在反序列化之前被認(rèn)證。
對于提供給用戶的數(shù)據(jù),通過一個只有服務(wù)器知道的秘鑰使用sodium_crypto_auth()和sodium_crypto_auth_verify()驗(yàn)證。
對于第三方提供的數(shù)據(jù),讓他們使用sodium_crypto_sign()簽名他們的 JSON 消息,
然后使用sodium_crypto_sign_open()和第三方公鑰驗(yàn)證消息。
如果你需要對傳輸?shù)暮灻M(jìn)行十六進(jìn)制或 Base64 位編碼,也可以使用分離的簽名 API 。
如果你無法驗(yàn)證 JSON 字符串,請嚴(yán)格限制速度并阻止 IP 地址,以減輕重復(fù)的違規(guī)者。
密碼散列#
深入:2016 年,如何安全地保存用戶密碼
安全的密碼存儲曾經(jīng)是一個激烈爭論的話題,但現(xiàn)在實(shí)現(xiàn)起來相當(dāng)微不足道,特別是在 PHP 中:
你甚至不需要知道在后臺使用什么算法,因?yàn)槿绻闶褂米钚掳姹镜?PHP ,你也將使用當(dāng)前最新的技術(shù),用戶的密碼將會自動進(jìn)行升級(只要有新的默認(rèn)算法可用)。
無論你做什么,都不要做 WordPress 所做的事情。
從 PHP 5.5 到 7.2 ,默認(rèn)算法都是 Bcrypt 。在未來,它可能會切換到獲得密碼哈希大賽冠軍的 Argon2 。
如果你以前沒有使用password_* API ,那需要遷移遺留哈希,請確保以這種方式進(jìn)行。很多公司搞錯了, 最有名的是雅虎。 最近,錯誤地實(shí)施傳統(tǒng)哈希升級似乎導(dǎo)致了蘋果的iamroot錯誤。
通用加密#
這是一些我們詳細(xì)寫了的話題:
Using Encryption and Authentication Correctly (2015)
Recommended: Choosing the Right Cryptography Library for your PHP Project: A Guide (2015)
Recommended: You Wouldn't Base64 a Password - Cryptography Decoded (2015)
Cryptographically Secure PHP Development (2017)
Recommended: Libsodium Quick Reference: Similarly-Named Functions and Their Use-Cases (2017)
一般來說,你總是希望使用 Sodium cryptography library(libsodium)進(jìn)行應(yīng)用層加密。如果你需要支持早于 7.2 的 PHP 版本(像 5.2.4),你可以使用sodium_compat,基本上可以假設(shè)你的用戶也是 7.2 。
在特定情況下,由于嚴(yán)格的算法選擇和互操作性,你可能需要不同的庫。如有疑問,請咨詢密碼專家和密碼工程師,了解密碼選擇是否安全(這是我們提供的服務(wù)之一)。
隨機(jī)性#
深入:如何在 PHP 中生成安全的整數(shù)和字符串?
如果你需要隨機(jī)數(shù)字,請使用random_int()。如果你需要隨機(jī)字節(jié)字符串,請使用random_bytes()。不要使用mt_rand(),rand()或uniqid()。
如果你需要從秘密種子(secret seed)生成偽隨機(jī)數(shù)(pseudorandom),請使用SeedSpring,而不是srand()或mt_srand()。
服務(wù)器端 HTTPS 請求#
確保 TLS 證書驗(yàn)證沒有被禁用
隨意使用你已經(jīng)熟悉的任何兼容 PSR-7 的 HTTP 客戶端。 我們喜歡 Guzzle ,有些人喜歡直接使用 cURL 。
無論你最終使用什么,請確保使用的確定性,以確保始終可以擁有最新的 CACert 軟件包,從而允許啟用最嚴(yán)格的 TLS 證書驗(yàn)證設(shè)置并保護(hù)服務(wù)器的出站 HTTPS 請求。
安裝 Certainty 很簡單:
composer require paragonie/certainty:^1
使用 Certainty 也很簡單:
這樣可以保護(hù)你免受網(wǎng)絡(luò)服務(wù)器與集成的任何第三方 API 之間的中間人攻擊。
我們真的需要 Certainty 嗎?
保護(hù)你的系統(tǒng), Certainty 并不是嚴(yán)格的要求。缺少它并不是什么漏洞。但如果沒有 Certainty ,開源軟件必須猜測操作系統(tǒng)的 CACert 軟件包的存在位置,如果猜測錯誤,它往往會失敗并導(dǎo)致可用性問題。從歷史上看,這激勵了許多開發(fā)人員只是禁用證書驗(yàn)證,以便他們的代碼“正常工作”,卻沒有意識到他們只是將應(yīng)用程序變成主動攻擊。 Certainty 通過將 CACert 捆綁在最新的可預(yù)測位置來消除這種激勵。 Certainty 還為希望運(yùn)行自己的內(nèi)部 CA 為企業(yè)提供大量的工具。
誰禁用了證書驗(yàn)證?
流行的內(nèi)容管理系統(tǒng)(WordPress,Magento 等 CMS)的插件/擴(kuò)展開發(fā)者!這是我們試圖在生態(tài)系統(tǒng)層面上解決的一個巨大的問題。 它不是孤立的任何特定的 CMS ,你會發(fā)現(xiàn)這些不安全的插件等都是類似的。
如果使用了類似的 CMS ,請?jiān)诓寮兴阉鰿URLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST,你可能會發(fā)現(xiàn)有幾個將這些值設(shè)置為FALSE。
避免的事情#
不要使用mcrypt。這是一個十多年來沒有開發(fā)出來的密碼學(xué)庫。如果你遵循我們的 PHP 版本建議,這應(yīng)該是一個容易避免的錯誤,因?yàn)閙crypt不再被 PHP 7.2 和更新的版本支持。
配置驅(qū)動的安全建議應(yīng)該大部分地忽略。如果你正在閱讀 PHP 安全性指南,并告訴你更改 php.ini 設(shè)置而不是編寫更好的代碼,那么你可能正在閱讀過時(shí)的建議。關(guān)閉窗口并轉(zhuǎn)到一些和register_globals無關(guān)的文章上吧。
不要使用 JOSE(JWT,JWS,JWE),這是一套互聯(lián)網(wǎng)標(biāo)準(zhǔn),它編纂了一系列容易出錯的密碼設(shè)計(jì)。盡管由于某種原因,被寫入了標(biāo)準(zhǔn),也吸引了很多傳道人。
加密 URL 參數(shù)是公司常用來模糊元數(shù)據(jù)的反模式(例如,我們有多少用戶?)。 它帶來了實(shí)施錯誤的高風(fēng)險(xiǎn),也造成了錯誤的安全感。我們在鏈接的文章中提出了一個更安全的選擇。
除非迫不得已,否則不要提供“我忘記了我的密碼”的功能。
不要諱言:密碼重置功能是一個后門。 有一些方法可以實(shí)施以抵御合理的威脅模型,但高風(fēng)險(xiǎn)用戶應(yīng)該不被考慮。
避免使用 RSA,改用 libsodium 。如果你必須使用 RSA ,請確保指定 OAEP 填充。
如果你不得不使用 PKCS#1 v1.5 填充,那么無論你與哪個集成在一起,幾乎肯定會受到 ROBOT 的影響,請以允許明文泄露和簽名偽造的漏洞將其報(bào)告給相應(yīng)的供應(yīng)商(或 US-CERT )。
專業(yè)用法#
現(xiàn)在你已經(jīng)掌握了在 2018 年及以后構(gòu)建安全 PHP 應(yīng)用程序的基礎(chǔ)知識,接下來我們來看一些更專業(yè)的用法。
可搜索的加密#
深入:使用PHP和SQL構(gòu)建可搜索的加密數(shù)據(jù)庫
可搜索的加密數(shù)據(jù)庫是可取的,但被廣泛認(rèn)為是不太可能實(shí)現(xiàn)的。上面鏈接的博客文章試圖通過改進(jìn)我們解決方案來實(shí)現(xiàn),但本質(zhì)上是這樣的:
設(shè)計(jì)你的架構(gòu),以便數(shù)據(jù)庫(database compromise)不會讓攻擊者訪問你的加密密鑰。
用一個密鑰加密數(shù)據(jù)。
基于 HMAC 或具有靜態(tài)鹽的安全 KDF (secure KDF with a static salt)創(chuàng)建多個索引(具有自己獨(dú)特的密鑰)
可選:截?cái)嗖襟E3的輸出,將其用作布隆過濾器(Bloom filter)
在 SELECT 查詢中使用步驟3或4的輸出
解密結(jié)果。
在這個過程中的任何一步,你都可以根據(jù)實(shí)際使用情況進(jìn)行不同的權(quán)衡。
沒有 Side-Channels 的基于令牌的身份驗(yàn)證#
深入: Split Tokens: Token-Based Authentication Protocols without Side-Channels
說到數(shù)據(jù)庫(上一節(jié)),你是否知道 SELECT 查詢理論上可能是定時(shí)信息泄漏的來源?
簡單的緩解措施:
把你的認(rèn)證令牌分為兩半
一半在 SELECT 查詢中使用
后一半在恒定的時(shí)間(constant-time)驗(yàn)證
可以選擇將后半部分的散列存儲在數(shù)據(jù)庫中。這對于只能使用一次的令牌是有意義的,例如 密碼重置或“在此計(jì)算機(jī)上記住我”的令牌
即使可以使用定時(shí)泄漏來竊取一半的令牌,剩下的也需要暴力破解才能成功。
開發(fā)安全的API#
深入: Hardening Your PHP-Powered APIs with Sapient
我們寫了 SAPIENT (the Secure API ENgineering Toolkit),讓服務(wù)器到服務(wù)器驗(yàn)證的消息傳遞變得簡單易行。除了 HTTPS 提供的安全性之外,Sapient允許你使用共享密鑰或公鑰來加密和驗(yàn)證消息。 這使得即使存在中間攻擊者,并設(shè)有流氓證書頒發(fā)機(jī)構(gòu),你也可以使用Ed25519對 API 請求和響應(yīng)進(jìn)行身份驗(yàn)證,或者將消息加密到只能由接收方服務(wù)器的密鑰解密的目標(biāo)服務(wù)器。 由于每個 HTTP 消息體都通過安全密碼進(jìn)行身份驗(yàn)證,所以可以安全地使用它來代替stateful token juggling protocols(例如 OAuth)。但是,在密碼學(xué)方面,在做任何不規(guī)范的事情之前,總要確保他們的實(shí)現(xiàn)是由專家研究的。
所有Sapient使用的密碼算法都由Sodium cryptography library提供。
進(jìn)一步閱讀:
Sapient Documentation
Sapient Tutorial
Sapient Specification
Paragon Initiative Enterprises已經(jīng)在其許多產(chǎn)品(包括許多開源軟件項(xiàng)目)中使用了Sapient,
并將繼續(xù)添加軟件項(xiàng)目到Sapient用戶群中。
使用Chronicle記錄安全事件#
深入: Chronicle Will Make You Question the Need for Blockchain Technology
Chronicle是一個基于散列鏈數(shù)據(jù)結(jié)構(gòu)的僅追加密碼分類賬(append-only cryptographic ledger),具有很多吸引公司“區(qū)塊鏈”技術(shù)的屬性,而不會過分矯枉過正。
除了僅追加密碼分類賬(append-only cryptographic ledger)這個具有創(chuàng)造性的用例之外,Chronicle集成到SIEM中時(shí),也可以十分有亮點(diǎn),因?yàn)槟憧梢詫踩P(guān)鍵事件發(fā)送到私人Chronicle中,并且它們是不能被改變的。
如果你的Chronicle設(shè)置為將其摘要散列交叉簽名到其他Chronicle實(shí)例,或者如果有其他實(shí)例配置為復(fù)制你的Chronicle內(nèi)容,攻擊者就很難篡改你的安全事件日志。
在Chronicle的幫助下,你可以獲得區(qū)塊鏈所承諾的彈性特性(resilience),而沒有任何隱私,性能或可伸縮性問題。
要將數(shù)據(jù)發(fā)布到本地Chronicle,你可以使用任何與Sapient-compatible API,但最簡單的解決方案稱為Quill。
一些聰明的讀者可能注意到我們引用了很多我們自己的工作,包括博客文章和開源軟件。(當(dāng)然也不僅僅引用了我們自己的工作)
這絕不是偶然的。
自從我們在 2015 年初成立以來,一直在編寫安全庫并參與提高 PHP 生態(tài)系統(tǒng)安全性的工作。我們已經(jīng)涉足了很多領(lǐng)域,而且我們的安全工程師(他們最近推動了更安全的加密技術(shù)加入 PHP 核心,就在最近的 PHP 7.2 中)自我擔(dān)保地說,并不擅長自我炒作,或是對已經(jīng)做過的工作持續(xù)熱情。但你很可能沒有聽說我們多年來開發(fā)的工具或庫。對于這個,深感抱歉。
不論如何,我們也不可能成為各方面的先行者,所以我們盡可能地選擇與重視公共利益而不是貪圖小利的行業(yè)專家工作。
這也是為什么瀏覽器安全的許多章節(jié)都參考了 Scott Helme 和他公司的工作,他們在為開發(fā)人員提供這些新的安全功能方面具有可訪問性和可理解性。
本指南當(dāng)然不會是詳盡的。編寫不安全代碼的方法幾乎和編寫代碼的方法一樣多。 安全是一種心態(tài),而不是目的地。隨著上面所寫的一切,以及后面涉及的資源,我們希望這將有助于全世界的開發(fā)人員,從今天開始用 PHP 編寫安全的軟件。
資源#
如果你已經(jīng)按照本頁上的所有內(nèi)容進(jìn)行了操作,并且需要更多內(nèi)容,則可能會對我們策劃的閱讀列表感興趣,以便學(xué)習(xí)應(yīng)用程序安全性。
如果你認(rèn)為自己編寫的代碼足夠安全,并希望我們從安全工程師的角度對其進(jìn)行評判,這也是我們?yōu)榭蛻籼峁┑姆?wù)。
你如果為一家要進(jìn)行合規(guī)性測試(PCI-DSS,ISO 27001等)的公司工作,可能還想聘請我們公司來審核你的源代碼。我們的流程比其他安全咨詢公司更適合開發(fā)者。
接下來是 PHP 和信息安全社區(qū)提供的資源列表,這些資源幫助互聯(lián)網(wǎng)更加安全。
PHP: The Right Way:現(xiàn)代 PHP 開發(fā)的實(shí)用指南,免費(fèi)在線。
Mozilla's SSL Config Generator
Let's Encrypt:證書頒發(fā)機(jī)構(gòu),通過提供免費(fèi) TLS 證書,為創(chuàng)建更安全的 Internet 做了很多。
Qualys SSL Labs:為 TLS 配置提供了一個快速而簡單的測試套件。幾乎每個人都使用這個來解決他們的密碼組和證書問題,理由很充分:It does its job well.
Security Headers:可以檢驗(yàn)?zāi)愕木W(wǎng)站在使用瀏覽器安全功能來保護(hù)用戶方面的表現(xiàn)如何。
Report-URI:一個很好的免費(fèi)資源,提供監(jiān)控 CSP/HPKP 等安全策略的實(shí)時(shí)安全報(bào)告服務(wù)。他們給你一個 Report-URI,你可以傳遞給你的用戶的瀏覽器,如果有什么事情發(fā)生或有人發(fā)現(xiàn) XSS 攻擊媒介,他們會投訴Report-URI。 Report-URI 會匯總這些錯誤,并允許你更好地對這些報(bào)告進(jìn)行疑難解答和分類。
PHP Security Advent Calenda:RIPSTech旗下的團(tuán)隊(duì)負(fù)責(zé)。
Snuffleupagus:一個面向安全的 PHP 模塊(Suhosin的精神繼承者,似乎在很大程度上會被放棄)
PHP Delusions:一個致力于更好地使用 PHP 的網(wǎng)站。大部分的口吻是非常有見地的,作者對技術(shù)的準(zhǔn)確性和清晰度的奉獻(xiàn)使得值得一讀,特別是對于那些不太喜歡 PDO 功能的人來說。
Have I Been Pwned?:幫助用戶發(fā)現(xiàn)他們的數(shù)據(jù)是否屬于過時(shí)數(shù)據(jù)泄露。
原文地址:The 2018 Guide to Building Secure PHP Software - P.I.E. Staff
最早是在社區(qū)里帖子 - The 2018 Guide to Building Secure PHP Software 看到,一位同學(xué)只發(fā)了原鏈接,由于是全英,文章也比較長,就沒有深讀,但可以知道這是一篇很好的文章,值得學(xué)習(xí),這幾天花了時(shí)間翻譯了全文。
為避免歧義,部分專業(yè)名詞和語句保留了原文。翻譯過程借助了 Google 和 Google 翻譯,本人英文和相關(guān)專業(yè)水平有限,如有錯誤感謝指出修正。
本文轉(zhuǎn)載自互聯(lián)網(wǎng),如侵犯了你的權(quán)益,請立即聯(lián)系告知,謝謝!
原文地址:
https://laravel-china.org/articles/7235/2018-php-application-security-design
*請認(rèn)真填寫需求信息,我們會在24小時(shí)內(nèi)與您取得聯(lián)系。