首页 > 解决方案 > 在 Python 中使用 JWT 破坏访问控制

问题描述

我目前正在开发一个使用 JWT 和 python 创建安全登录的项目。这是一个简单的银行账户应用程序,显示用户名、出生日期和账户余额。在我的代码中,我仍然可以通过更改分配给其他用户的 URL 帐号来访问其他帐户,例如www.domain.com/account/#

如果foo是帐户 16 并且已登录,我可以将数字更改为 17,从而允许我访问bar显示他们信息的帐户,这是一个很大的禁忌。我只想只能看到foo自己的帐户信息。在将数据发送给用户之前,我正在尝试检查 JWT 以确保foo' 是用户并且它是foo' 帐户信息。

传递给函数的 JWT 包含经过身份验证的用户的username, 和logged_in字段(或声明)。我正在尝试通过 URL 中的数字与正在数据库中查找的帐户进行比较。我还试图确保如果 JWT 中的用户名与从数据库返回的用户名不匹配,则引发“您无权访问”异常。

我一直在用头撞墙来解决这个问题。

有效载荷

jwt_token = {
      "username": "foo",
      "logged_in": true
    }

代码

import jwt
import pymysql


class LoggedOutException(Exception):
    '''Raising a LoggedOutException will redirect the user to the login screen
    in the app.
    '''
    pass

def account_lookup(account_id, jwt_token):
    try:
        token = jwt.decode(jwt_token, 'secret', algorithm='HS256')
    except Exception as e:
        raise LoggedOutException('User is not logged in')

    if "logged_in" in token.keys() and token["logged_in"] == True:
        conn = pymysql.connect(
            host='mysql',
            port=3306,
            user='root',
            passwd='letmein',
            db='BankApp'
        )
        cursor = conn.cursor()

        statement = "SELECT username FROM tbl_user WHERE id = " + account_id + ";"
        cursor.execute(statement)
        username_results = cursor.fetchone()

        if username_results:
            username = username_results[0]

            statement = "SELECT balance, dob FROM tbl_account WHERE user_id = " + account_id + ";"
            cursor.execute(statement)
            account_results = cursor.fetchone()

            conn.commit()
            cursor.close()
            conn.close()

            return {
                'balance': account_results[0],
                'dob': account_results[1],
                'username': username
            }
        else:
            raise Exception('Account not found')
    else:
        raise LoggedOutException('User is not logged in')

标签: pythonjwtpymysql

解决方案


我还试图确保如果 JWT 中的用户名与从数据库返回的用户名不匹配,则引发“您无权访问”异常。

在哪里?您的代码中没有这样的逻辑。您使用 JWT 仅根据值检查用户是否已登录,logged_in这并没有多大帮助,因为只有登录的用户应该持有有效的 JWT 令牌,因此此类令牌本身的存在代表已登录用户的状态。

逻辑应该类似于当用户登录时,您为该用户生成一个 JWT 令牌,当该用户注销时,您使该令牌无效(当然,您可能希望稍后考虑实现令牌年龄和刷新) .

您的代码中有 2 个 SQL 查询

statement = "SELECT username FROM tbl_user WHERE id = " + account_id + ";"
statement = "SELECT balance, dob FROM tbl_account WHERE user_id = " + account_id + ";"

但它们仅取决于不属于 JWT 的值(如果变量显然是 a account_id,为什么还要使用name ?这只是令人困惑)。account_iduser_id

简单的解决方案是将account_id(或更恰当地命名user_id)放入 JWT 中,而username不是无论如何都不应该存在(在我看来),并使用该值从数据库中获取数据。


推荐阅读