2020 PHP安全指南

2019 年,大多數的科技工做者 — 尤爲是 Web 開發者 — 必須擯棄掉關於開發安全 PHP 應用的老一套。這對那些不相信可以開發出安全的 PHP 應用的人來講尤爲重要.javascript

這篇指南應該做爲 PHP: The Right Way 這本電子書強調安所有分的補充,而不是做爲代碼風格同樣的普通主題.php

PHP 版本css

長話短說::除非你沒有辦法, 2018 年你在最好使用 PHP 7.2 , 同時在 2019 年早些時候計劃切換到 7.3。

PHP 7.2 已經於 2017 年 11 月 30 號發佈.html

在撰寫本文時,只有 PHP 7.1 和 7.2 會獲得了 PHP 語言開發人員的積極支持,而 PHP 5.6 和 7.0 只會在大約一年的時間內得到安全補丁。java

雖然一些操做系統爲不受支持的 PHP 版本提供長期支持,可是這種作法廣泛被認爲是有害的。特別在於,他們會在不升級版本號的狀況下提供安全補丁,這個壞習慣會使得僅經過 PHP 版原本判斷系統的安全性變得很是困難。laravel

綜上,不管其餘供應商作出什麼樣的承諾,只要你可以作到,都應該在任什麼時候間內只運行得到積極支的 PHP 版本。這樣,即便使用了一段時間的安全版本,持續不斷的升級工做也會讓你的生活免於不愉快的意外。git

依賴管理github

簡而言之:使用 Composer .

Composer 是對於 PHP 生態系統最早進的依賴管理方案, 咱們強烈推薦的 PHP: The Right Way 裏有專門一整節用於如何開始使用 Composer .web

若是你不使用 Composer 來管理你的依賴項,你最終會 (但願延遲但可能事情很快發生) 出現這樣一種狀況,你所依賴的庫變得過期,舊版本的漏洞被黑客利用.面試

重點: 始終記得在開發軟件時更新依賴項 . 幸運的是,這是一條命令:

composer update

若是你正在作一些特別須要使用 PHP 擴展(用 C 語言編寫)的東西,你就不能用 Composer 安裝它們。您還須要 PECL.

推薦的包

不管您正在構建什麼,您幾乎確定會從這些依賴項中獲益。這是大多數 PHP 開發人員推薦的(好比:PHPUnit、PHP-CS-fixer)。

roave/security-advisories

Roave 的安全報告 使用了名叫 Friends of PHP 的包來保證你的項目不會依賴任何已知的非健壯的包。

composer require roave/security-advisories:dev-master

或者,你能夠 上傳你的 composer.lock 文件到 Sensio Labs 做爲常規自動漏洞評估工做的一部分,它會把全部使用的過時的包告知你。

vimeo/psalm

Psalm 是一個靜態分析工具,能夠幫助識別你代碼中的 bug。雖然還有其餘很好的靜態分析工具(例如: Phan and PHPStan ,它們都很好),若是您發現本身須要支持 php 5,沒問題,psalm 是支持 php 5.4 + 的。

Psalm 是很容易上手的:

# 目前尚未Version 1 ,可是讓咱們拭目以待:

composer require --dev vimeo/psalm:^0#

僅需這樣操做:

vendor/bin/psalm --init#

一如慣例的操做:

vendor/bin/psalm

若是你是第一次在現有的代碼庫上運行,可能會看到不少紅色提示。這是正常的,除非你創造了一個如同 Wordpress 同樣強大的應用程序,不然不太可能使所有測試經過以知足符合 Herculean 的要求。

不管您使用哪一種靜態分析工具,咱們建議您將運用到持續集成工做流(若是適用),以便在每次代碼更改後運行它。

HTTPS 和瀏覽器安全

簡而言之: HTTPS, which should be tested, and security headers.

 

在 2018 年,經過不安全的 HTTP 訪問網站將再也不被接受。幸運的是,得益於 ACME 協議和 Let's Encrypt certificate authority 的存在,咱們能夠免費獲取 TLS 證書並自動更新它們。

 

將 Acme 集成到 Web 服務器中簡直就是小菜一碟。

  • Caddy: 自動生成.

  • Apache: 不久將以 mod_-md. 的形式提供, 這裏有高質量的教程 在互聯網上提供。

  • Nginx: 相對簡單.

你也許會想,「好吧,我有一個 TLS 證書。如今,我必須花幾個小時來處理配置,而後才能保證它的安全和快速。」

Nope! Mozilla 支持. 您可使用配置生成器根據預期的訪問羣體構建推薦的密碼套件

HTTPS (HTTP over TLS) 是絕對不可協商若是您但願您的網站是安全的。使用 HTTPS 能夠當即消除對用戶的幾類攻擊(中間建注入、竊聽、重複攻擊和多種形式的會話操做,不然將容許用戶模擬)。

安全 Headers

雖然將 HTTPS 鏈接到服務器上確實爲用戶增長了安全性和性能優點,但你能夠經過利用其餘瀏覽器安全功能更進一步的擴大這些優點。其中大多數都涉及在內容裏發送 HTTP 響應頭。

  • Content-Security-Policy

    • 你須要這個 header,由於它能夠對瀏覽器容許加載的內部和外部資源進行精度控制,從而爲跨站點腳本漏洞提供強大的防護層。

    • 請參閱 CSP-Builder,以便快速輕鬆地部署 / 管理內容安全策略。

    • 要進行更深刻的分析,Scott Helme 的 Content-Security-Policy 標題簡介是一個很好的起點。

  • Expect-CT

    • 你須要這個 header,由於它經過強制將不良居心的人的證書的證據發佈到可公開驗證的數據結構,從而爲惡意 / 受損的證書頒發機構添加了一層保護。 瞭解更多關於 「Expect-CT」 的信息

    • 首先將這個 header 設置爲 enforce,max-age = 30,並增長 max-age,如此操做讓服務更穩定。

  • Referrer-Policy

    • 你須要這個 header,由於它容許您控制是否將有關用戶行爲的信息泄露給第三方。

    • 再次深刻了解 Scott Helme 深刻探討Referrer-Policy headers

    • 將 header 設置爲 「same-origin」 或 「no-referrer」,除非您有理由容許更寬鬆的設置。

  • Strict-Transport-Security

    • 你須要這個 header,由於它告訴瀏覽器經過 HTTPS 強制全部未來的請求到同一個來源而不是不安全的 HTTP。

    • 首次部署時將其設置爲 「max-age = 30」,而後當您確信沒有任何內容會中斷時,將此值增長到某個較大的值(例如 「31536000」)。

  • X-Content-Type-Options

    • 你須要這個 header,由於 MIME 類型混淆可能致使不可預測的結果,包括容許 XSS 漏洞的奇怪邊緣狀況。最好伴隨標準的 Content-Type 標題。

    • 設置爲 nosniff,除非您須要默認行爲(例如,用於文件下載)。

  • X-Frame-Options

    • 你須要這個 header,由於它能夠防止點擊劫持

    • 設置爲 DENY(或 SAMEORIGIN,但僅當你使用 <frame> 元素時)

    • X-XSS-Protection
      - 你須要這個 header,由於它啓用了默認狀況下未啓用的某些瀏覽器 Anti-XSS 功能。
      - 設爲 1; mode=block

一樣,若是你使用 PHP 的內置會話管理功能(推薦使用),你可能想要調用 session_start(),以下所示:

session_start([

'cookie_httponly' => true,

'cookie_secure' => true]);

 

這會強制你的應用在發送會話標識符 cookie 時使用僅 HTTP 和安全標記,阻止成功的 XSS 攻擊竊取用戶的 cookie 並強制它們分別僅經過 HTTPS 發送。咱們以前已經在 2015 年的博文中介紹了安全 PHP 會話

 

子資源一致性攻擊(Subresource Integrity)

在未來的某個時候,你可能會使用 CDN 將經常使用的 Javascript / CSS 框架和庫放到一個集中的地方。

負責安全的工程師對這種操做表示有很明顯的安全隱患:那就是,許多網站使用 CDN 來提供內容,那麼攻擊 CDN 並替換內容注入這些代碼到成千上萬數千的網站。

輸入 subresource integrity.

Subresource integrity (SRI) 容許你固定你但願 CDN 提供的文件內容的哈希值。當前實現的 SRI 僅容許使用安全加密散列函數,這意味着攻擊者生成與原始文件產生相同散列的相同資源的惡意版本是不可行的。

真實的案例: Bootstrap v4-alpha 在他們的 CDN 示例片斷中使用 SRI.

<link

rel=``"stylesheet"

href=``"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"

integrity=``"sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ"

crossorigin=``"anonymous"``/><script

src=``"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"

integrity=``"sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn"

crossorigin=``"anonymous"``></script>

文檔關聯

Web 開發人員常常在超連接上設置 target 屬性(例如:target="_blank")實如今新窗口中打開連接。可是,若是您沒有傳遞 ' rel="noopener" 標記,則可能容許目標頁面控制原始頁面

不要這樣作

<a href=``"http://example.com" target=``"_blank"``>Click here</a>

這讓example.com 能夠控制當前的網頁。

替換成這樣

<a href=``"https://example.com" target=``"_blank" rel=``"noopener noreferrer"``>Click here</a>

這將在一個新窗口中打開 example.com,但不會將當前窗口的控制權交給可能懷有惡意的第三方。

延伸閱讀

開發安全的 PHP 軟件

若是應用程序安全性是一個新主題,請從應用安全性詳解開始.

許多安全領域的專家都會向開發人員提供諸如 OWASP Top 10 之類的資源.

可是,大多數常見漏洞能夠歸類爲同一類的安全問題(代碼 / 數據沒有徹底分離,邏輯不健全,操做環境不安全或加密協議缺陷)。

給新手們說明安全問題是一個很簡單的,容易實現的事情,可是如何解決這些安全問題將是更長遠的安全工程。

所以, 咱們只推薦類前 10 名或前 25 名安全檢查清單.

數據庫交互

深刻了解: PHP 防止 SQL 注入 https:``//paragonie.com/blog/2015/05/preventing-sql-injection-in-php-applications-easy-and-definitive-guide

若是您本身編寫 SQL 查詢,請確保您使用的是預備表達式,而且將網絡或文件系統提供的任何信息都做爲參數傳遞,而不是拼接查詢字符串。此外,確保你沒有使用_模擬的預備表達式_.

爲達到最佳效果,使用 EasyDB.

* 不要這樣作:

/* 不安全代碼:

*/``$query = $pdo``->query(``"SELECT * FROM users WHERE username = '" . $_GET``['username``'] . "'``");

替換成這樣:

 

 

/* 防止SQL注入: */

$results = $easydb``->row(``"SELECT * FROM users WHERE username = ?"``, $_GET``[``'username'``]);
還有其餘一些數據庫抽象層提供了同等的安全性(EasyDB 實際上在底層使用 PDO,可是爲了防止安全隱患,它特地禁用準備好的語句模擬,而使用實際的準備好的語句)。只要用戶輸入不能影響查詢的結構,您就是安全的。(這包括存儲過程。)

 

文件上傳

 

深刻了解: 如何安全地容許用戶上傳文件 https:``//paragonie.com/blog/2015/10/how-securely-allow-users-upload-files

接受文件上傳是一個冒險的主張,但只要採起一些基本的預防措施,就能夠安全地執行此操做。也就是說,應當阻止意外地容許執行或解釋上傳文件的方式直接訪問上傳文件.

上傳的文件應該是隻讀的或讀寫的,永遠不能被執行.

若是你的站點根目錄是 /var/www/example.com, 你不該該存貯上傳文件在 /var/www/example.com/uploaded_files.

相反,你應該將上傳文件存儲在沒法經過瀏覽器直接訪問的單獨目錄中 (例如, /var/www/example.com-uploaded/), 以避免它們意外地做爲服務器端腳本執行,打開遠程代碼執行的漏洞。

更簡單的解決方案是將站點根目錄向下移動一級 (例如,移動到:/var/www/example.com/public)。

文件上傳的另外一個問題是安全地 下載文件 。

直接訪問 SVG 圖像將在用戶的瀏覽器中執行 JavaScript 代碼。 這是真的,儘管 SVG 圖像的 MIME 類型是以image\ 爲前綴.

MIME 類型嗅探可能致使類型混淆攻擊。詳情見前文安全 HeadersX-Content-Type-Options 響應頭的介紹。

若是你不採納前面關於如何安全存貯上傳文件的建議,攻擊者可能設法上傳.php 或者.phtml 的文件, 經過直接在瀏覽器中訪問上傳文件執行任意代碼,從而得到對服務器的徹底控制。請安全地玩你的服務器。

跨站腳本 (XSS)

深刻閱讀: 關於防止 PHP 中的跨站點腳本漏洞,您須要瞭解的全部內容 https:``//paragonie.com/blog/2015/06/preventing-xss-vulnerabilities-in-php-everything-you-need-know

在理想的狀況下, XSS 和 SQL 注入同樣容易預防。咱們有簡單易用的 API ,用於將查詢語句和數據進行分離。

不幸的是,大多數 web 開發人員的實際工做會涉及到將生成的一長串 HTML 文本並經過 HTTP 協議響應。這不是 PHP 獨有的功能,它只是 web 開發的基本工做方式。

減小 XSS 漏洞並非那麼難作。可是,瀏覽器安全 的全部內容是相當重要。簡而言之:

  1. 常常對_輸出轉義_,而不是對_輸入轉義_。 若是你在數據庫中存儲已過濾的數據,而後在一些地方發現 SQL 注入漏洞,那麼攻擊者能夠經過惡意代碼篡改可信的數據記錄,從而徹底繞過 XSS 保護。

  2. 若是你的框架中有一個提供自動上下文過濾的模板引擎,那可使用它。它將會給你的框架的功能的安全性提供保障。

  3. echo htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8'); 是一種安全有效的方式,它能夠阻止對 UTF-8 編碼的 web 頁面的 XSS 攻擊,但它不容許任何 HTML 標籤內容輸出。

  4. 若是你的需求是容許你使用 Markdown 替代 HTML,不要使用 HTML

  5. 若是你須要容許一些 HTML 而且沒有使用模板引擎(請參見 #1),那麼就使用 HTML 淨化器。 HTML 淨化器不適用於將內容轉義成 HTML 標籤屬性的場景。

  6. 對於用戶提供的 URLs ,你應該只容許使用 http:https: 協議模式;不要用 javascript: 。此外,使用 URL 編碼方式編碼用戶的全部輸入。

跨站請求僞造 (CSRF)

跨站請求僞造是一種混亂的代理攻擊,經過這種攻擊,你能夠利用用戶的權限,欺騙用戶的瀏覽器執行惡意的 HTTP 請求來實現攻擊者的目的。

這在通常狀況下可經過兩個簡單步驟解決:

  1. 使用 HTTPS,這是前置條件。沒有 HTTPS,任何防護都會變得脆弱,然而單純的 HTTPS 並不能阻止 CSRF。

  2. 添加基本的請求 - 響應的身份驗證。

    • 在全部表單中添加一個隱藏的表單值。

    • 用安全的隨機加密字符串來填充這個值(稱爲令牌)。

    • 驗證表單中是否含有這個隱藏的值,而且校驗是否與設置的一致。

咱們編寫了一個名爲 Anti-CSRF 的庫來更進一步瞭解如何防範 CSRF。

  • 爲了防止重複攻擊,每一個令牌只能使用一次。

    • 多個令牌都存儲在後端。

    • 令牌輪換一旦達到上限,優先使用最老的。

  • 每一個令牌均可以綁定到指定的資源地址(URI)。

    • 一旦令牌泄露,那麼它也不能用於其餘資源請求。
  • 令牌能夠選擇綁定到指定的 IP 地址。

  • 從 v2.1 版本開始,令牌能夠重複使用(即 AJAX 調用)。

若是你沒有使用一個可以幫你解決 CSRF 的框架,那麼 Anti-CSRF 可以幫到你。

在未來,使用 cookie 的 SameSite 屬性可以更加簡單地防範 CSRF

譯者注:截至 2016 年 4 月,Chrome 5一、Opera 3九、火狐 60 已實現了 cookie 的 Same-Site 屬性。

XML 攻擊 (XML 外部實體注入,XPath 注入)

對於那些過多依賴 XML 數據結構來處理繁重的業務邏輯的程序而言,這裏有兩個比較容易被攻擊的點。

  1. XML 外部實體注入 (XXE)XPath 注入

  2. XXE 攻擊會利用服務器執行本地或遠端的的惡意外部文件, 或者執行其餘惡意的行爲.

在早期版本的谷歌安全文檔中就有顯著的說起 XXE 攻擊,但對於大多數的大量執行 XML 操做的非商業應用來講對 XXE 的防範意識是薄弱的。

其實最簡單的減輕 XXE 攻擊影響的方式就是:

libxml_disable_entity_loader(true);

XPath 注入 和 SQL 注入的原理同樣,只不過是把攻擊對象換成了 XML 文檔。

比較幸運的是,PHP 對 XPath 操做方法的查詢參數是很比較特殊和形式固定的。

另外一方面呢,PHP 對於 XPath 注入沒有提供簡單有效的防護手段(參數過濾)。

對於 XPath 查詢參數過濾,你的最佳方案就是使用白名單策略匹配過濾。

<?phpdeclare(strict_types=1);``class SafeXPathEscaper{

/**

* [@param] string $input

* [@return] string

*/

public static function allowAlphaNumeric(string $input``): string    {

return \preg_replace(``'#[^A-Za-z0-9]#'``, ''``, $input``);

}

/**

* [@param] string $input

* [@return] string

*/

public static function allowNumeric(string $input``): string    {

return \preg_replace(``'#[^0-9]#'``, ''``, $input``);

}}``// 用法示例:$selected = $xml->xpath(

"/user/username/" . SafeXPathEscaper::allowAlphaNumeric(

$_GET``[``'username'``]

));

這裏咱們採用白名單的策略比黑名單策略安全。

反序列化和 PHP 對象注入

深度閱讀: php 反序列化安全的實現 https:``//paragonie.com/blog/2016/04/securely-implementing-de-serialization-in-php

若是你將不可信的數據傳遞給 unserialize(),你將不得不面對如下兩個窘境:

  1. PHP 對象注入風險,一種利用 POP 鏈(POP chain)來觸發其餘誤用對象的漏洞。php 反序列化 POP 鏈的構造與理解異常語法

  2. 帶來的 PHP 解析器自己的內存奔潰。

對於大多數開發者來說他們更傾向於用 JSON 來替代對對象的序列化操做,這樣的話確實規避了不少安全風險,但又引起了另一個安全問題不得不提:DoS 攻擊 - Hash 碰撞攻擊( json_decode () 容易遭受 DoS 攻擊 - Hash 碰撞攻擊 (Hash-DoS) )。 遺憾的是, PHP 的 Hash-DOS 問題尚未獲得完全解決

對於 Hash-DOS 利用的 php Hash 衝突的問題。從 djb33 遷移到 Siphash,對於字符串輸入,哈希輸出的最高位設置爲 1 ,對於整數輸入設置爲 0 ,使用 CSPRNG 提供的請求密鑰,將徹底解決這些攻擊。

遺憾的是, PHP 團隊尚未準備好放棄他們已經在 PHP 7 系列中取得的性能提高,因此很難說服他們放棄 djb33 (這是很是快但不安全的) 採用 SipHash (這也是快速的,但不像 djb33 那麼快,但更安全)。 若是性能受到重大影響,可能會阻礙將來版本的採用,但也影響了安全性。

所以咱們當前能作的是:

  • 使用 JSON 的方式,由於它比 unserialize() 更安全。

    • 在任何可能的地方,在反序列化以前確保輸入是通過安全過濾的。

    • 對於提供給用戶的數據,經過一個只有服務器知道的祕鑰使用 sodium_crypto_auth()sodium_crypto_auth_verify() 驗證。

    • 對於第三方提供的數據,讓他們使用 sodium_crypto_sign() 簽名他們的 JSON 消息,而後使用 sodium_crypto_sign_open() 和第三方公鑰驗證消息。

  • 若是你須要對傳輸的簽名進行十六進制或 Base64 位編碼,也可使用分離的簽名 API 。

  • 若是你沒法確保 參數中 JSON 字符串的安全性,請嚴格限制單個 IP 訪問頻率以免高頻的攻擊。(laravel 框架能夠採用 Throttle 配置)

密碼哈希

深刻了解: 在 2016 年如何安全存儲用戶密碼 https:``//paragonie.com/blog/2016/02/how-safely-store-password-in-2016

密碼安全的存儲曾經是一個備受爭議的話題,但如今實現起來至關簡單,尤爲是在 PHP 中:

$hash = \password_hash(``$password``, PASSWORD_DEFAULT);``if (\password_verify(``$password``, $hash``)) {

// 已驗證

if (\password_needs_rehash(``$hash``, PASSWORD_DEFAULT)) {

// 刷新,更新數據庫

}}

您甚至不須要知道後臺使用的是什麼算法,由於若是您使用的是最新版本的 PHP,那麼您也將使用最新的最新版本,而且一旦有新的默認算法可用,用戶的密碼將自動升級。

無論你作什麼, 在 WordPress 不要這樣作.
若是你對此感到好奇:從 php 5.5 到 7.2,默認算法是 bcrypt。未來,它可能會切換到 Argon2,即 [密碼散列類型]https://password-hashing.net/).

若是您之前沒有在 API 中使用加密,同時須要遷移舊散列,請使用這種方法. 不少公司在這方面作了錯誤的操做,其中典型就的公司有,雅虎。, Yahoo. 最近,錯誤地實現舊哈希升級彷佛已經致使了蘋果最近的 iamroot bug caused Apple's recent iamroot bug.

通常用途的加密

這是咱們以前已經詳細討論過的話題:

一般,你總但願使用 Sodium 加密庫 (libsodium)對應用層加密。若是須要低於 7.2 版本(直到 5.2.4)你可使用 sodium_compat 並假設你的用戶也在使用 7.2 。

在特定的實例中,因爲嚴格的算法選擇和互操做性,你可能須要一個不一樣的庫。若是有疑問,能夠向加密專家諮詢加密方式,並向密碼工程師諮詢這種實現是否安全。(這就是咱們提供的服務之一 。)

若是你直接使用密碼 / 模式, 請參考關於加密最佳實踐的簡要指南

隨機數

深刻了解: 如何在 PHP 中安全地生成隨機字符串和整數 https:``//paragonie.com/blog/2015/07/how-safely-generate-random-strings-and-integers-in-php

若是您須要隨機數,請使用 random_int(). 若是須要隨機字節字符串,請使用 random_bytes(). 因此不要使用 mt_rand(), rand(), 或 uniqid() .

若是你須要從一個密鑰生成僞隨機數,不要用 srand() 或者 mt_srand(), 請查看 SeedSpring .

<?php

use ParagonIE\SeedSpring\SeedSpring;

$seed = random_bytes(16);``$rng = new SeedSpring(``$seed``);

$data = $rng``->getBytes(1024);

$int = $rng``->getInt(1, 100);

服務器端 HTTPS 請求

簡而言之:確保沒有禁用 TLS 證書驗證。

請隨意使用你熟悉且兼容 PSR-7 規範的 HTTP 客戶端,大多數人喜歡使用 Guzzle 庫。也有一些人喜歡直接使用 cURL。

不管你用哪種,你能夠 使用 Certainty 庫來確保你擁有最新的證書包 , 這進而容許你啓用最嚴格的 TLS 證書驗證設置,並保護服務器的出站 HTTPS 請求。

安裝 Certainty 庫很是簡單:

composer require paragonie/certainty:^1

使用 Certainty 庫也很容易:

<?php

use ParagonIE\Certainty\RemoteFetch;

$latestCACertBundle = (``new RemoteFetch())->getLatestBundle();

# 使用 cURL:

$ch = curl_init();

curl_setopt(``$ch``, CURLOPT_SSL_VERIFYHOST, 2);

curl_setopt(``$ch``, CURLOPT_SSL_VERIFYPEER, true);

curl_setopt(``$ch``, CURLOPT_CAINFO, $latestCACertBundle``->getFilePath());

# 使用 Guzzle:

/** [@var](https://my.oschina.net/u/1030343) \GuzzleHttp\Client $http */

$repsonse = $http``->get(

'https://example.com'``,

[

'verify' => $latestCACertBundle``->getFilePath()

]

這將保護你免受 Web 服務器與你集成的任何第三方 API 之間的中間人攻擊 (man-in-the-middle attacks)。

咱們_真的_ 須要 Certainty 庫嗎?

嚴格來講,爲了保護您的系統,Certainty 庫不是必要的。缺乏它並非弱點。

可是沒有 Certainty 庫。 開源軟件必須推測操做系統的 CACert 包是否存在,而且若是它推測錯誤,它會常常失敗得很慘並致使可用性問題。

縱觀歷史,這激勵了許多開發人員禁用證書驗證,這樣他們的代碼就能夠 「正常工做」 了,卻沒有意識到他們的應用程序在受到主動攻擊時是多麼不堪一擊。

Certainty 庫經過使 CACert 捆綁包位於最新的和可預測的位置來消除這種激勵。Certainty 庫還爲許多但願運行他們本身內部 CA 的企業提供了許多工具。

誰來禁用證書驗證?

常見的內容管理系統(WordPress,Magento 等)的插件 / 擴展開發人員能夠作到! 這是咱們在生態系統層面試圖解決的一個巨大問題。 它不是孤立於任何特定的 CMS,你會發現插件等。 由於全部這些都是不安全的。

若是您正在使用這樣的 CMS,請在插件中搜索 CURLOPT_SSL_VERIFYPEERCURLOPT_SSL_VERIFYHOST ,您可能會發現有幾個將這些值設置爲 FALSE

應該避免的事情

不要使用 mcrypt,一個已經十多年沒有開發的密碼學庫。若是您正在關注 咱們的 PHP 版本推薦,自從 PHP 7.2 及更新版本中沒有提供 mcrypt,這應該是一個容易避開的陷阱。

配置驅動安全建議應該有大部分被忽視了。若是你正在閱讀 PHP 安全指南而且他們告訴你修改 php.ini 配置,而不是編寫更優秀的代碼,那麼你可能正在閱讀很是過期的建議。 關掉當前窗口,並轉移到那些不吹噓 register_globals 的頁面中。

不要使用 JOSE (JWT, JWS, JWE),儘管腳註表示已經寫進了標準。但這是一套編纂成一系列容易出錯的密碼學設計,由於某些緣由吸引了大量追崇者而造成的互聯網標準 。

加密 URL 參數是一種不少公司用來混淆元數據採用的反面模式 (e.g. 咱們有多少使用者呢?)。在產生安全感的錯覺同時,它攜帶着實現錯誤的高風險。咱們在相關文章中提出了一個更安全的替代方案。

除非你真的無可奈何,不然不要實現 "忘記密碼" 功能。直言不諱地講: 密碼重置功能就是一個後門。 有一些方法能夠實現它們,這些方法對合理的威脅模型是安全的,可是這應該也給了高風險用戶一個讓他們徹底選擇退出的機會。

若是能夠,避免使用 RSA, 而使用 libsodium。若是你必定要 RSA,確保你指定了 OAEP 進行填補。

<?php

openssl_private_decrypt(

$ciphertext``,

$decrypted``, // 明文在成功時寫入這個變量。

$privateKey``,

OPENSSL_PKCS1_OAEP_PADDING // 重要:不要忽略這個!

);

若是你專一於使用 PKCS#1 v1.5 進行填補,不管你集成了什麼,幾乎都會很容易被 機器人攻擊,因此將其做爲一個容許明文公開和僞造簽名的漏洞報告給合適的供應商 (或 US-CERT)。

專業使用案例

既然你已經掌握了在 2018 年及之後構建安全 PHP 應用程序的基礎知識,如今讓咱們來看一些更專業的使用案例。

可搜索的加密

深刻閱讀:使用 PHP 和 SQL 創建可搜索的加密數據庫 https:``//paragonie.com/blog/2017/05/building-searchable-encrypted-databases-with-php-and-sql

可搜索的加密數據庫是可取的,但實現它被廣泛認爲不是很是重要。上面的博文試圖讓讀者更深刻地瞭解咱們的解決方案,但實際上你只需:

  1. 設計您的架構,使數據庫即便泄露也不會讓攻擊者獲取到您的加密密鑰。

  2. 使用密鑰加密你的數據。

  3. 基於 HMAC 或帶有靜態鹽的安全 KDF(例如:Argon2)建立多個索引(使用它們本身獨特的密鑰)。

  4. 可選:截斷步驟 3 的輸出,將其做爲一個布隆過濾器(Bloom filter)。

  5. 在你的 SELECT 查詢中使用第 3 或第 4 步的輸出結果。

  6. 解密結果。

在這個過程當中的任何步驟,你均可以根據你的實際狀況來作調整。

無邊信道的基於令牌的身份認證

深刻閱讀: 拆分令牌:無邊信道的基於令牌的身份驗證協議 https:``//paragonie.com/blog/2017/02/split-tokens-token-based-authentication-protocols-without-side-channels

說到數據庫(上一章節),你知道 SELECT 查詢理論上能夠成爲定時信息泄漏的來源嗎?

簡單的防範措施:

  1. 切分你的認證令牌。

  2. 一半在 SELECT 查詢中使用。

  3. 在必定的時間內使用後半部分進行驗。

    • 您能夠選擇將後半部分的哈希存儲在數據庫中,而不是它自己。這對於只使用一次的令牌是有意義的,如用在 「密碼重置」 或 「在這臺計算機上記住我」 等地方的令牌。

這樣即便你可能會由於定時泄漏被別人竊取到一半的令牌,剩下的一半也須要暴力破解才能成功。

開發安全的 API

深刻閱讀: 使用 Sapient 讓 PHP 開發的 API 更爲堅固 https:``//paragonie.com/blog/2017/06/hardening-your-php-powered-apis-with-sapient

咱們編寫了 SAPIENT(the Secure API ENgineering Toolkit)使服務器到服務器之間傳遞身份驗證信息變得更爲簡單。

除了具備 HTTPS 提供的安全性以外,Sapient 還容許你使用共享密鑰或公鑰來加密和驗證信息。

即便有一個用惡意 / 受損的證書頒發機構武裝本身的中間人攻擊(man-in-the-middle)攻擊者,也能讓你能夠對 API 請求進行身份驗證 ,並使用 ED25519 或只能由接收服務器的密鑰解密的加密信息對目標服務器響應。

因爲每一個 HTTP 消息體都經過安全加密進行了身份驗證,所以能夠安全地使用它來代替有狀態令牌可能會被篡改的協議(例如 OAuth)。但當涉及到密碼學時,在作任何非標準的事情以前,都應該始終確保專家對它們的實現進行了研究。

Sapient 所使用的全部密碼學算法都由 Sodium cryptography library 提供。

拓展閱讀:

Sapient 文檔

Sapient 教程

Sapient 規範

Paragon Initiative Enterprises 已經在其許多產品(包括許多開源軟件項目)中使用了 Sapient,並將繼續將軟件項目添加到 Sapient 產品組合中。

使用 Chronicle 記錄安全事件日誌

深刻閱讀: Chronicle 會讓你質疑區塊鏈技術的需求 https:``//paragonie.com/blog/2017/07/chronicle-will-make-you-question-need-for-blockchain-technology

Chronicle 是一個基於哈希鏈(hash-chain)數據結構的僅追加的加密分類帳(append-only cryptographic ledger),它具備許多吸引公司使用的 「區塊鏈」 技術的屬性,也不會有太多多餘的功能。

除了僅追加加密分類帳這樣具備創造性的使用案例以外,當集成到 SIEM 中時,Chronicle 也是很是有亮點的,由於你能夠將安全關鍵事件發送到私有的 Chronicle,使它們不可被改變。

若是你設置 Chronicle 將其摘要哈希交叉簽名到其餘 Chronicle 實例,或者配置了其餘實例來複制 Chronicle 的內容,那麼攻擊者就很難篡改你的安全事件日誌了。

使用 Chronicle,您能夠得到區塊鏈具備的全部彈性(resilience)特色,而不會出現任何隱私、性能和可擴展性問題。

要將數據發佈到本地 Chronicle,您可使用任何與 Sapient 兼容的 API,最簡單的方式是 Quill

做者的一些話

不少聰明的讀者應該注意到了咱們參考了不少咱們本身的工做內容(包括了一些以前發的博文和咱們的開源項目),但其實咱們並不只僅參考咱們本身的內容。

這並不意外。

本公司自從 2015 成立以來一直致力於編寫安全庫並參與改善 PHP 生態系統安全性。

咱們已經涉及了不少領域,但咱們的安全工程師(就在最近發佈的 PHP 7.2 中,他們推進了 PHP 核心更安全的加密技術的發展)本身並不太擅長炒做,也不會拘泥於過去所作的工做。極可能您甚至沒有據說過咱們多年來開發的一個半個工具或庫。對此咱們深感抱歉。

然而,咱們也不可能成爲全部方面的先驅,因此咱們會盡量地與一些符合公共利益而不是自私自利的專家們公事。這就是爲何在瀏覽器安全性的部分引用了 Scott Helme 和他的公司的工做內容,他們在使開發人員可以接觸和理解這些新的安全特性方面作了大量的工做。

本篇指南也不是徹底詳盡的。寫不安全的代碼的方法幾乎和寫安全的代碼的方法同樣多。安全不只僅是目的,更是一種心態。有了上面所寫的內容,以及接下來的資源,咱們但願這能幫助全世界的開發人員從今天起用 PHP 編寫安全的軟件。

資源

若是您已經閱讀的本篇的全部內容,而且還想了解更多的知識,那麼您可能會對咱們針對學習應用程序安全而制定的閱讀列表感興趣

若是您以爲您寫的代碼足夠安全,而且但願咱們以安全工程師的角度對其進行評價的話,那麼來找咱們吧,這實際上就是咱們爲客戶提供的一項服務之一。

若是您所在的公司將要進行規範測試(如 PCI-DSS, ISO 27001 等),那麼您可能會想要僱用個人公司來審覈您的源代碼。與其餘安全諮詢機構相比,咱們的流程對開發人員更加友好。

如下就是 PHP 和信息安全社區提供的資源列表了,這些資源有助於大家以本身的方式提升網絡安全性。

PHP 之道,真正的現代 PHP 開發指南。

Mozilla 的 SSL 配置生成器

Let's Encrypt,這是一個免費提供 TLS 證書的證書頒發機構網站,他們正在盡本身最大的努力來建立更安全的網絡環境。

Qualys SSL 庫 爲 TLS 配置提供了一個快速簡單的測試套件。實際上,每一個人都用它來解決他們的密碼套件和證書問題,緣由:它能很好地完成這項工做。

Security Headers 讓您檢驗您的網站在利用瀏覽器安全功能保護用戶方面的表現好壞。

Report-URI 是一個很棒的免費資源,能幫助您快速的主動啓用一個安全頭(kickstarting initiatives to implement security headers)。他們會爲您提供一個 Report-URI 傳遞給您的用戶的瀏覽器,若是有什麼異常發生或發現 XSS 攻擊媒介,它們就會向 Report-URI 發送報告。 Report-URI 會收集這些錯誤信息,讓您更好地分類和排除錯誤。

The PHP Security Advent CalendarRIPSTech 團隊製做。

Snuffleupagus,一個以安全爲導向的 PHP 模塊(繼承自 Suhosin 的思想,彷佛大部分已經被棄用)。

PHP Delusions,一個致力於更好地使用 PHP 的網站。做者的不少語調都很是執拗己見,但做者對技術準確性和清晰度的奉獻精神仍是使其值得一讀的,尤爲是對於那些不太熟悉 PDO 許多特性的人來講。

Have I Been Pwned? 幫助用戶發現他們的數據是否在過去發生數據泄露。

相關文章
相關標籤/搜索