平常面试的时候,相信大家都用过在线笔试系统,那么有了解过它们究竟是如何防作弊的吗?有时明明感觉答得还可以,但最终还是被刷了,大家了解过背后的原因吗?
也许你的分数还可以,但行为记录有问题,这也是会影响面试结果的。也许有些行为是你的无心之过,但还是被莫名其妙的记录了。今天就和大家聊一聊在线笔试的各种监控行为,跟着笔者一起来揭秘在线笔试防作弊黑科技,并手把手教你如何从头打造一个强大的在线考试系统。
一、系统架构设计
我们都知道,笔试结果 = 笔试分数 + 行为记录。
因此,在设计在线笔试系统时,需要综合考虑这两方面的因素,一个基本的笔试流程如下:
基本架构可以分为以下几个模块:
- 前端应用:负责呈现考试界面,处理用户交互,并收集用户行为数据。
- 后端服务:处理考试逻辑、题目管理、用户认证、作弊行为检测等。
- 数据库:用于存储用户信息、考试题目、考试结果和监控数据。
- 视频监控服务:用于实时监控考生行为,包括视频流采集、存储。
- 视频分析服务:用于分析考生行为,包括视频流分析和异常检测。
- 用人单位后台:出题和查看结果,根据考试分数和考生行为,给出综合考试结果。
二、实现在线笔试系统的基本功能
在实现防作弊机制之前,首先需要构建一个最基本的在线笔试系统。
1. 用户认证
- 登录和注册:实现用户注册和登录功能,支持双因素认证(2FA)以加强安全性。
- 身份验证:使用摄像头进行面部识别,确保考试者是本人。
2. 考试界面
- 题目展示:从数据库中获取考试题目并动态渲染到页面上,支持多种题型(选择题、填空题、编程题等)。
- 答题计时:实现倒计时功能,确保考试在规定时间内完成。
- 自动保存:在答题过程中定时自动保存答题进度,防止数据丢失。
3. 考试提交和结果评估
- 答题提交:用户完成考试后,将答案提交到服务器进行保存和评估。
- 结果评估:后端根据题型自动评估考试分数,同时结合 AI 智能分析用户监控录像和用户考试行为,给出各项检测结果,并将它们保存到数据库中,用人单位可在后台查看考试结果。
先来看一下我们的效果图,如下:
欢迎大家点赞和扩展更多有趣的功能。
三、防作弊技术揭秘
首先需要特别说明一下,本文所介绍的是利用前端技术手段监听和防作弊,不包括网络屏蔽、流量分析等外部监控手段。
下面笔者将一一剖析在线笔试的各种防作弊技术。
1. 实时视频监控
从开始流程说起,首先第一个是防止枪手,因此第一个防作弊手段就是登录人脸识别和用户认证,其次考试过程中需要进行实时的视频监控。
- 视频采集:首先需要打开用户摄像头:
<video id="video" autoplay playsinline></video>
<script>
async function startCamera() {
try {
// 请求摄像头权限
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
// 获取 video 元素
const video = document.getElementById('video');
// 将获取的视频流设置为 video 元素的源
video.srcObject = stream;
} catch (error) {
console.error('无法访问摄像头:', error);
}
}
// 启动摄像头
startCamera();
</script>
视频采集上传到数据库的方式有两种,一种是实时上传,另一种是先在本地保存数据,在合适的时机在手动上传。
-
视频实时采集:使用 WebRTC 实时采集用户摄像头数据:
async function startVideoCapture() { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); const videoElement = document.querySelector('#video-preview'); videoElement.srcObject = stream; // 将视频流发送到服务器 sendVideoStream(stream); } function sendVideoStream(stream) { // WebSocket 或其他实时传输方式将视频流发送到服务器 const socket = new WebSocket('ws://your-server-url'); socket.onopen = () => { // 将视频流发送到服务器进行实时分析 }; } startVideoCapture();
实时上传的好处是不用担心中断考试,数据丢失的问题,但缺点是要建立一个websoket连接,对服务有一定的压力;
而手动上传则没有这样的缺陷,先将收集到的数据保存在本地,在合适的时机再利用普通的http上传到服务端,由于我们设计的是轻服务,我们这里采用手动上传的方案。
2. 全屏检测
有了监控,还需要一个十分必要的手段,那就是全屏模式,考试的防作弊检测基本是以此作为基础的,因为非全屏的话,用户会有很多操作空间。
因此绝大多数防作弊在线笔试系统,都会从一开始就让用户强制进入全屏模式,只要考生退出全屏,考试就会中断。
如何强制全屏模式?
你可以通过 Fullscreen API 将当前页面设置为全屏,而不仅仅是最大化窗口:
function openFullscreen() {
if (document.documentElement.requestFullscreen) {
document.documentElement.requestFullscreen();
} else if (document.documentElement.mozRequestFullScreen) { // Firefox
document.documentElement.mozRequestFullScreen();
} else if (document.documentElement.webkitRequestFullscreen) { // Chrome, Safari and Opera
document.documentElement.webkitRequestFullscreen();
} else if (document.documentElement.msRequestFullscreen) { // IE/Edge
document.documentElement.msRequestFullscreen();
}
}
// 调用函数进入全屏
openFullscreen();
进入全屏模式方法是有了,但如何检测用户是否退出全屏了呢?
考虑到不同浏览器的兼容性问题,不同浏览器可能有前缀,你可以考虑为不同的浏览器添加对 webkit
、moz
等前缀的兼容性支持:
document.addEventListener('fullscreenchange', handleFullscreenChange);
document.addEventListener('webkitfullscreenchange', handleFullscreenChange); // Chrome, Safari
document.addEventListener('mozfullscreenchange', handleFullscreenChange); // Firefox
document.addEventListener('MSFullscreenChange', handleFullscreenChange); // IE/Edge
function handleFullscreenChange() {
if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) {
console.log('进入全屏');
} else {
console.log('退出全屏');
}
}
通过以上方式,你可以准确监听到用户进入或退出全屏模式并根据需求执行相应的操作。
退出全屏,通常会中断考试服务,也会有相关次数的记录,因此大家平常面试过程中,一旦进入了面试,不要多次无意义的退出,否则都会有对应的次数记录,对面试结果会有负面影响。
但在实践中发现上述退出全屏有时候会检测不到,这就需要额外的技术手段去辅助,若想更深入的了解,请查看我的项目源码吧。
3. 切屏检测
监听屏幕是否切换(即用户切换到其他标签页或窗口)通常可以通过 visibilitychange
事件来实现。这个事件会在页面的可见性发生变化时触发,允许你检测用户是否在切换标签页。
以下是如何使用 visibilitychange
事件来监听屏幕切换的示例:
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
console.log('页面不可见'); // 用户切换到了其他标签页或其他屏幕
} else {
console.log('页面可见'); // 用户回到当前标签页
}
});
所以大家平常考试过程中不要切屏。
4. 拷贝粘贴监控
另一种行为检测就是用户复制了文本,然后从 AI 答案中帖过来,面对这种场景,就需要检测用户的复制、剪切和粘贴行为。
// 监听拷贝事件
document.addEventListener('copy', (event) => {
console.log('拷贝事件触发');
// 尝试获取拷贝的内容
const copiedData = event.clipboardData ? event.clipboardData.getData('text') : '';
console.log('拷贝的内容:', copiedData);
});
// 监听剪切事件
document.addEventListener('cut', (event) => {
console.log('剪切事件触发');
// 尝试获取剪切的内容
const cutData = event.clipboardData ? event.clipboardData.getData('text') : '';
console.log('剪切的内容:', cutData);
});
// 监听粘贴事件
document.addEventListener('paste', (event) => {
console.log('粘贴事件触发');
// 尝试获取粘贴的内容
const pastedData = event.clipboardData ? event.clipboardData.getData('text') : '';
console.log('粘贴的内容:', pastedData);
});
实际应用中,若想拿到拷贝内容,上面的event.clipboardData
可能会有点兼容性问题,具体方法可前往看源码。
除了监控这些操作以外,另一种方式是直接禁用,不让用户使用,实现代码如下:
document.addEventListener('copy', (e) => {
e.preventDefault();
alert('复制功能已禁用!');
});
document.addEventListener('paste', (e) => {
e.preventDefault();
alert('粘贴功能已禁用!');
});
禁用剪贴板操作:上述代码,通过 JavaScript 禁用复制、剪切和粘贴操作。
所以大家平常考试过程中不要拷贝粘贴。
5. 多屏作弊识别
有这样一种情况,用户电脑连接多个屏幕设备,全屏模式下,照样可以进行作弊。
你以为这样就可以躲避监控么?
答案是否定的。
面对此场景,主要有两种手段检测,一是屏幕大小检测,二是监听鼠标;
-
屏幕大小检测:
- 这种场景是将多个浏览器窗口都塞在一个电脑窗口中,从而实现不可告人的目的。面对这种情况,通常会使用 JavaScript 检测屏幕分辨率和窗口大小,判断是否存在多屏幕情况:
function detectMultipleScreens() { const screenWidth = window.screen.width; const screenHeight = window.screen.height; const windowWidth = window.outerWidth; const windowHeight = window.outerHeight; if (windowWidth < screenWidth || windowHeight < screenHeight) { alert('检测到多屏幕或窗口大小异常!'); reportMultipleScreens(); } } function reportMultipleScreens() { // 上传数据到服务端 } window.addEventListener('resize', detectMultipleScreens);
-
监听鼠标:使用 JavaScript 监听浏览器的
blur
和mouseleave
事件,检测用户是否切换到其他窗口。代码示例如下:// 监听鼠标离开视口 document.addEventListener('mouseleave', () => { console.log('鼠标离开了视口'); }); // 监听窗口失去焦点 window.addEventListener('blur', () => { console.log('窗口失去焦点'); });
所以大家平常不要打开控制台或点击到其他屏幕,只要鼠标不在全屏窗口内,都会触发相关的违规监控事件。
6. 异常行为分析
异常行为通常包含两个方面,除了上面介绍的前端浏览器中违规行为记录,还包括屏幕以外的违规行为,也就是视频监控记录的行为。
-
用户行为监控:收集用户的监控录像数据,并通过机器学习模型分析这些数据,判断用户是否在进行异常操作。
const startRecording = async () => { try { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); setMediaStream(stream); if (videoRef.current) { videoRef.current.srcObject = stream; videoRef.current.play(); } const mediaRecorder = new MediaRecorder(stream); const chunks: Blob[] = []; mediaRecorder.ondataavailable = (event) => chunks.push(event.data); mediaRecorder.onstop = () => { const blob = new Blob(chunks, { type: 'video/webm' }); const url = URL.createObjectURL(blob); // setVideoURL(url); // setIsRecording(false); // 调用外部函数来处理录制完成的 Blob 数据 if (onRecordingComplete) { onRecordingComplete(blob, url); } }; mediaRecorder.start(); mediaRecorderRef.current = mediaRecorder; // setIsRecording(true); } catch (err) { console.error('Error accessing media devices.', err); if (onRecordingError) { onRecordingError(); } } }; const stopRecording = () => { if (mediaRecorderRef.current) { mediaRecorderRef.current.stop(); } if (mediaStream) { mediaStream.getTracks().forEach(track => track.stop()); setMediaStream(null); } if (videoRef.current) { videoRef.current.srcObject = null; } };
上述两个方法,分别记录了浏览器分别开始监控录像和停止监控录像,然后在退出考试时自动上报给服务器,当然也可以实时上报。
上报到视频监控服务平台后,还要对录像提取关键帧,检测分析有无违规行为,上报和分析两个步骤通常是分开的。
四、视频分析服务
通常我们的视频存储服务和分析服务是分开的。下面我们就以一个简单的例子看看 AI 是如何检测用户异常行为的。
通常我们的图像分析以流行且功能强大的 OpenCV
作为框架,但考虑到这是演示教程,而且它们原理是一样的,下面就以 face-api
+ tensorflow
作为演示例子。
它们的实现过程分为两个步骤:一是关键帧提取,二是检测违规行为(检测人脸和打标)
- 关键帧提取:将一段录像视频提取出关键帧(即图片),然后再利用图像分析工具进行分析。
async extractKeyFrames(
videoPath: string,
outputDir: string,
interval: number,
keyFrameCount: number
): Promise<number> {
return new Promise((resolve, reject) => {
const timemarks = Array.from(
{ length: Math.ceil(60 / interval) },
(_, i) => ((i + 1) * interval).toFixed(2)
);
ffmpeg(videoPath)
.on('end', (data: any) => {
console.log('Key frame extraction completed.', data);
resolve(keyFrameCount);
})
.on('error', (err: any) => {
console.error('Error extracting key frames:', err);
reject(err);
})
.screenshots({
count: keyFrameCount, // 提取的关键帧数量
folder: outputDir, // 输出目录
filename: 'keyframe-%i.png', // 输出文件名
timemarks: timemarks, // 从开始每隔 interval 秒提取关键帧
});
});
}
- 检测违规行为: 取到关键帧后,需要对关键帧进行保存,然后加载模型,再利用 face-api.js 对关键帧进行人脸识别。
// 加载模型
async loadModels() {
if (!this.modelsLoaded) {
const modelPath = path.join(__dirname, '../models'); // 模型路径
await faceapi.nets.ssdMobilenetv1.loadFromDisk(modelPath);
await faceapi.nets.faceLandmark68Net.loadFromDisk(modelPath);
await faceapi.nets.faceRecognitionNet.loadFromDisk(modelPath);
this.modelsLoaded = true;
}
}
// 检测人脸
async detectFaces(imagePath: string) {
await this.loadModels();
const image = await loadImage(imagePath);
const detections = await faceapi
.detectAllFaces(image as any)
.withFaceLandmarks()
.withFaceDescriptors();
return detections;
}
最后根据识别出来人脸信息数据进行打标,查看哪些关键帧没有看到人脸的,然后将对应的图片提取出来,然后做上记号。若数量达到了一定的阈值,则报告异常行为。
五、系统功能介绍
系统分为前端和后端,他们的功能集成如下:
- 视频采集:利用
mediaDevices.getUserMedia
采集用户的摄像头数据,同时摄像头探矿是悬浮且可拖动的。
- 考试界面:呈现考试题目,处理用户交互,倒计时记录考试进度。
- 防作弊监控:
- 切屏检测:通过监听
blur
和focus
事件,记录切屏行为。 - 拷贝粘贴监控:禁用或记录剪贴板操作。
- 全屏模式:强制全屏并监控退出全屏行为。
- 更多……
- 切屏检测:通过监听
- 录像监控分析服务:利用 AI 技术手段提取关键帧,检测违规行为。
上述基本是该项目的框架,处于演示的作用,后端没有采用集成服务,人脸识别更是使用比较有计算瓶颈的 Node 服务,真正的应用应该改用 Python 等利于 NLP 分析数据的编程语言和架构。
六、未来的挑战
-
多维违规行为:
- 人脸识别打标:上述项目中只做了人脸识别的功能,可以识别出人脸的信息和位置,但尚没有对其进行打标,后续要扩展的话需要完善。
-
误报与误判:
- 误报率降低:现有的防作弊系统可能会因为切屏检测、面部识别等技术的限制,导致误报情况的发生。如何降低误报率,确保考生在合法操作时不受影响,是一项挑战。
-
用户体验:
- 平衡防作弊与体验:严格的防作弊措施可能会影响考生的考试体验,例如频繁的警告或误判终止考试。因此,如何在防作弊和用户体验之间取得平衡,提供一个既安全又友好的考试环境,是一个关键问题。
-
技术与资源限制:
- 实时分析性能:实时视频分析和行为检测需要大量的计算资源,如何在有限的硬件条件下保证系统的实时性和准确性是一个挑战。
- 网络环境:不同地区的网络质量参差不齐,如何在不稳定的网络环境下保持视频监控和数据传输的稳定性,是需要解决的问题。
-
作弊者的对抗策略:
- AI 对抗:随着人工智能的普及,作弊者可能利用 AI 技术进行对抗,例如利用深度伪造(Deepfake)技术伪装面部。系统需要具备识别和抵御这些高级作弊手段的能力。
七、附言
不管屏幕前的你是不是一名技术人员,希望本篇文章能帮助你了解到求职过程中线上笔试的一些注意事项,以及应该规避的一些行为,也希望对你未来的在线面试有所帮助。
记住,不要切屏、不要复制粘贴、不要打开控制台、不要利用多屏、不要点击其他屏幕让鼠标失活、不要摇头晃脑……总之一句话,不要试图作弊,否则很可能会被拉入企业黑名单。
最后的最后,是本篇文章演示项目的开源地址:github.com/ctq123/onli…
若该项目对你有帮助,也欢迎点赞和留言,也非常期待能此项目能应用到你们的实际项目当中去。