天天看點

php代碼審計_PHP代碼審計簡單思路。。。PHP常用架構業務邏輯多線程引發的漏洞

php代碼審計_PHP代碼審計簡單思路。。。PHP常用架構業務邏輯多線程引發的漏洞

PHP常用架構

Zendframwork、Yii、Laravel 、ThinkPHP。。。

這裡舉例因為thinkphp由國内人開發使用者量較多而且曆史漏洞也多

Thinkphp曆史漏洞很多,對于漏洞形成原因可以自己複現。

篇幅有限隻介紹披露漏洞

Update方法 低于3.2.3 有sql注入問題

/**
     * 更新記錄
     * @access public
     * @param mixed $data 資料
     * @param array $options 表達式
     * @return false | integer*/public function update($data,$options) {$this->model  =   $options['model'];$this->parseBind(!empty($options['bind'])?$options['bind']:array());$table  =   $this->parseTable($options['table']);$sql   = 'UPDATE ' . $table . $this->parseSet($data);if(strpos($table,',')){// 多表更新支援JOIN操作$sql .= $this->parseJoin(!empty($options['join'])?$options['join']:'');
        }$sql .= $this->parseWhere(!empty($options['where'])?$options['where']:'');if(!strpos($table,',')){//  單表更新支援order和lmit$sql   .=  $this->parseOrder(!empty($options['order'])?$options['order']:'').$this->parseLimit(!empty($options['limit'])?$options['limit']:'');
        }$sql .=   $this->parseComment(!empty($options['comment'])?$options['comment']:'');return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);
    }
           

在github上也有曆史分支可以檢視修複代碼.

業務邏輯

想要對整體的邏輯進行審計

  1. 熟悉業務場景
  2. 熟悉業務流程
  3. 通讀代碼

多線程引發的漏洞

例子

php
           
$money=100;
           
//資料庫查詢的使用者餘額$buy=intval($_GET['buy']);if ($money>0 && $money-$buy>0){sleep(10);$moeny -= $buy;//寫入資料庫
}return $money
           

正常情況下使用者餘額一定不為負數 如果在并發情況下呢?

使用者發送惡意并發請求時就有可能出現這種情況。這麼防禦呢

這裡需要知道事務和鎖的概念可以自行百度了解我這裡簡單概述一下

事務:類似一個執行任務 成功就任務完成 ,失敗任務自動復原到未接任務前

鎖:悲觀鎖,樂觀鎖。

我們可以把多線程請求變成單線程處理,這裡也可以用隊列壓入壓出。

php$money = 100;//資料庫查詢的使用者餘額$buy = intval($_GET['buy']);try {if (flock($money, LOCK_EX)) {if ($money > 0 && $money - $buy > 0) {sleep(10);$moeny -= $buy;//寫入資料庫Athrow new ExceptionNew("xp");//寫入資料庫B
        }flock($money, LOCK_UN);
    }
} catch (Exception $exceptione) {throw new ExceptionNew("xp");
}return $money
           

這樣确實解決了這個并發問題,但又有另外一個問題,如果有多個資料庫操作中間一段中斷是無法對資料還原的,這裡我們需要把事務也加上同時預設加鎖。

我們修改一下代碼看一下

php$money=100;//資料庫查詢的使用者餘額$buy=intval($_GET['buy']);try{$this->startTrans();//開啟事務if ($money>0&& $money-$buy>0){sleep(10);$moeny-=$buy;$this->commit(); //送出事務
        //寫入資料庫
    }
}catch (Exception $exceptione){$this->rollback();//復原
}return $money;
           
php$buy=intval($_GET['buy']);try{$this->startTrans();//開啟事務$money=100;//資料庫查詢的使用者餘額if ($money>0&& $money-$buy>0){sleep(10);$moeny-=$buy;$this->commit(); //送出事務
        //寫入資料庫
    }
}catch (Exception $exceptione){$this->rollback();//復原
}return $money;
           

在加了事務的悲觀鎖後,所有請求到已經開啟事務的代碼,都會進行阻塞隻有送出了事務或者復原才會處理下一個請求。

然而這樣的代碼并不能防禦并發。這也是很多開發中的問題,确實做了事務加鎖,依然沒有用。加事務必須是在查詢内加,不然依舊會造成并發問題。我們在改改把讀放入事務鎖中。

php$buy=intval($_GET['buy']);try{$this->startTrans();//開啟事務$money=100;//資料庫查詢的使用者餘額if ($money>0&& $money-$buy>0){sleep(10);$moeny-=$buy;$this->commit(); //送出事務
        //寫入資料庫
    }
}catch (Exception $exceptione){$this->rollback();//復原
}return $money;
           

這樣也解決了髒讀的問題。

  髒讀:

(針對未送出資料)如果一個事務中對資料進行了更新,但事務還沒有送出,另一個事務可以“看到”該事務沒有送出的更新結果,這樣造成的問題就是,如果第一個事務復原,那麼,第二個事務在此之前所“看到”的資料就是一筆髒資料。

當然也有更複雜的情況可能架構有多個端。這種二次利用的情況更加難以審計。

在實際審計中我們想要精通一個語言的代碼審計我們要做的更難

  1. 要比産品更懂業務
  2. 要比測試更懂流程
  3. 要比開發更懂代碼
  4. 要比架構更懂架構

文章來源:https://www.cnblogs.com/feizianquan/p/11637337.html

看完本文有收獲?點贊、分享是最大的支援!

php代碼審計_PHP代碼審計簡單思路。。。PHP常用架構業務邏輯多線程引發的漏洞