You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django自定义认证Session漏洞:未授权访问与URL参数篡改问题

Django自定义认证系统权限漏洞修复

存在的问题

  • 未登录用户直接输入类似127.0.0.1/account/Adam的URL即可进入账户页面,即便该用户未在数据库注册,页面仍会显示对应欢迎信息。
  • 用全局变量auth = False控制权限的方案存在严重缺陷:已登录用户在同一会话中篡改URL末尾的用户名参数,就能显示任意用户名的欢迎信息;且全局变量为服务器共享,多用户登录时会互相干扰。

问题根源

  1. 全局变量不适合会话级状态管理:auth是全局变量,所有访问服务器的用户共用该值,一个用户登录会将所有用户的auth设为True,完全无法实现用户隔离。
  2. 账户视图未做身份校验:account视图直接将URL中的composterName传给模板,既不检查该用户是否存在,也不验证当前登录用户是否与该用户名匹配。
  3. 密码明文存储:注册时直接将密码存入数据库,属于严重安全隐患。

修复方案

1. 改用Django Session存储登录状态

Django自带的Session是会话级存储,每个用户拥有独立Session,是管理登录状态的正确方式。

2. 修改登录视图

验证用户密码正确后,将用户唯一标识存入Session,替代全局变量:

def login(request):
    if request.method == 'POST':
        email = request.POST['Email']
        password = request.POST['Password']
        try:
            user = Composter.objects.get(composterEmail=email)
            # 先暂时用明文验证,后续需替换为哈希验证
            if user.composterPassword == password:
                # 将用户ID和用户名存入session
                request.session['user_id'] = user.id
                request.session['composter_name'] = user.composterName
                return redirect('account', composterName=user.composterName)
            else:
                messages.info(request, '密码错误')
                return redirect('login')
        except ObjectDoesNotExist:
            messages.info(request, '该邮箱未注册')
            return redirect('login')
    return render(request, 'users/login.html')

3. 修改账户视图

先检查Session是否存在登录用户,再验证URL中的用户名是否属于当前登录用户,同时确认用户存在:

def account(request, composterName):
    # 检查是否登录
    user_id = request.session.get('user_id')
    if not user_id:
        return redirect('login')
    
    try:
        current_user = Composter.objects.get(id=user_id)
        # 验证URL中的用户名是否与当前登录用户一致
        if current_user.composterName != composterName:
            messages.info(request, '无权访问该账户')
            return redirect('account', composterName=current_user.composterName)
        
        # 直接传递当前用户信息给模板,不依赖URL参数
        return render(request, 'users/account.html', {'composterName': current_user.composterName})
    except ObjectDoesNotExist:
        # Session中用户ID不存在时,清除Session并跳转登录
        del request.session['user_id']
        messages.info(request, '用户不存在')
        return redirect('login')

4. 修复密码存储问题(关键安全优化)

注册时使用Django的密码哈希函数存储密码,避免明文泄露:

# 先导入哈希工具
from django.contrib.auth.hashers import make_password, check_password

def composter_register(request):
    if request.method == 'POST':
        # 其他字段获取代码不变
        composterName = request.POST['Composter_Name']
        composterEmail = request.POST['Composter_Email']
        composterPassword = request.POST['Composter_Password']
        composterConfirmationPassword = request.POST['Composter_Confirmation_Password']
        composterAddress = request.POST['Composter_Address']
        composterState = request.POST['Composter_State']
        composterCity = request.POST['Composter_City']
        composterZipCode = request.POST['Composter_Zip_Code']
        
        if composterPassword == composterConfirmationPassword:
            if Composter.objects.filter(composterName=composterName).exists():
                messages.info(request,'用户名已被占用!')
                return redirect('composter_register')
            elif Composter.objects.filter(composterEmail=composterEmail).exists():
                messages.info(request,'邮箱已被注册!')
                return redirect('composter_register')
            else:
                # 哈希密码后存储
                hashed_password = make_password(composterPassword)
                composter = Composter(
                    composterName=composterName,
                    composterEmail=composterEmail,
                    composterPassword=hashed_password,
                    composterAddress=composterAddress,
                    composterState=composterState,
                    composterCity=composterCity,
                    composterZipCode=composterZipCode
                )
                composter.save()
                messages.info(request,'注册成功,请登录')
                return redirect('login')
        else:
            messages.info(request,'两次输入的密码不一致!')
            return redirect('composter_register')
    else:
        return render(request, 'users/composter_register.html')

同时修改登录视图的密码验证逻辑,使用哈希校验:

# 登录视图中的密码验证部分替换为:
if check_password(password, user.composterPassword):
    request.session['user_id'] = user.id
    request.session['composter_name'] = user.composterName
    return redirect('account', composterName=user.composterName)
else:
    messages.info(request, '密码错误')
    return redirect('login')

5. 可选:添加登出功能

提供登出选项,清除当前用户的Session:

def logout(request):
    # 清除Session中的用户信息
    request.session.flush()
    return redirect('home')

在urls.py中添加路由:

path('logout/', views.logout, name='logout')

额外建议

  • 可以使用Django的@login_required装饰器简化登录验证逻辑,若使用自定义用户模型,需配置AUTH_USER_MODEL或调整装饰器适配逻辑。
  • 可移除账户URL中的用户名参数,直接从Session获取当前用户信息渲染页面,彻底避免URL篡改问题,例如将路由改为path('account/', views.account, name='account'),视图直接使用Session内的用户数据。

内容的提问来源于stack exchange,提问作者Leo Narido

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 01:01:51