鱼C论坛

 找回密码
 立即注册
查看: 1465|回复: 1

[已解决]Django中图形验证码(django-simple-captcha) 伪造post?

[复制链接]
发表于 2023-4-24 23:10:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
网上找到的源码,用django-simple-captcha 服务
发现可以伪造个post请求,使用固定的hashkey和captcha 提交,过了验证的?有没优化的办法?

  1. 1
复制代码


django-simple-captcha的安装

pip install django-simple-captcha


在settings.py文件中注册captcha

INSTALLED_APPS = [
    'captcha'
]



在settings.py文件中设置图形验证码的样式


  1. #字母验证码
  2. CAPTCHA_IMAGE_SIZE = (80, 45)   # 设置 captcha 图片大小
  3. CAPTCHA_LENGTH = 4   # 字符个数
  4. CAPTCHA_TIMEOUT = 1   # 超时(minutes)
  5. #加减乘除验证码
  6. CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
  7. CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_null',
  8.      'captcha.helpers.noise_arcs', # 线
  9.      'captcha.helpers.noise_dots', # 点
  10. )
  11. CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
  12. CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
  13. CAPTCHA_TIMEOUT = 1
复制代码



执行数据迁移,在数据表中生成captcha_captchastore表

python manage.py migrate



在urls.py中添加路由

urlpatterns = [
    path('captcha/', include('captcha.urls')),       # 图片验证码 路由
    path('refresh_captcha/', views.refresh_captcha),    # 刷新验证码,ajax
]



下面是源代码。

urls.py文件

  1. from django.urls import path
  2. from django.conf.urls import include
  3. from App.views import IndexView
  4. from App import views
  5. urlpatterns = [
  6.     path('captcha/', include('captcha.urls')),
  7.     path('refresh_captcha/',views.refresh_captcha),
  8.     path('',IndexView.as_view()),
  9. ]
复制代码



views.py文件

  1. from django.shortcuts import render
  2. from django.views.generic import View
  3. from captcha.models import CaptchaStore
  4. from captcha.helpers import  captcha_image_url
  5. from django.http import HttpResponse
  6. import json
  7. # 创建验证码
  8. def captcha():
  9.     hashkey = CaptchaStore.generate_key()   #验证码答案
  10.     image_url = captcha_image_url(hashkey)  #验证码地址
  11.     captcha = {'hashkey': hashkey, 'image_url': image_url}
  12.     return captcha
  13. #刷新验证码
  14. def refresh_captcha(request):
  15.     return HttpResponse(json.dumps(captcha()), content_type='application/json')
  16. # 验证验证码
  17. def jarge_captcha(captchaStr, captchaHashkey):
  18.     if captchaStr and captchaHashkey:
  19.         try:
  20.             # 获取根据hashkey获取数据库中的response值
  21.             get_captcha = CaptchaStore.objects.get(hashkey=captchaHashkey)
  22.             if get_captcha.response == captchaStr.lower():     # 如果验证码匹配
  23.                 return True
  24.         except:
  25.             return False
  26.     else:
  27.         return False
  28. class IndexView(View):
  29.     def get(self, request):
  30.         hashkey = CaptchaStore.generate_key()  # 验证码答案
  31.         image_url = captcha_image_url(hashkey)  # 验证码地址
  32.         captcha = {'hashkey': hashkey, 'image_url': image_url}
  33.         return render(request, "login.html", locals())
  34.     def post(self,request):
  35.         capt=request.POST.get("captcha",None)         #用户提交的验证码
  36.         key=request.POST.get("hashkey",None)          #验证码答案
  37.         if jarge_captcha(capt,key):
  38.             return  HttpResponse("验证码正确")
  39.         else:
  40.             return HttpResponse("验证码错误")
复制代码

  

login.html文件,这里使用 js 动态刷新图形验证码用到了jquery和bootstrap的js,所以,我们提前将jquery和bootstrap放在了static文件夹下。关于如何加载静态文件​

  1. {% load static %}
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5.     <meta charset="UTF-8">
  6.     <title>Title</title>
  7.     <script src="{% static 'bower_components/jquery/dist/jquery.min.js' %}"></script>
  8.     <script src="{% static 'bower_components/bootstrap/dist/js/bootstrap.min.js'%}"></script>
  9. </head>
  10. <body>
  11.     <form action="/" method="post">
  12.         <a href="#" class="captcha">
  13.             <img src="{{ captcha.image_url }}" alt="点击切换" id="id_captcha" >
  14.         </a> <br>
  15.         <input type="text" name="captcha" placeholder="验证码"> <br>
  16.         <input value="{{ captcha.hashkey }}" name="hashkey" type="hidden" id="id_captcha_0">
  17.         <button type="submit" class="btn btn-primary btn-block ">提交</button>
  18.     </form>
  19. <script>
  20.         <!-- 动态刷新验证码js -->
  21.         $(document).ready(function(){
  22.             $('.captcha').click(function () {
  23.                 $.getJSON("refresh_captcha/", function (result) {
  24.                     $('#id_captcha').attr('src', result['image_url']);
  25.                     $('#id_captcha_0').val(result['hashkey'])
  26.                 });
  27.             });
  28.         });
  29. </script>
  30. </body>
  31. </html>
复制代码
最佳答案
2023-4-24 23:15:00
从你的描述中,我了解到你发现了使用固定的hashkey和captcha可以通过伪造POST请求绕过验证码验证。这个问题是由于验证码在后端验证时,固定的hashkey和captcha能够匹配,导致验证通过。为了解决这个问题,你可以在验证时增加一些额外的安全措施。

一个简单的解决方案是对每次请求使用不同的hashkey。这样,即使攻击者获得了一个有效的hashkey和captcha组合,他们也不能绕过验证码验证,因为每次请求的hashkey都不同。这可以通过在视图中实现一个新的功能来完成。例如,你可以在刷新验证码时生成一个新的hashkey,并将其存储在session中。

1. 在 `refresh_captcha` 函数中,将新生成的 hashkey 保存在 session 中:

  1. def refresh_captcha(request):
  2.     new_captcha = captcha()
  3.     request.session['captcha_hashkey'] = new_captcha['hashkey']
  4.     return HttpResponse(json.dumps(new_captcha), content_type='application/json')
复制代码


2. 在 `jarge_captcha` 函数中,检查传入的 hashkey 是否与 session 中存储的相同。如果不同,则表示用户可能伪造了 POST 请求:

  1. def jarge_captcha(request, captchaStr, captchaHashkey):
  2.     if captchaStr and captchaHashkey:
  3.         try:
  4.             if request.session.get('captcha_hashkey', '') != captchaHashkey:
  5.                 return False
  6.             
  7.             # 获取根据hashkey获取数据库中的response值
  8.             get_captcha = CaptchaStore.objects.get(hashkey=captchaHashkey)
  9.             if get_captcha.response == captchaStr.lower():     # 如果验证码匹配
  10.                 return True
  11.         except:
  12.             return False
  13.     else:
  14.         return False
复制代码


注意,在调用 `jarge_captcha` 函数时,需要传入 `request` 参数:

  1. class IndexView(View):
  2.     # ...
  3.     def post(self, request):
  4.         capt = request.POST.get("captcha", None)  # 用户提交的验证码
  5.         key = request.POST.get("hashkey", None)  # 验证码答案
  6.         if jarge_captcha(request, capt, key):
  7.             return HttpResponse("验证码正确")
  8.         else:
  9.             return HttpResponse("验证码错误")
复制代码


通过这种方法,你可以确保每次请求的hashkey都是不同的,从而提高安全性。希望这个解决方案对你有帮助!
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2023-4-24 23:15:00 | 显示全部楼层    本楼为最佳答案   
从你的描述中,我了解到你发现了使用固定的hashkey和captcha可以通过伪造POST请求绕过验证码验证。这个问题是由于验证码在后端验证时,固定的hashkey和captcha能够匹配,导致验证通过。为了解决这个问题,你可以在验证时增加一些额外的安全措施。

一个简单的解决方案是对每次请求使用不同的hashkey。这样,即使攻击者获得了一个有效的hashkey和captcha组合,他们也不能绕过验证码验证,因为每次请求的hashkey都不同。这可以通过在视图中实现一个新的功能来完成。例如,你可以在刷新验证码时生成一个新的hashkey,并将其存储在session中。

1. 在 `refresh_captcha` 函数中,将新生成的 hashkey 保存在 session 中:

  1. def refresh_captcha(request):
  2.     new_captcha = captcha()
  3.     request.session['captcha_hashkey'] = new_captcha['hashkey']
  4.     return HttpResponse(json.dumps(new_captcha), content_type='application/json')
复制代码


2. 在 `jarge_captcha` 函数中,检查传入的 hashkey 是否与 session 中存储的相同。如果不同,则表示用户可能伪造了 POST 请求:

  1. def jarge_captcha(request, captchaStr, captchaHashkey):
  2.     if captchaStr and captchaHashkey:
  3.         try:
  4.             if request.session.get('captcha_hashkey', '') != captchaHashkey:
  5.                 return False
  6.             
  7.             # 获取根据hashkey获取数据库中的response值
  8.             get_captcha = CaptchaStore.objects.get(hashkey=captchaHashkey)
  9.             if get_captcha.response == captchaStr.lower():     # 如果验证码匹配
  10.                 return True
  11.         except:
  12.             return False
  13.     else:
  14.         return False
复制代码


注意,在调用 `jarge_captcha` 函数时,需要传入 `request` 参数:

  1. class IndexView(View):
  2.     # ...
  3.     def post(self, request):
  4.         capt = request.POST.get("captcha", None)  # 用户提交的验证码
  5.         key = request.POST.get("hashkey", None)  # 验证码答案
  6.         if jarge_captcha(request, capt, key):
  7.             return HttpResponse("验证码正确")
  8.         else:
  9.             return HttpResponse("验证码错误")
复制代码


通过这种方法,你可以确保每次请求的hashkey都是不同的,从而提高安全性。希望这个解决方案对你有帮助!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-25 01:01

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表