1 OJ大概架构
1.0 OJ页面–>WEB服务器(SpringBoot)–>判题机(Linux)
OJ页面将提交的代码封装成json格式发给web服务器端,服务器端接收json获取信息,进行进一步封装,转发给判题机,拆解json数据获得程序代码,运行程序返回结果。
1.1 判题机
IO重定向判断程序是否正确,返回json数据,程序的所有输出重定向到一个文件,将输出的文件与标准答案的文件相比较,判断是否正确。
难点:如何防止恶意代码?
如,提交了C++代码,system("shutdown -s -t 120")
,如果服务器照常运行会使服务器关机,造成严重后果。
1.2 解决方法
- 构造沙箱,记录运行情况
- 黑名单:禁用部分危险函数库的使用(难度较大)
- 关键字过滤(行不通,C语言有强大的宏定义)
- docker(存在安全隐患)
- 白名单(推荐):只给它常用的调用函数,其他的都不能调用,危险操作被禁止,优点:简单方便易实现
2 验证码设计
2.1 朴素思路
服务器端生成验证码字符串和验证码图片,验证码字符串存入session中以便登录时判断验证码是否正确,之后Bufferedimage格式图片通过网络IO写入到response,发送到客户端显示,客户端输入内容再发送到服务器端。
2.2 存在问题
自己手写的验证码很容易被OCR计算机视觉识别,一旦拿到了账号和密码,就可以通过程序自动识别验证码并且通过无限制爬取用户信息。
2.3 解决
验证码的设计是一场计算机视觉和人之间的博弈,是一场反图灵测试,需要的效果是人能够识别,但机器不能够识别,可以在图片生成时,在图片里加一些干扰,如横线、点等干扰OCR的识别。
把原来识别数字改成识别一个等式比如0+3=?,进一步加大机器识别难度。
2.4 jcaptcha
一个开源的验证码生成工具
2.5 前后端分离(Springsecurity结合boot,jwt,Redis,图片验证码实现登录认证权限功能)
- 因为我们是想要实现图片验证码功能,但是我们发现security给我们默认提供的UsernamePasswordAuthentication的filter是不能用的,因为他那里只是对用户名和密码进行校验,因此我们可以这样想,我们使用验证码其实就是在用户名和密码的校验上多了一层而已,因此我们可以在这个过滤器之前再加一个过滤器来进行验证码校验,当然我们也可以通过自定义过滤器继承UsernamePasswordAuthenticationFilter,然后自己把验证码验证逻辑和认证逻辑写在一起,这也是一种解决方式。
- 这里我们便采用加前置图片过滤器CaptchaFilter来提前校验验证码是否正确,这样的话我们是可以继续使用security给我们提供的用户名与密码的过滤器的,然后登录正常或失败我们都可以通过对应的Handler来返回我们特定格式的封装结果数据。
- 因为前后端分离,我们禁用了session,所以我们把验证码放在了redis中,使用一个随机字符串作为key,并传送到前端,前端再把随机字符串和用户输入的验证码提交上来,这样我们就可以通过随机字符串获取到保存的验证码和用户的验证码进行比较了是否正确了。
- 然后因为图片验证码的方式,所以我们进行了encode,把图片进行了base64编码,这样前端就可以显示图片了。