引言
这个问题一开始真的难倒我了。
我接到的需求是,如何防止提交的成员不是成员本身?
这个需求乍一看其实很无厘头,因为权限的关系,能够提交推送的人,必然是团队内部成员,防止的人就是内部人员。
换句话来说,这就是防自己人的。
我其实看到就很无语了,防自己人干啥?又不是什么特别大的公司,有什么必要呢?
但是理由也说得过去,是因为有可能把自己写的 bug
,栽赃在团队里其他的成员身上,也……好像说的过去。
所以我就在考虑如何解决这个问题。
过程
解决这个问题其实很曲折。
Git Hook
——pre-receive
实现
我一开始是在想,如何通过服务端的 git hook
来验证用户来源名字和邮箱,遂百度了一堆 git
钩子的方式,都是用 shell
来编写的。
大概思路是这样的:
- 首先读取
pre - receive
钩子传入的旧版本号(oldrev
)、新版本号(newrev
)和引用名称(refname
)。 - 然后,对于在这个版本区间内的每个提交,它获取提交者的用户名(
%an
)和邮箱地址(%ae
)。 - 最后,它检查如果提交者是
yuesha
但邮箱不是hw1312@qq.com
,就报错并阻止提交。
这里我甚至想定义一个 allowed_users
数组,来存放团队成员的名字和邮箱。
代码大概长这样:
#!/bin/bash
# 定义允许的用户名和邮箱地址组合数组
declare -A allowed_users=(
["yuesha"]="hw1312@qq.com"
)
while read oldrev newrev refname; do
# 遍历每个提交
for commit in $(git rev - list $oldrev..$newrev); do
author_name=$(git show - s -- format='%an' $commit)
author_email=$(git show - s -- format='%ae' $commit)
if [[ -n ${allowed_users[$author_name]} && ${allowed_users[$author_name]}!= $author_email ]]; then
echo "Error: 提交的用户名和邮箱地址不匹配。对于用户 $author_name,邮箱地址应为相应的指定邮箱。"
exit 1
fi
done
done
但是这里有一个很大的问题,脚本当中有 git rev - list $oldrev..$newrev
这一句
在新版的 git
当中是会报错的——不存在git rev命令
我找了很多解决方案,包括换命令 git log
啊,折腾了好久,但是依然解决不掉这个报错:
remote: hooks/pre-receive: line 8: conditional binary operator expected
remote: hooks/pre-receive: line 8: expected `)'
remote: hooks/pre-receive: line 8: syntax error near `"hw1312@qq.com")'
remote: hooks/pre-receive: line 8: ` if [[ ($author_name == "yuesha" && $
author_email!= "hw1312@qq.com") ||'
remote: hooks/pre-receive: line 8: conditional binary operator expected
remote: hooks/pre-receive: line 8: expected )' remote: hooks/pre-receive: line 8: syntax error near "hw1312@qq.com")'
remote: hooks/pre-receive: line 8: ` if [[ ($author_name == "yuesha" && $
author_email!= "hw1312@qq.com") ||'
remote: hooks/pre-receive: line 8: conditional binary operator expected
remote: hooks/pre-receive: line 8: expected )' remote: hooks/pre-receive: line 8: syntax error near "hw1312@qq.com")'
remote: hooks/pre-receive: line 8: ` if [[ ($author_name == "yuesha" && $
author_email!= "hw1312@qq.com") ||'
remote: hooks/pre-receive: line 8: conditional binary operator expected
remote: hooks/pre-receive: line 8: expected )' remote: hooks/pre-receive: line 8: syntax error near "hw1312@qq.com")'
remote: hooks/pre-receive: line 8: ` if [[ ($author_name == "yuesha" && $
author_email!= "hw1312@qq.com") ||'
用 gitolite
管控
然后我就在想啊,我以前学到过一个 git
的工具,gitolite
之前说这个软件是用来对用户进行权限管控的,是不是能解决我的问题呢?
下载……安装……
这个有一个叫做 admin
的 git
项目,clone
下来之后,修改权限信息,传入成员公钥,就可以实现管控了。
但是这里我有点迷糊。
真的能实现管控嘛?
我试着创建了一个仓库,设置了权限之后,另一个目录把这个仓库项目拉下来,之后提交,依然是可以提交的!
我突然发现——
GIT
是可以自己设置用户名和密码的!!!
这就很糟糕了,成员一样可以随意修改自己的用户名,然后提交在同一个项目当中(毕竟这个项目他肯定有公钥,是合作开发的)
这样我们从远端拉取下来的 git
历史记录里,依然是那个“假”成员提交的信息。
所以,gitolite
管控对于我这个需求也是没有意义的了……
AI问计
我在这个天工的模型AI里问了问,给了我一些答案,但是我还是摸不着头脑……
但是吧,其实AI在这个时候已经给我答案了,只不过我这时候还看不懂……
一头雾水……
如果有人故意冒充别人在Git中进行操作,这可能会导致代码库的安全性受到威胁。为了防止这种情况的发生,可以采取以下措施:
1. 使用强密码和多因素身份验证
确保每个用户都使用强密码,并启用多因素身份验证(MFA)。这增加了攻击者冒充他人的难度,因为他们不仅需要密码,还需要访问用户的其他身份验证因素,如手机验证码或硬件令牌。
2. 限制访问权限
在Git仓库中,根据用户的角色和职责,限制他们的访问权限。例如,只允许特定的开发人员或团队有权访问和修改生产环境相关的分支,从而减少潜在的安全风险。
3. 使用SSH密钥进行身份验证
使用SSH密钥对进行身份验证,而不是简单的用户名和密码。SSH密钥提供了更高的安全性,因为私钥存储在用户的本地机器上,攻击者很难获取。
4. 监控和审查提交历史
定期监控和审查Git仓库的提交历史,特别是对于敏感分支。如果发现异常的提交或未经授权的访问,应立即采取措施,如撤销访问权限或回滚到之前的安全版本。
5. 使用GPG签名
GPG签名可以用于验证提交的真实性。通过为每个提交添加GPG签名,可以确保提交的作者身份是真实的,并且代码在传输和存储过程中没有被篡改。
6. 实施IP限制
如果可能,实施IP限制,只允许来自特定IP地址或IP地址范围的访问。这可以防止攻击者从不受信任的网络环境中访问Git仓库。
7. 教育和培训
对开发团队进行安全意识培训,教育他们如何识别和防止冒充攻击。这包括不共享密码、不点击可疑链接以及如何识别钓鱼邮件等。
8. 定期备份和恢复
定期备份Git仓库,以防止数据丢失和恢复受损的仓库。确保备份存储在安全的位置,并采取适当的措施来保护备份数据的安全性。
9. 使用代码审查工具
使用代码审查工具,如Gerrit或Pull Requests,对提交的代码进行审查。这可以帮助发现潜在的安全问题和冒充行为。
10. 审计和日志
Git提供了详细的日志记录和审计功能,可以追踪每一次代码的修改和提交。开发人员可以查看日志,了解每个提交的细节,及时发现和解决代码安全问题。
通过上述措施,可以大大降低攻击者冒充他人在Git中进行恶意操作的风险。同时,保持系统和软件的更新,以及遵循最佳实践,也是确保Git仓库安全的重要步骤。
柳暗花明
就在我一筹莫展的时候,翻 git
大佬,廖雪峰大佬的博客的时候,看到了一句话。
什么办法呢??
既然都说肯定有,那我就去看各种评论区,毕竟评论区的大佬才是真牛逼。
然后在下面看到了这个
点开了这个链接,看到这位大佬的文章,很优秀!
https://spencerwoo.com/blog/wait-this-is-not-my-commit
就很棒!
用这里提到的GPG签名,就可以完全解决我的问题了。
GPG签名方法
下载GPG
首先去到官网:https://gpg4win.org/index.html
找到Gpg4win
的下载链接
像我这种穷鬼肯定是直接免费下载了啊
然后点击$0
,点击Download
就开始下载了
安装并生成你的OpenPGP证书
下载完成之后,安装其实就是很傻瓜式的了
一路默认值回车就行
然后会让你打开个应用客户端,叫Kleopatra
(这下面是我创建的密钥,你没有很正常)
https://spencerwoo.com/blog/wait-this-is-not-my-commit
如果是这个大佬的文章步骤的话,我个人觉得还是很繁琐的(我试过一次,要敲命令),所以我一般用图形化的方式来创建密钥
首先,打开”文件“菜单,创建一个OpenPGP
密钥对(就是所谓的GPG
证书)
输入名字和邮箱地址,然后回车(这里可以设置密码,那样会更安全,我演示就不设置了)
这里的高级设置里可以处理一些证书加密方式啊,检查更新之类的,不用管,直接点OK
就行
就生成了一个证书
怎么样,,是不是超简单
导出证书ID(GPG 私钥 ID)
这里的证书ID,其实就是上面图片弹框出来的这个,但没法复制,不要紧,下面教你怎么复制导出。
点开细节(注意,不是导出)
可以查看并且复制这里的证书指纹(大佬文章说的GPG 私钥 ID
)
给git
配置
接下来需要将这个编号作为配置值写入到git
里面,当然,你可以写全局,也可以写入单个项目里
二者任选其一即可
以下是全局配置:
// 设置GPG私钥ID
git config --global user.signingkey 换成你的证书ID
// 自动给每个提交commit签名
git config --global commit.gpgsign true
以下是项目配置:
// 设置GPG私钥ID
git config user.signingkey 换成你的证书ID
// 自动给每个提交commit签名
git config commit.gpgsign true
配置好之后,可以查看是否配置成功
这个命令可以在你的项目目录下执行,这样,默认会取你的项目配置,没有的话,去取全局配置
// 获取证书ID
git config user.signingkey
// 获取自动签名开关
git config commit.gpgsign
尝试提交及查看签名
本地项目正常提交
提交的方法跟平时是一模一样的
git commit -m "提交信息"
不同的点在于,如果你的证书是设置了密钥,那么提交的时候会提示你输入密码
如果像我,不设置密码的话,就是在提交那的时间会长了一点点而已。
查看提交的签名信息
这里用--show-signature
参数来展示提交日志列表的签名信息
git log --show-signature
如果你嫌弃这个命令比较麻烦的话,我推荐你设置一个别名,可以参考我这里的设置方法
git config --global alias.signLog 'log --show-signature'
当然,也可以查看单独一条的提交内容
git cat-file -p 提交Hash
可以看到,git
已经将每次提交的内容签名之后,将签名串放到提交正文里了。
上传GitHub
平台的GPG签名验证
我这里是以GitHub
为例进行阐述,如果是GitLab
或者其他代码托管平台,操作也是类似的。
导出公钥内容
首先,我们只有一个ID
肯定是无法让GitHub
识别出来是你自己的。
所以,我们需要将对称加密的公钥导出来
跟上面一样,找到你的证书,点击“细节”
然后在弹出来的窗口里,找到“导出”按钮
在弹出来的框里面,就可以复制这个公钥了。
一定要注意!
这里的整段都要复制,包括前面的:
“-----BEGIN PGP PUBLIC KEY BLOCK-----”
和结尾的:
“-----END PGP PUBLIC KEY BLOCK-----”
一点不能漏
打开GitHub
上传公钥文件
找到你的个人中心
上面的SSH keys
代表你通过ssh
方式上传代码的公钥
我们要配置的是下面,GPG keys
点击这里的New GPG key
按钮
标题可以自己随意编写,但是内容一定要整段复制,一点不能漏
然后需要输入密码
显示保存成功,列表也看到这个公钥了
小绿锁
在将之前内容进行提交版本库之后,需要推送到远端,就是我们的GitHub
平台上
然后就可以看到小绿锁了
很安全
附录-bug及解决方法
1. 提交显示“Unverified”
如上图所示,显示未验证,这里主要是你GitHub
登录的邮箱和签名邮箱不一致导致的
需要去到添加GPG Keys
的位置,找到你的信息
点开,添加你的其他邮箱信息
然后发送邮箱验证码
邮箱收到的邮件,点击验证即可
2. Git
找不到GPG
的签名执行文件
如果是失败了
可以执行下面的命令:
这里的路径,代表
GPG
可执行文件的路径需要包含有执行文件名,如“
D:/GnuPG/bin/gpg.exe
”
git config --global gpg.program 路径
设置后,git
可以找到相关可执行文件进行签名
适用于GPG
程序没有默认安装在默认位置的情况