一、背景
前段時間在做代碼審計,發現很多項目都存在安全隱患,大多數是來自於參數未過濾所造成的;爲了解決這個問題,我將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