python - 在 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')
解决方案
我还试图确保如果 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_id
user_id
简单的解决方案是将account_id
(或更恰当地命名user_id
)放入 JWT 中,而username
不是无论如何都不应该存在(在我看来),并使用该值从数据库中获取数据。
推荐阅读
- c++ - 用于图形 API 的 Microsoft C++ Rest SDK
- python - 如何添加 python 字典中使用的新键?
- node.js - 无法在 AWS Elastic beanstalk 上部署节点映像(NestJS)
- curl - 从 sourceforge 获取直接下载链接
- arrays - 比较重复的列和行
- cryptocurrency - 如何为我的应用考虑代币经济学?
- sql - 基于可选条件的 SELECT 查询在目标表中的 NULL 上失败
- algorithm - 在不触及 html 属性的情况下替换单词列表的最有效方法是什么?
- android - 如何阻止 webview 在 android 中刷新?
- sql - 与视图结果相比,如何最好地检查已导出到 xlsx 文件的 nvarchar 字段的完整性?