一个简单的作业提交平台

这个项目大概是上星期五晚开始做的,之所以现在才写这篇文,纯粹是因为没有时间,刚好今早把高数写完了, CAD 又不想动,于是便借此时间简单总结一下。

首先写这个网站的起因是邮箱发作业实在是过于麻烦,看着隔壁广州计算机的都用着 Matrix(一个我们大学学生运维的 OJ ,即在线判题平台),一点提交就有结果,而我们交作业却是原始的上交源文件和运行截图,我也无何办法,谁让我们是材料计算机呢(并无歧视材料的意思,只是单纯地憎恶化学,高中本就没选)。等我和课代表商量的时候,他也表示早已被不按规则提交的作业搞得苦不堪言(乐),想了想,虽然费劲写个小破站有些浪费时间,与大卷之势相悖,但毕竟也算有点意思,便做了下去。


开始

最初的文件是直接抄中国人民公安大学的一道信安题的,代码附上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
header("Content-type: text/html;charset=utf-8");
error_reporting(0);
//设置上传目录
define("UPLOAD_PATH", dirname(__FILE__) . "/upload/");
// define("UPLOAD_URL_PATH", str_replace($_SERVER['DOCUMENT_ROOT'], "", UPLOAD_PATH));
if (!file_exists(UPLOAD_PATH)) {
mkdir(UPLOAD_PATH, 0755);
}
if (!empty($_POST['submit'])) {
if (!$_FILES['file']['size']) {
echo "<script>alert('请添加上传文件')</script>";
} else {
$name = basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], UPLOAD_PATH . $name)) {
echo "<script>alert('上传成功')</script>";
echo "上传文件相对路径<br>" . "/upload/" . $name;
} else {
echo "<script>alert('上传失败')</script>";
}
}
}
$myfile = fopen("log.txt", "a") or die("Unable to open file!");
fwrite($myfile,$_SERVER["REMOTE_ADDR"]);
$txt="\n";
fwrite($myfile,$txt);
fclose($myfile);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PPSUC 文件上传 - js前端验证</title>
</head>
<body>
<h1>PPSUC 文件上传 - js前端验证</h1>
<p>本题从PPSUC窃取得来</p>
<form action="" method="post" enctype="multipart/form-data" onsubmit="return checkfilesuffix()">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>
<script>
function checkfilesuffix()
{
var file=document.getElementsByName('file')[0]['value'];
if(file==""||file==null)
{
alert("请添加上传文件");
return false;
}
else
{
var whitelist=new Array(".jpg",".png",".gif");
var file_suffix=file.substring(file.lastIndexOf("."));
if(whitelist.indexOf(file_suffix) == -1)
{
alert(":(该文件不允许上传:(");
return false;
}
}
}
</script>
</body>
</html>

这题考的是 JS 前端验证的绕过,解出题后的我深知前端验证的不可靠,便知道敏感的操作限制应该加在后端了。但毕竟前端也得有点拦一下不是,否则累死后端不说,代码冗杂也是一个问题。上百度抄一抄,后端的后缀限制也完成了(解释一下,之所以限制文件后缀,一方面是因为提交的文件格式问题,一方面是安全问题,假若给你上传了一个 php 木马而我又没加限制访问的情况下, RCE 就是件很简单的事情了,之后你可以查看和操作任意权限允许的文件,总之是很危险的事)。
在完成后缀的限制后,我又加了如下的诸多验证:

文件大小非空且大小须小于512KB(后来改成了666KB) :否则给你当网盘使那我服务器也是难顶,而且源文件最大也没什么可能超过 10 KB,截图预计也是几十 KB
upload目录的访问限制:可不能给随便偷了作业看
姓名不能为空且不多于4个字:这个问过课代表,我们班的名字没有超过 3 个字的
学号范围:086-199 ,但有一个人的学号孤悬在外,有些奇怪(乐)
姓名和学号的联合验证:这个是前两天才加上去的,主要是忘了之前的军事课有份名单(但是那位竟然是没有的,再处理吧)

后端处理逻辑重构

一开始我是设置先新建(姓名+学号)的一个目录,再逐个文件进行判断,若符合条件则放进目录里,但这就会引发一个问题,如果有文件不符合条件的话目录仍会存在,而为了防止有意或是无意的重复上传导致原文件被覆盖,我又设置了若目录已存在则不能继续放文件,于是我在上机课的时候改成了先全部验证通过再上传目录。

管理员端

毕竟作业也不是我收的,如果每次都要我来登录服务器下载未免也太过麻烦,于是我抄了段多级目录压缩的代码,在管理员通过验证后将提交上的作业打包成了个 zip ,再存储于基于 SHA256 算法生成的时间哈希值命名的目录中,这样大概便无法被直接扫描出来了。
管理员的登录验证我采用的是RSA公钥加密出的一段 base64 编码的字符串,若在后端用私钥解密后得到明文”admin”便通过验证,但想了想似乎没必要用非对称加密,有空再改。
除此之外,我还加了个验证码,但是在 Firefox 上似乎不能正常刷新,于是就没加在学生端了。

前端的样式

这个是我最无奈的地方,个人的美术功底着实是捞得亚匹,布局和配色搞得乱七八糟,在此就希望同学多多与我反馈了。

一些问题

开源

本来打算上传到 github 的,但是还没处理好重要文件的放置(总不能学号和姓名也开源不是)。

更新:项目已发布于
https://github.com/weyung/A-simple-homework-submission-platform

JQuery

说来有些可笑,我一开始是用原生 Javescript 写的前端,代码繁琐且在使用 ajax 的时候被异步坑了一把:我写了一个函数调用后端的接口然后 return 数据,却发现主函数中得到的结果总是 undefined ,后来才知道是先 return 再接收数据,晕。而用 JQuery 一个回调函数就搞定了,虽然 JQuery 似乎的确有些过时,但有空再看 React、Vue 什么的吧。

SSH

之前是想用 VSCode 写代码的,但是 SSH 一直显示什么管道不存在,直到今晚才瞎搞接通了。用宝塔的在线文本编辑器写了一个星期的代码,现在终于能有舒服点的高亮了。至于调试也是个问题,因为懒得搭本地环境,我至今还是肉眼调试,有空也得处理下。

作者

未央

发布于

2021-12-19

更新于

2024-07-02

许可协议

评论