# PHP 版本
請在 2019 年使用 PHP 7.2, 并且計劃 2019 中期切換到 PHP 7.3
到目前為止(2018-01-19),PHP 7.2 已經發布快兩個月了。
7.1 以下版本已進入 LTS 養老末期,使用低版本的 PHP 意味著沒有官方的安全維護,
也無法使用新特性和更快的速度(例如 PHP 內置加密操作 PASSWORD_HASH() 僅支持 PHP >= 5.5 ,
和大多數軟件一樣,PHP 通常會提供 LTS 長期支持和維護,
但是因為無法知道安全補丁的版本號,不像 Windows 操作系統一樣,安全補丁有據可查, 這會使得產品的安全性大大降低。
因此,如果你是新開的項目,請使用 PHP 最新版本,而過舊的項目也要嘗試重構更新。
## 依賴管理
> Composer 安裝、配置及使用請參考本書 第二章:2.3 開發環境搭建
Composer: https://getcomposer.org/ 在 PHP 生態中是重要的一環,大部分的擴展包都是通過 Composer 進行管理。
如果你是手動下載擴展包并進行手動加載,那么在大型應用上,你無法檢測某個框架是否過時,
也無法知曉某個框架的重大安全漏洞并及時更新到最新版本,過老的版本是非常不安全的。
## HTTPS 和瀏覽器安全
HTTPS,一種通過計算機網絡進行安全通信的傳輸協議
在 2018 年,所有現代安全的瀏覽器已經不在接受 HTTP,用戶打開 HTTP 協議的網站時,
瀏覽器會警告該網站的連接不安全。
不過你可以從各大云廠商免費的申請一個 TLS 證書, 或者使用 Let's Encrypt certificate authority: https://letsencrypt.org/ .
## 開發安全的 PHP 程序
避免 PHP 程序存在 SQL 注入
如果你是自己編寫 SQL 代碼, 請確保使用 prepared 語句,
并且從網絡或文件系統提供的信息都作為參數傳遞, 而不是字符串拼接的形式。
此外,確保你沒有使用 模擬的 prepared 語句: https://stackoverflow.com/questions/134099 .
## 文件上傳處理
接受未知來源的問題,意味著這些文件可能惡意攻擊服務器,
請保證服務器文件權限不超過 775,
上傳的新文件應該是 只讀或讀寫,
不要在網站根目錄保存文件,
同大多數 PHP 框架一樣,不在根目錄運行 index.php 目的是為惡意代碼提供最少的執行環境,
例如:
` /var/www/example.com-uploaded/ `
或者直接將文件往下移動一個層級
` /var/www/example.com/public `
## 跨站請求偽造
跨站請求偽造(CSRF)是一種混淆的代理攻擊,通過誘導用戶的瀏覽器代表攻擊者執行惡意的 HTTP 請求(使用的是該用戶的權限).
首先使用 HTTPS,沒有 HTTPS 的話,任何保護都是脆弱的,因為所有數據都是明文傳輸。
如果你是用的是現代 PHP 框架,請在框架中開啟 CSRF 驗證
如果你是原生用戶,只需要:
* 增加基本的 Challenge-response authentication。
* 為每個表單添加一個隱藏的表單屬性。
* 填充一個密碼安全的隨機值(稱為令牌).
* 驗證是否提供了隱藏的表單屬性,以及是否匹配上期望值。
## 密碼散列
>安全的密碼存儲曾經是一個激烈爭論的話題,但現在實現起來相當微不足道
~~~~
$hash = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($password, $hash)) {
// Authenticated.
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
// Rehash, update database.
}
}
~~~~
甚至不需要知道在后臺使用什么算法,因為如果你使用最新版本的 PHP ,你也將使用當前最新的技術,用戶的密碼將會自動進行升級(只要有新的默認算法可用).
無論你做什么,都不要做 WordPress 所做的事情
WordPress 并不使用 bcrypt 來儲存密碼,而是使用 MD5,
要理解為什么,首先查看 這個代碼片段 以及 這一個
如果 $this->portable_hashes 設置為TRUE,則會調用 $this->crypt_private()
因此,HashPassword 可以大大簡化為以下片段:
~~~~
function HashPassword($password)
{
if ( strlen( $password ) > 4096 ) {
return '*';
}
/* these steps are skipped */
$random = $this->get_random_bytes(6);
$hash =
$this->crypt_private($password,
$this->gensalt_private($random));
if (strlen($hash) == 34)
return $hash;
return '*';
}
~~~~
- 第一章. 基礎信息
- 1.1 序言
- 1.2 關于作者
- 1.3 本書源碼
- 1.4 反饋糾錯
- 1.5 安全指南
- 1.6 捐助作者
- 第二章. 開發環境布置
- 2.1 編輯器選用
- 2.2 命令行工具
- 2.3 開發環境搭建
- 2.4 瀏覽器選擇
- 2.5 第一個應用
- 2.6 Git 工作流
- 第三章. 構建頁面
- 3.1 章節說明
- 3.2 靜態頁面
- 3.3 Think 命令
- 3.4 小結
- 第四章. 優化頁面
- 4.1 章節說明
- 4.2 樣式美化
- 4.3 局部視圖
- 4.4 路由鏈接
- 4.5 用戶注冊頁面
- 4.6 集中視圖
- 4.7 小結
- 第五章. 用戶模型
- 5.1 章節說明
- 5.2 數據庫遷移
- 5.3 查看數據表
- 5.4 模型文件
- 5.5 小結
- 第六章. 用戶注冊
- 6.1 章節說明
- 6.2 注冊表單
- 6.3 用戶數據驗證
- 6.4 注冊失敗錯誤信息
- 6.5 注冊成功
- 6.6 小結
- 第七章. 會話管理
- 7.1 章節說明
- 7.2 會話
- 7.3 用戶登錄
- 7.4 退出
- 7.5 小結
- 第八章. 用戶 CRUD
- 8.1 章節說明
- 8.2 重構代碼
- 8.3 更新用戶
- 8.4 權限系統
- 8.5 列出所有用戶
- 8.6 刪除用戶
- 8.7 訪客模式
- 8.8 優化前端
- 8.9 小結
- 第九章. 微博 CRUD
- 9.1 章節說明
- 9.2 微博模型
- 9.3 顯示微博
- 9.4 發布微博
- 9.5 微博數據流
- 9.6 刪除微博
- 9.7 小結