总体设计
后端设计如下:
- index 项目信息
- user 与用户相关的处理
- login 登录
- register 登录
- forget 忘记密码
- logut 登出
- job 任务相关处理
- upload 上传 webshell 文件
- scan 对上传的文件进行扫描
- count 统计当前用户所有的扫描任务与已上传的文件
- search 具体描述某一任务,重点为改任务的结果
其中,仅 index 允许游客访问。
环境为开发环境,上传的是生产环境
User 应用设计
后端设计
参考的项目
User 其 MVT 中的 Module 和 view 部分,参考于基于 Django2.2 可重用登录与注册系统
模型如下:
classUser(models.Model):""" 用户模型 """name=models.CharField(max_length=128,unique=True)password=models.CharField(max_length=256)email=models.EmailField(unique=True)c_time=models.DateTimeField(auto_now_add=True)has_confirmed=models.BooleanField(default=False)def__str__(self):returnself.nameclassMeta:ordering=["-c_time"]verbose_name="用户"verbose_name_plural="用户"classConfirmString(models.Model):""" 邮箱确认模型 """code=models.CharField(max_length=256)user=models.OneToOneField('User',on_delete=models.CASCADE)c_time=models.DateTimeField(auto_now_add=True)def__str__(self):returnself.user.name+": "+self.codeclassMeta:ordering=["-c_time"]verbose_name="确认码"verbose_name_plural="确认码"
其他功能
之后的 View 部分是在基于 Django2.2 可重用登录与注册系统的基础上,补充部分功能:
- 忘记密码
- 重置密码
- django simple captcha refresh
忘记密码
其中重置密码没有独立出来,是属于忘记密码的一部分
相关模型如下:
classConfirmString(models.Model):""" 邮箱确认模型 """code=models.CharField(max_length=256)user=models.OneToOneField('User',on_delete=models.CASCADE)c_time=models.DateTimeField(auto_now_add=True)def__str__(self):returnself.user.name+": "+self.codeclassMeta:ordering=["-c_time"]verbose_name="确认码"verbose_name_plural="确认码"
应用逻辑如下:
- 用户在 user/forget/index 的表单中,添加需要重置密码的用户邮箱
- 若无改用户,则弹出无该用户的警告
- 有该邮箱,则往用户邮箱发送重置密码的链接,此时
- 重置密码的链接大致为 user/forget/confirm/?code=*
- 当 code 是在 ConfirmString 实例中时,将 user 的 has_confirmed,使其在重置密码期间无法登录,之后携
- 带 code 转到 user/forget/change/?code=*
- 若数据库中没有该 code,则拒绝
- user/forget/change/?code=* 中,根据 code 查询一对一匹配的 user,再根据添加的表单修改密码,之后 confirm.user.save() 和 confirm.delete()
django simple captcha refresh
在原项目基础上,需要修改 Template 和 urls.py
- urls.py
captcha.views 内置就有刷新验证码的方法
fromcaptcha.viewsimportcaptcha_refresh# 验证码刷新功能,captcha_refresh为captcha.views内置方法,不需要我们单独写urlpatterns=[...path('refresh/',captcha_refresh),# 点击可以刷新验证码]
- Template
{#刷新验证码的脚本,放到body部分的最后面即可#} <script>$('.captcha').click(function(){$.getJSON('/captcha/refresh/',function(result){$('.captcha').attr('src',result['image_url']);$('#id_captcha_0').val(result['key']);});});</script>
前端设计
前端设计上是基本参考于 bootstrapdoc 5.0 example.
- index.html
- login.html
Job 应用设计
后端设计
Job 的应用设计上,个人在设计时,分为一些几个功能:
- Upload 上传 WebShell 文件
- Count 统计当前用户的上传文件和扫描任务
- Scan 根据 file 文件创建扫描任务
- Search 根据 task_id 查询扫描任务结果
在四个任务中,upload、count、search 设计相对简单,网上参考也相对较多,这里只是简单介绍。而 scan 中的设计相对麻烦,本质上是利用 celery 来处理扫描任务。
upload
在 models 中设计相关模型,且添加装饰器,用于在 admin 可以方便地同时删除文件对象和磁盘中的文件。
- models.py
classModelWithFileField(models.Model):tmp_file=models.FileField(upload_to='./FileUpload/')# 上传目录为 FileUploadfile_user=models.ForeignKey(User,on_delete=models.CASCADE,null=True)''' 值得注意的一点是,FileUpload中已经存在相同文件名的文件时,会对上传文件的文件名重命名 如 1.png 转为 1_fIZVhN3.png 且存储的文件为 1_fIZVhN3.png '''c_time=models.DateTimeField(auto_now_add=True)def__str__(self):returnself.tmp_file.nameclassMeta:ordering=["-c_time"]verbose_name="文件"verbose_name_plural="文件"# 添加装饰器@receiver(post_delete,sender=ModelWithFileField)defdelete_upload_files(sender,instance,**kwargs):files=getattr(instance,'tmp_file')ifnotfiles:returnfname=os.path.join(settings.MEDIA_ROOT,str(files))ifos.path.isfile(fname):os.remove(fname)
- views.py
defupload_file(request):""" 上传文件 :param request: :return: """ifnotrequest.session.get('is_login',None):# 不允许重复登录returnredirect('/user/index/')ifrequest.method=='POST':form=UploadFileForm(request.POST,request.FILES)ifform.is_valid():user_id=request.session.get('user_id')ifuser_id:tmp_user=models.User.objects.get(id=user_id)instance=ModelWithFileField(tmp_file=request.FILES['file'],file_user=tmp_user)instance.save()message="上传成功!\n存储的文件名为:\n"+instance.tmp_file.namereturnrender(request,'job/upload.html',{'message_success':message})else:returnrender(request,'job/upload.html',{'message_warning':"上传失败"})else:form=UploadFileForm()returnrender(request,'job/upload.html',{'form':form})
scan
scan 设计思路如下:
- 利用 celery 和 redis,作为任务调度模块
- 当 scan 成功访问,file 文件存在和无相关任务时,后台分别创建 ScanTaskField 实例和启动 celery 中的 scanTask.delay(file_name=file_name)
- 当 celery 中任务完成,自动更新 ScanTaskField 实例(同样需要添加装饰器)
参考文档 docs.celeryproject.org/en/v5.0.5/django/first-steps-with-django
前端设计
前端设计上同样是基本参考于 bootstrapdoc 5.0 example.
job/count
job/upload
应用配置
邮箱功能需要在 settings.py 中配置如下参数:
在 celery 中设置 worker 为 redis,需要
`docker run --name=redis -d -p 6379:6379 redis`
celery 启动
celery -A ScanWebShell worker -l info
完整代码:https://download.csdn.net/download/pythonyanyan/87390586