一、背景
前段時間在做程式碼審計,發現很多專案都存在安全隱患,大多數是來自於引數未過濾所造成的;為了解決這個問題,我將Web安全開發規範手冊V1.0進行了培訓,但是效果並不是太理想,原因是培訓後開發者的關注點主要在功能完成度上,安全編碼對於他們來說並不是核心指標;
為了能讓開發者時時刻刻關注安全問題,我在gitlab服務端放了一個鉤子,這個鉤子主要是將本次提交的程式碼檔案進行了檢測,遇到可能存在安全風險的問題將其輸出出來,這樣開發者能夠對培訓的內容有更深的感受,更注重編碼時候的安全問題。
二、操作步驟
- 搭建環境
- 建立專案
- 建立鉤子
- 鉤子實驗
三、搭建環境
3.1 安裝gitlab
在正式部署到伺服器之前,我需要在本地搭建一個gitlab服務,用於鉤子的開發和測試,這裡我用docker搭建速度比較快,執行的命令如下
docker run --detach --publish 443:443 --publish 80:80 --name gitlab --restart always gitlab/gitlab-ce
命令執行之後,返回的資訊如下所示
在上圖中可以看到容器已經執行成功,使用瀏覽器訪問gitlab的地址
http://127.0.0.1
訪問之後需要設定一個管理員的密碼,如下圖所示
填寫密碼之後,確認修改密碼,會跳轉到gitlab的主頁,如下圖所示
這gitlab中建立一個專案用於鉤子測試,如下圖所示
建立專案成功之後,注意留意頁面中的Project ID:2
,把這個2
記錄一下,後續會使用到;接下來需要開始鉤子的開發和部署,鉤子可以使用各種語言開發,這裡我比較熟悉php,因此採用php開發。
3.2 安裝依賴
gitlab的容器預設不支援php語言,需要先安裝php,安裝命令如下所示
apt update -y && apt install php -y
命令執行之後,返回的資訊如下所示
在上圖中可以看到php已經安裝成功,為了驗證php命令是否可以執行,這裡我使用如下命令進行驗證
php -v
命令執行之後,返回的資訊如下所示
在上圖中可以看到php的版本是7.4.3 ,說明php已經安裝成功。
3.3 安裝semgrep
鉤子程式中需要呼叫semgrep,這個程式gitlab中也沒有安裝,需要安裝一下,這裡採用pip安裝,不過需要先升級pip的版本才行,升級的命令如下所示
pip3 install --upgrade pip
命令執行之後,返回的資訊如下所示
在上圖中可以看到pip的版本已經升級到21.1.2,說明升級成功了
semgrep還依賴setuptools模組,需要用pip先升級一下,升級的命令如下所示
pip3 install --upgrade setuptools
命令執行之後,返回的資訊如下所示
在上圖中可以看到setuptools模組已經升級成功
接下來就可以正式安裝semgrep了,安裝的命令如下所示
cd /usr/local/bin/ && python3 -m pip install semgrep
命令執行之後,返回的資訊如下所示
在上圖中可以看到semgrep已經安裝完成,這裡我需要再次使用semgrep命令來驗證一下,執行的命令如下所示
semgrep --version
命令執行之後,返回的資訊如下所示
在上圖中可以看到semgrep的版本資訊為0.52.0,確認安裝成功了。
3.4 檢視hash
現在我們需要在剛才建立的專案中新增鉤子,這裡需要找到專案的存放路徑,在專案頁中
echo -n 2 | sha256sum
命令執行之後,返回的資訊如下所示
find / -iname d4
命令執行之後,返回的資訊如下所示
在上圖中可以看到專案存放的位置,返回了兩個路徑,這兩個路徑其中有一個是軟連線,通過cd
命令進入進入專案的存放位置
cd /var/opt/gitlab/git-data/repositories/@hashed/d4
命令執行之後,再次執行ls
命令,得到的資訊如下所示
在上圖中可以看到有一個73的資料夾,這是gitlab的命名規則,進入此資料夾,命令如下所示
cd 73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git/
命令執行之後,返回的資訊如下所示
在上圖中可以看到此專案的所有檔案,我需要在這個位置開發鉤子檔案
五、建立鉤子
自定義鉤子需要存放在custom_hooks
目錄下,預設沒有此資料夾所以需要建立此資料夾,執行命令如下所示
mkdir custom_hooks && cd custom_hooks
5.1 新建鉤子
建立custom_hooks
資料夾並進入之後,使用vim建立一個鉤子檔案,命令如下所示
vim pre-receive
進入vim編輯器介面之後,將如下鉤子程式碼新增進去,程式碼如下所示
#!/usr/bin/php
<?php
fwrite(STDOUT, 'please input:');
list($oldVer, $newVer, $ref_name) = explode(" ", fgets(STDIN));
//ob_start();
$cmd = "git diff --name-only {$oldVer}..{$newVer}";
echo $cmd . PHP_EOL;
exec($cmd, $result);
$rand = date("Y-m-d-H-i-s");
$baseDir = "/tmp/11/$rand/";
$ruleFile = "/semgrep-rule.yaml";
foreach ($result as $value) {
if (strstr($value, ".php") !== false) {
$randName = $baseDir . $value;
if (!is_dir(dirname($randName))) {
# if (file_exists($randName) == false) {
mkdir(dirname($randName), 0777, true);
}
$cmd = "git show {$newVer}:$value > $randName";
# echo $cmd . PHP_EOL;
exec($cmd, $result);
}
}
$cmd = "/opt/gitlab/embedded/bin/semgrep -f '$ruleFile' $baseDir -o /tmp/11.txt";
exec($cmd, $result);
//ob_clean();
$notice = file_get_contents("/tmp/11.txt");
echo $notice . PHP_EOL;
file_put_contents("/tmp/11.txt", "");
exec("rm -rf $baseDir");
echo 0;
儲存並推出此鉤子檔案,接著需要給自定義鉤子目錄設定許可權,這裡我簡單粗暴的把許可權設定為777,命令如下所示
chmod -R 777 ../
許可權設定好之後,我還需要建立一個semgrep
的掃描規則檔案,用於判斷程式碼是否正確。
執行的命令如下所示
vim /semgrep-rule.yaml
進入vim編輯器之後,需要將如下規則內容複製進去
rules:
- id: assert-use
patterns:
- pattern: assert($ASSERT, ...);
# - pattern-not: assert(<... $ASSERT ...>, ...); - https://github.com/returntocorp/semgrep/issues/2035
- pattern-not: assert("...", ...);
message: |
使用使用者輸入呼叫assert等價於eval'。
metadata:
references:
- https://www.php.net/manual/en/function.assert
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/AssertsSniff.php
languages: [ php ]
severity: ERROR
- id: backticks-use
pattern: '`...`;'
message: |
使用反勾號可能導致命令注入漏洞。
metadata:
references:
- https://www.php.net/manual/en/language.operators.execution.php
- https://github.com/FloeDesignTechnologies/phpcs-security-audit/blob/master/Security/Sniffs/BadFunctions/BackticksSniff.php
languages: [ php ]
severity: ERROR
儲存並推出規則檔案後,需要修改此規則檔案的許可權,這裡我以777許可權距離,命令如下所示
chmod 777 /semgrep-rule.yaml
設定完規則檔案許可權之後,還有兩個快取地方需要設定許可權,否則會在執行過程當中報錯,首先是semgrep的快取檔案,設定許可權命令如下
mkdir -p /var/opt/gitlab/.cache && chmod -R 777 /var/opt/gitlab/.cache
另外一處是鉤子本身的快取檔案,同樣需要設定許可權,執行的命令如下所示
echo '' > /tmp/11.txt && chmod 777 /tmp/11.txt
5.2 測試鉤子
現在可以正式測試鉤子的可用性,首先需要拉取剛才建立的專案程式碼,命令如下所示
git clone http://127.0.0.1/root/test.git
執行命令之後,返回的資訊如下所示
在上圖中可以看到專案已經拉取下來,接下來我需要編輯一個php檔案,命令如下所示
vim index.php
命令執行完畢之後,將測試的程式碼存放進去
<?php
phpinfo();
$cmd = "ls {$_GET['x']}";
exec($cmd);
儲存並退出之後,將程式碼提交到gitlab中去,命令如下所示
echo ' ' >> index.php && git add . && git commit . -m 'init' && git push
但git往gitlab伺服器推送之後,gitlab就會呼叫鉤子,並將鉤子返回的資訊輸出出來,如下圖所示
在上圖中可以看到鉤子提示了 index.php
檔案第8行不安全,此致整個部署完畢。
作者:湯青松
日期:2021-06-03
微信:songboy8888
本作品採用《CC 協議》,轉載必須註明作者和本文連結