江苏信安竞赛初赛工作组记事

11月21日,比赛前一天

20日晚还在赶第二天编译原理课的展示,21日上午才开始搞江苏信安竞赛初赛的运维。网站还没有用户和队伍信息,信息要从一个csv文件中导入。也没有题目信息,需要从一个.docx文件里导入,我用的办法是unoconv -f txt a.docx转成文本文件a.txt后用awk处理得到csv格式的文件,之后在Rails项目的lib/tasks目录里创建了一个导入csv格式题目信息的task。在BCTF初赛平台的基础上,还有很多页面、路由和模型等需要调整。

折腾到13:00多把nginx装好运行起来了,14:30选手修改密码截止。

上完编译原理课,吃完晚饭就立刻动身去南京,在高铁上继续工作。
后台的用户管理页面需要添加提交数字段,采用左外连接解决了这个问题。

1
2
3
@users = User.order(:id).joins('left join submissions on submissions.user_id = users.id')
.select('users.*, count(submissions.id) as submissions_count')
.group('users.id').page params[:page]

因为比赛分两天进行,时间不是连续的,之前BCTF初赛时判断比赛开始和结束的代码需要做一些调整。

23:00多下车,到达运维现场已是次日。之后完成了题目分类、场景描述等比较容易实现的需求,还要把题目的答案散列导入到网站使用的数据库中。之后我们核对了各个题目的答案是否正确,准备离开运维现场已是3:30多。

11月22日,比赛第一天

比赛时间为9:00到17:00。9:00不到到达运维现场。

当用户产生一个新提交时,需要在submissions表里添加一条记录,并在usersteams表里更新相关记录的分数,我采用了这样的逻辑:

1
2
3
if correct_submission not exist
insert correct_submission
update score

处理两个并发的正确请求时,这样可能导致correct_submissions被插入两次,分数被增加两次。为此我一开始只用了单进程,开始着手用unique index,即用team_idcorrectness组成的键作为索引,先尝试插入提交记录,如果成功再更新分数。考虑到错误请求很多又用不上,可以使用partial index。到10:29问题解决,开始转用多进程的unicorn作为HTTP服务器。

13:00多网站一直在遭受CC攻击,网站访问很慢,重启unicorn、重启数据库都不见效,服务器(虚拟机)内存只有4G,而内存使用量已经接近用满,unicorn的工作进程一直因为内存问题被SIGKILL,之后重启了服务器,添加了内存。后来发现问题出在/scoreboard页面,被这个页面取消后就好了。之后重构了积分榜页面的实现,取出所有正确提交计算各队伍的分数,并确定解出的题目是哪些。

14:00发现之前积分榜的问题所在,缓存时间被人设置成两秒了……
14:50把积分榜的题目按照分类、分数、题目id排序。
15:44把题目显示前3名改成显示前16名。
16:17在后台的提交管理页面添加了表单,设置了几个查询条件用于筛选提交,方便工作人员审核。
17:00比赛结束,配置的at job生效,nginx原先的反向代理到rails网站的配置被替换成一个静态页面,显示比赛暂停,次日继续。
17:04根据要求修改了各题目分类的场景描述。

11月23日,比赛第二天

8:00多起床,8:40多赶到运维现场,然后把nginx的静态站点配置撤下换成rails网站。

9:00多把后台的提交管理页面改成根据通配符查询了。
工作组考虑封禁作弊队伍的特定题目,即扣掉得到的分数,并且不允许继续提交该题,并在积分榜页面标示出来。
我决定在积分榜页面用红点表示,并把Submissioncorrectness字段从boolean改成integer,允许一个新值-1表示该队伍的此题被封禁,在积分榜页面用红色圆标示。之后开始学习rails和postgresql怎么创建数据库的migration变更字段类型,遇到一些问题,后来猜测是因为partial index对submissions表的依赖导致字段类型无法变更。添加了重建索引的逻辑的migration可用了,之后在后台提交管理的表格里添加了封禁按钮,一支队伍的某一道题被封禁后将扣除相应分数。

13:00多在/admins/submissions添加了根据表格特定列对提交进行排序的功能。

15:00多发现有队伍重新提交了被封禁的题目得分了,原来在产生新的正确提交时只判断了是否存在该队伍同一道题的正确记录,应该改成是否存在正确记录或者被封禁记录。

临近结束网站开始受到了可能是开赛以来最大规模的CC攻击,访问变得很慢;此时我又得到新需求,要仔细核实前若干名队伍的解题情况,因为涉及到获奖和晋级决赛的问题。还好之前BCTF初赛时导出分数为tsv的task仍能使用,导出后用R画了张图。

17:00比赛结束,题目服务器停止服务。之后还有一些零碎的需求,比如关闭积分榜等,之后工作组成员还需要仔细核实可能晋级的队伍的得分、提交等是否有异常。

离开南京,晚上到达北京南站已是23:20多。