主頁 > 知識庫 > 如何讓PHP的代碼更安全

如何讓PHP的代碼更安全

熱門標(biāo)簽:Linux服務(wù)器 團(tuán)購網(wǎng)站 電子圍欄 科大訊飛語音識別系統(tǒng) 阿里云 銀行業(yè)務(wù) 服務(wù)器配置 Mysql連接數(shù)設(shè)置

概述

攻擊者通過構(gòu)造惡意SQL命令發(fā)送到數(shù)據(jù)庫,如果程序未對用戶輸入的 SQL命令執(zhí)行判斷過濾,那么生成的SQL語句可能會繞過安全性檢查,插入其他用于修改后端數(shù)據(jù)庫的語句,并可能執(zhí)行系統(tǒng)命令,從而對系統(tǒng)造成危害

例如刪除 id 為 1 的帖子,sql 如下:

$post_id = $_POST['post_id'];
$sql = "DELETE FROM posts WHERE user_id = 1 AND id = $post_id";
\DB::statement($sql);

如果有人在提交 post_id 時輸入 1 OR 1 ,你的語句會組合成這樣:

$sql = "DELETE FROM posts WHERE user_id = 1 AND id = 1 OR 1";

一般比較常出現(xiàn)在原生的 SQL 操作,框架一般會解決這方面的問題。通常采用參數(shù)控制或過濾特殊字符避免上述的問題。

越權(quán)漏洞

1. 水平越權(quán)

水平越權(quán)就是同等角色下的用戶,不但能夠訪問和操作自己私有的數(shù)據(jù),還能訪問其他人私有的數(shù)據(jù),其根本是基于數(shù)據(jù)的訪問權(quán)限。

刪除用戶收款方式的場景如下:

graph LR

用戶登錄-->token

token-->獲取收款方式列表

獲取收款方式列表--token-->通過id刪除

通過收款方式 {id} 執(zhí)行 delete 請求的路由為:localhost/api/payments/{id}

假如用戶A的收款方式有{1,2,3}    用戶B的收款方式有{4,5}

如果沒有做數(shù)據(jù)控制,A 登錄后攜帶 A 的 token 執(zhí)行刪除的接口localhost/api/payments/4,則會刪除 B 的,所以需要對destory方法做數(shù)據(jù)控制

# 1 刪除前鑒權(quán)處理
public function destory($id){
    $payment = Payment::find($id);
    if ($payment->user_id != $this->currentUser->id) {
            return ...
    }
    $payment->delete();
}

# 2 參入id查詢刪除
public function destory($id){
    Payment::whereUserId($this->currentUser->id)->whereId($id)->delete();
}

# 3 模型關(guān)聯(lián)查詢
class User extends Model{
    public function payments()
    {
            return $this->hasMany('App\Payment');
    }
}

class PaymentController extends Controller{
    public function destory($id)
    {
            $this->currentUser->payments()->whereId($id)->delete();
    }
}

推薦使用第三種方式做數(shù)據(jù)控制,不然面向?qū)ο蟀讓W(xué)了。獲取收款方式的列表同樣需要數(shù)據(jù)權(quán)限控制,用戶和收款方式存在一對多的關(guān)聯(lián)關(guān)系,模型關(guān)聯(lián)后,獲取用戶收款方式列表可以寫成

class PaymentController extends Controller{
    public function index($id)
    {
        #帶條件的查詢
        $payments = $this->currentUser->payments()->where(function($query){
                ...
        })->get();

        #不帶條件的查詢
        $payments = $this->currentUser->payments;
    }
}

2. 垂直越權(quán)

低權(quán)限的角色通過一些途徑,獲得高權(quán)限的能力,就發(fā)生了越權(quán)訪問。如普通用戶 guest 修改 admin 用戶的密碼;guest 可直接進(jìn)入后臺取得域名管理、用戶管理等所有權(quán)限

解決這個問題,需要把權(quán)限職責(zé)以最小顆粒細(xì)分,基于 RBAC 設(shè)計(jì)權(quán)限管理系統(tǒng)。分為以下關(guān)聯(lián)模型

graph LR 

用戶--多對多-->角色

用戶--多對多-->權(quán)限

角色--多對多-->權(quán)限

每次執(zhí)行請求時,在前置中間件判斷這個用戶是否永遠(yuǎn)該執(zhí)行請求的權(quán)限,無權(quán)限則駁回。

3. 上下文越權(quán)

攻擊者能夠利用應(yīng)用程序狀態(tài)機(jī)中的漏洞獲得關(guān)鍵資源的訪問權(quán)限,這就存在上下文相關(guān)的越權(quán)。上下文相關(guān)的越權(quán)漏洞一般屬于業(yè)務(wù)邏輯漏洞。 如在找回密碼過程中,攻擊者使用自己的賬戶信息通過驗(yàn)證,將他人的密碼進(jìn)行了修改。

graph LR

1.郵箱驗(yàn)證-->2.找回密碼

在步驟1之后,執(zhí)行找回密碼,路由為 。如果此時沒有校驗(yàn)當(dāng)前找回密碼的賬戶是否為進(jìn)行郵箱校驗(yàn)后的賬戶,由可能產(chǎn)生越權(quán)漏洞.

路由 : 【PUT 】localhost/api/users/find-password,接收參數(shù) email,new_password.

錯誤:校驗(yàn)和修改分成 2 步localhost/api/email/check->localhost/api/users/password

class UserController extends Controller{
    public function check($data)
    {
        if (checkEmail($data['email'], $data['code'])) {
                return true;
        }
        ...
    }

    public function findPassword()
    {
        $user = User::whereEmail($data['email'])->first();
        $user->password = bcrypt($data['new_password']);
        $user->save();
    }
}

正確:在 findPassword 里面再次驗(yàn)證完成郵箱校驗(yàn)的賬戶是否為當(dāng)前找回密碼的賬號

class UserController extends Controller{

    public function check($data)
    {
        if (checkEmail($data['email'], $data['code'])) {
                return true;
        }
        ...
    }

    public function findPassword($data)
    {
        if (checkEmail($data['email'], $data['code'])) {
                $user = User::whereEmail($data['email'])->first();
                $user->password = $data['new_password'];
                $user->save();
        }
        ...
    }
}

限制分頁條目范圍,防止惡意請求

如獲文章列表的接口localhost/api/articles

public function index($params){
    $pageId = $params['pageid'] ?? PAGE_ID;    //頁碼
    $pageSize = $params['pagesize'] ?? 15;  //條碼

    $articles = Article::where(function ($query) use ($params) {
            ...
    })->take($pageSize)->skip($pageId * $pageSize)->orderby('id', 'desc')->get();
    ...
    ...
}

以上代碼如果沒有限制 pagesize 的范圍,惡意請求者請求把 pagesize 輸入 5000,10000 等甚至更大的數(shù),會給數(shù)據(jù)庫帶來一定的壓力,localhost/api/articles?pageid=0pagesize=10000

//用框架自帶的分頁方法
public function index(){
    $builder = Article::with('category:id,name')->orderBy('id', 'desc')->paginate(8);
    return response()->json(['status' => true, 'count' => $builder->total(), 'articles' => $builder->items()]);
}

JWT 的 Token 需要二次加密

許多拓展包加密出的token并不十分安全,用base64_decode可以解密獲取 加密主鍵、載荷等重要信息,所以通常需要對JWT的token進(jìn)行二次加密

限制上傳文件的類型

對于一個圖片上傳的接口,如果沒有對上傳文件的格式做限制,攻擊者很有可能把 .php后綴的文件上傳到public/images目錄下,然后通過根目錄執(zhí)行這個文件。

需要設(shè)計(jì)安全的文件上傳功能避免上述問題

1.文件上傳的目錄設(shè)置為不可執(zhí)行

2.判斷文件類型

3.使用隨機(jī)數(shù)改寫文件名和文件路徑

4.單獨(dú)設(shè)置文件服務(wù)器的域名

禁止或者避免寫自動解壓.zip 等壓縮文件的代碼

單純地限制文件或壓縮包大小并沒有用,一個ZIP炸彈的.zip文件僅有 42 KB,但在解壓后會占用 4718592 GB

避免登錄密碼被暴力破解

1.設(shè)定嚴(yán)格的速率限制,如登錄次數(shù)限制,登錄錯誤次數(shù)達(dá) x 次時暫停登錄 n 分鐘

2.密碼加上隨機(jī)鹽

public function reg(){
    $user = new User;
    $salt = radom(6);
    $user->password = bcrypt($data['password'] . $salt);
    ...
}

做好異常處理,避免在生產(chǎn)環(huán)境中不正確的錯誤報告暴露敏感數(shù)據(jù)

如果你不小心,可能會在生產(chǎn)環(huán)境中因?yàn)椴徽_的錯誤報告泄露了敏感信息,例如:文件夾結(jié)構(gòu)、數(shù)據(jù)庫結(jié)構(gòu)、連接信息與用戶信息。

1.在.env 文件中關(guān)閉調(diào)試模式

APP_DEBUG=true

2.php 錯誤控制 error_reporting、display_errors

?php
// 關(guān)閉錯誤報告
error_reporting(0);

// 報告 runtime 錯誤
error_reporting(E_ERROR | E_WARNING | E_PARSE);

// 報告所有錯誤
error_reporting(E_ALL);

// 等同 error_reporting(E_ALL);
ini_set("error_reporting", E_ALL);

// 報告 E_NOTICE 之外的所有錯誤
error_reporting(E_ALL  ~E_NOTICE);
?>

display_errors = Off

php 弱語言的設(shè)計(jì)缺陷如:in_array

$array=[0,1,2,'3'];

var_dump(in_array('abc', $array)); //true

var_dump(in_array('1bc', $array)); //true

# 上面的情況返回的都是 true, 因?yàn)?abc'會轉(zhuǎn)換為 0,'1bc'轉(zhuǎn)換為 1

$a = null;
$b = false;
echo $a==$b;  //true

$c = "";
$d = 0;
echo $c==$d   //true

在一些重要的地方需要使用===來作數(shù)據(jù)判斷。

LFI (本地文件包含)

LFI (本地文件包含) 是一個用戶未經(jīng)驗(yàn)證從磁盤讀取文件的漏洞。

不驗(yàn)證過濾用戶的輸入 將它要渲染的模板文件用 GET 請求加載。

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ì)考慮允許用戶輸入的類型,并刪除可能有害的字符,如輸入字符中的 “.” “/” “\”。

XSS

XSS 又叫 CSS (Cross Site Script) ,跨站腳本攻擊。它指的是惡意攻擊者往 Web 頁面里插入惡意 html 代碼,當(dāng)用戶瀏覽該頁之時,嵌入其中 Web 里面的 html 代碼會被執(zhí)行,從而達(dá)到惡意攻擊用戶的特殊目的。

body>
    ?php
        $searchQuery = $_GET['q'];
        /* some search magic here */
    ?>h1>You searched for: ?php echo $searchQuery; ?>/h1>/body>

因?yàn)槲覀儼延脩舻膬?nèi)容直接打印出來,不經(jīng)過任何過濾,非法用戶可以拼接 URL: search.php?q=%3Cscript%3Ealert(1)%3B%3C%2Fscript%3E

PHP 渲染出來的內(nèi)容如下,可以看到 Javascript 代碼會被直接執(zhí)行:

body>
h1>You searched for: script>alert(1);/script>/h1>
p>We found: Absolutely nothing because this is a demo/p>
/body>

Javascript 可以:

  • 偷走你用戶瀏覽器里的 Cookie;
  • 通過瀏覽器的記住密碼功能獲取到你的站點(diǎn)登錄賬號和密碼;
  • 盜取用戶的機(jī)密信息;
  • 你的用戶在站點(diǎn)上能做到的事情,有了 JS 權(quán)限執(zhí)行權(quán)限就都能做,也就是說 A 用戶可以模擬成為任何用戶;
  • 在你的網(wǎng)頁中嵌入惡意代碼;

使用htmlentities()過濾特殊字符,防止大部分的 xss 攻擊

CSRF (跨站請求偽造)

例如網(wǎng)站上有用戶可以用來注銷賬戶的鏈接。

a  rel="external nofollow" >銷毀賬戶/a>

如果某個用戶評論:

img src=”http://your-website.com/delete-account”> wow

用戶將在查看此評論的時候刪除他們的賬號。

laravel 的 web 路由默認(rèn)開啟了 csrf 驗(yàn)證,原理是在客戶端產(chǎn)生一個隨機(jī)的 token,在表單校驗(yàn)時判斷這個 token 是否是這個頁面上的請求

以上就是如何讓PHP的代碼更安全的詳細(xì)內(nèi)容,更多關(guān)于讓PHP的代碼更安全的資料請關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:
  • 如何理解PHP程序執(zhí)行的過程原理
  • 如何使用PHP依賴管理工具Composer
  • 如何使用Casbin作為ThinkPHP的權(quán)限控制中間件
  • 詳解php內(nèi)存管理機(jī)制與垃圾回收機(jī)制
  • 淺談PHP性能優(yōu)化之php.ini配置
  • 詳解PHP的7個預(yù)定義接口
  • 如何使用Zephir輕松構(gòu)建PHP擴(kuò)展
  • 詳解thinkphp的Auth類認(rèn)證
  • 如何使用PHP7的Yaconf

標(biāo)簽:棗莊 蚌埠 衡水 江蘇 萍鄉(xiāng) 廣元 衢州 大理

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《如何讓PHP的代碼更安全》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266