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

Flask+SQLAlchemy子路由认证问题:改URL用户名仍可访问受限路由

Flask登录验证漏洞修复:URL篡改后仍可访问受限路由

问题原因

你的/<user>/home路由仅通过@login_required确保用户已登录,但未验证URL中的用户名参数与当前登录用户是否一致。只要用户处于登录状态,修改URL里的用户名就能绕过权限限制访问他人页面。

修复方案

1. 核心校验逻辑添加

在main_page路由中,对比URL参数<user>与current_user.name,不匹配则拒绝访问:

2. 代码修改细节

首先导入current_user:

from flask_login import login_required, LoginManager, login_user, UserMixin, current_user

然后修改main_page路由:

@app.route('/<user>/home',methods=['GET','POST'])
@login_required
def main_page(user):
    # 校验URL用户名与当前登录用户是否一致
    if user != current_user.name:
        # 可选择重定向到自己的主页,或返回403禁止访问
        return redirect(url_for('main_page', user=current_user.name))
        # 或者返回403:return "无权访问该页面", 403
    return render_template('home.html',user=current_user.name)

3. 其他优化与错误修复

  • 登录跳转优化:登录成功后用url_for生成路由,避免硬编码:
# 原代码
# route = '/'+str(user.name)+'/home'
# return redirect(route)
# 修改为
return redirect(url_for('main_page', user=user.name))
  • 注册路由变量名错误:注册时获取的表单变量是user,但创建用户时用了name=name,会导致NameError,修正:
# 原代码
# user = request.form['user']
# new_user = User(name=name, email=email, password=psw)
# 修改为
username = request.form['user']
new_user = User(name=username, email=email, password=psw)

修改后的完整代码

from flask import Flask, redirect, flash, request, render_template, url_for, make_response
import secrets
from flask_login import login_required, LoginManager, login_user, UserMixin, current_user
from flask_sqlalchemy import SQLAlchemy


app = Flask("test")
secret_key = secrets.token_hex(16)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SECRET_KEY'] = secret_key
db = SQLAlchemy(app)


login_manager = LoginManager(app)
login_manager.init_app(app)

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), unique=True, nullable=False)
    password = db.Column(db.String(120), nullable=False)
    email = db.Column(db.String(100), unique=True, nullable=False)
    games = db.relationship('Game', backref='user', lazy=True)

class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    moves= db.Column(db.String(500), nullable=False)
    status = db.Column(db.String(5), nullable=False)#Si o no
    color = db.Column(db.String(20), nullable=False)


@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
    
@login_manager.unauthorized_handler
def unauthorized():
    return redirect(url_for("login"))


@app.route('/')
def home():
    return render_template('begin.html')

@app.route('/login',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        name= request.form['user']
        psw = request.form['psw']
        user = User.query.filter_by(name=name).first()

        if user and user.password==psw:
            login_user(user)
            # 使用url_for生成路由,避免硬编码
            return redirect(url_for('main_page', user=user.name))
        else:
            return render_template('login.html',resultado='user not found')
    else:
        return render_template('login.html')
    

       
@app.route('/registrar',methods=['GET','POST'])
def registrar():
    if request.method == 'POST':
        username = request.form['user']
        email = request.form['email']
        psw = request.form['psw']
        confirm_psw = request.form['confirm_psw']

        if psw != confirm_psw:
            return render_template('registrar.html',validacion="Passwords do not match")
        
        # 修正变量名错误
        new_user = User(name=username, email=email, password=psw)
        db.session.add(new_user)
        db.session.commit()
        
        return redirect('/login')
    else:
        return render_template('registrar.html')

@app.route('/<user>/home',methods=['GET','POST'])
@login_required
def main_page(user):
    # 核心校验:URL用户名必须与当前登录用户一致
    if user != current_user.name:
        # 重定向到当前用户的主页
        return redirect(url_for('main_page', user=current_user.name))
    return render_template('home.html',user=current_user.name)

说明

  • current_user是Flask-Login提供的全局对象,始终指向当前已登录的用户,不受URL参数篡改影响。
  • 校验不通过时,可根据需求选择重定向到用户自己的主页,或返回403状态码提示无权访问,后者更符合安全规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:18:24