成都移动端网站建设,保定网站制作排名需要多少钱,小程序开发教程资料,手机网站制作步骤DjangoORM注入
简介
这篇文章中#xff0c;分享一些关于django orm相关的技术积累和如果orm注入相关的安全问题讨论。
攻击效果同数据库注入
从Django-Orm开始
开发角度
Django ORM#xff08;Object-Relational Mapping#xff09;是Django框架中用于处理数…DjangoORM注入
简介
这篇文章中分享一些关于django orm相关的技术积累和如果orm注入相关的安全问题讨论。
攻击效果同数据库注入
从Django-Orm开始
开发角度
Django ORMObject-Relational Mapping是Django框架中用于处理数据库操作的一种机制。它允许开发者使用Python代码来描述数据库模式和执行数据库查询进行数据库操作如创建、读取、更新和删除数据等操作而不需要直接编写SQL语句。通过ORM开发者可以更直观和方便地进行数据库操作同时保持代码的可读性和可维护性。
如果没有ORM作为后端开发的需要写如下代码
# 假设需求背景 Python 开发人员想要编写一个博客网站供人们发布文章并希望向其应用程序添加搜索功能
def search_articles(search_term: str) - list[dict]:results []with get_db_connection() as conn:with conn.cursor() as cursor:cursor.execute(SELECT title, body FROM articles WHERE title LIKE %s, (f%{search_term}%,))rows cursor.fetchall()for row in rows:results.append({title: row[0],body: row[1]})return results
换成ORM模式开发如下
# models/article.py
from django.db import modelsclass Article(models.Model):The data model for Articlestitle models.CharField(max_length255)body models.TextField()class Meta:ordering [title]# serializers/article.py
class ArticleSerializer(serializers.ModelSerializer):How objects of the Article model are serialized into other data types (e.g. JSON)class Meta:model Articlefields (title, body)# views/article.py
class ArticleView(APIView):Some basic API view that users send requests to for searching for articlesdef post(self, request: Request, formatNone):# Returns the search URL parameter if present otherwise it is set to Nonesearch_term request.data.get(search, None)if search_term is not None:articles Article.objects.filter(title__containssearch_term)else:articles Article.objects.all()serializer ArticleSerializer(articles, manyTrue)return Response(serializer.data)
安全角度
Django ORM通常可以防止SQL注入问题因为它会自动对查询参数进行适当的转义和处理。不过如果在使用Django ORM时不小心使用了原生的SQL查询或手动构建了SQL语句也是有SQL注入的问题不过这个不是这篇文章讨论的主要方向。仅作概述
使用ORM的过滤器方法 始终使用Django ORM的过滤器方法而不是手动构建SQL查询。例如
# 安全的查询方式
users User.objects.filter(usernameusername)
避免使用raw()方法 raw()方法允许你编写原生SQL查询但如果不正确处理输入可能会导致SQL注入。
# 不安全的方式
users User.objects.raw(SELECT * FROM auth_user WHERE username %s % username)# 安全的方式
users User.objects.raw(SELECT * FROM auth_user WHERE username %s, [username])
使用Django的QuerySet API 尽量避免使用低级别的数据库APIDjango的QuerySet API提供了足够的功能来执行大多数查询而不需要直接编写SQL
# 安全的方式
users User.objects.filter(email__icontainsexample.com)
使用参数化查询 如果必须使用自定义的SQL查询确保使用参数化查询。
from django.db import connectiondef get_user_by_username(username):with connection.cursor() as cursor:cursor.execute(SELECT * FROM auth_user WHERE username %s, [username])row cursor.fetchone()return row
变量效验 在处理用户输入时始终进行变量效验以确保输入数据的安全和有效性。
from django.db import connectiondef get_user_by_username(username):with connection.cursor() as cursor:# 使用参数化查询防止SQL注入cursor.execute(SELECT * FROM auth_user WHERE username %s, [username])user cursor.fetchone()return user
Django-Orm注入
首先创建一个django应用能够获取book信息 此时的view逻辑为 假设此时后端开发的领导有了如下的要求 需要一个强大的 API 来允许用户按 book 模型中的任何字段进行过滤后续会不断新增表中的字段并且希望 API 无需修改任何代码即可兼容这些更改任务十分紧急.... 这个时候开发十分容易写出如下代码 盲注获取敏感字段
写在前面修改部分代码模拟一个靶场环境
新增flagbook其中isbn为敏感字段flag真是环境flag可能为密码、手机号、token等敏感字段 Book.objects.create(titleflagbook, authorflag book, published_datedate(2020, 4, 15), isbnflag{secret})
修改后端view代码不返回isbn字段调整下代码 通过django filter startwith 进行注入获取flag
具体 django filter语法可参考 https://docs.djangoproject.com/en/5.0/ref/models/querysets/#id4
基础语法查询flagbook数据 盲注获取flag poc
startswith正确时如下 startswith错误时如下 至此我们就可以写脚本获取完整的flag
泄露的条件总结
可以控制filter过滤列ORM支持正则、startswith类似操作表中存在一个隐藏的敏感字段
多表关联的情况
在 Django 中OneToOneField、ManyToManyField 和 ForeignKey 是用来定义模型之间关系的字段类型。每种字段类型表示不同的数据库关系。
OneToOneField
OneToOneField 表示一对一关系。一个模型实例与另一个模型实例之间有且仅有一个关联。
from django.db import modelsclass UserProfile(models.Model):user models.OneToOneField(User, on_deletemodels.CASCADE)bio models.TextField()
在这个例子中每个 UserProfile 实例与一个 User 实例有且只有一个关联。
ManyToManyField
ManyToManyField 表示多对多关系。一个模型实例可以与多个另一个模型实例关联反之亦然。
class Author(models.Model):name models.CharField(max_length100)class Book(models.Model):title models.CharField(max_length100)authors models.ManyToManyField(Author)
在这个例子中一本书可以有多个作者一个作者也可以写多本书。
ForeignKey
ForeignKey 表示多对一关系。一个模型实例可以与多个另一个模型实例关联但反过来每个模型实例只能与一个实例关联。
class Publisher(models.Model):name models.CharField(max_length100)class Book(models.Model):title models.CharField(max_length100)publisher models.ForeignKey(Publisher, on_deletemodels.CASCADE)
在这个例子中一本书只能有一个出版社但一个出版社可以出版多本书。
关系总结
OneToOneField: 一对一关系ManyToManyField: 多对多关系ForeignKey: 多对一关系
demo演示
我们修改model代码如下
from django.db import modelsclass Publisher(models.Model):name models.CharField(max_length100)address models.TextField()def __str__(self):return self.nameclass Category(models.Model):name models.CharField(max_length100)def __str__(self):return self.nameclass Book(models.Model):title models.CharField(max_length200)author models.CharField(max_length100)published_date models.DateField()isbn models.CharField(max_length13, uniqueTrue)publisher models.ForeignKey(Publisher, on_deletemodels.CASCADE)categories models.ManyToManyField(Category)def __str__(self):return self.titleclass BookDetail(models.Model):book models.OneToOneField(Book, on_deletemodels.CASCADE)summary models.TextField()number_of_pages models.IntegerField()def __str__(self):return self.book.title
demo数据如下
import os
import django
import datetime
import randomos.environ.setdefault(DJANGO_SETTINGS_MODULE, MyProject.settings)
django.setup()from BookStore.models import Book, Publisher, Category, BookDetail# 清空旧数据
Publisher.objects.all().delete()
Category.objects.all().delete()
Book.objects.all().delete()
BookDetail.objects.all().delete()# 创建 Publisher 示例数据
publishers [Publisher.objects.create(namefPublisher {i}, addressf{i} Main St) for i in range(1, 6)
]# 创建 Category 示例数据
categories [Category.objects.create(namefCategory {i}) for i in range(1, 6)
]# 创建 Book 示例数据
books [Book.objects.create(titlefBook {i},authorfAuthor {i},published_datedatetime.date(2021, 1, i),isbnf{1234567890123 i},publisherrandom.choice(publishers)) for i in range(1, 6)
]# 添加 Book 到 Category
for book in books:book.categories.add(*random.sample(categories, k2)) # 随机选择两个分类# 创建 BookDetail 示例数据
for book in books:BookDetail.objects.create(bookbook,summaryfThis is the summary for {book.title}.,number_of_pagesrandom.randint(100, 500))print(Demo data created successfully.)
依旧是这个接口逻辑不变 一对一的方式通过bookdetail关联 book 的isbn列数据包 多对一的方式通过book 关联 publishers 的address地址列数据包 多对多的方式通过book 关联 Category的name列数据包 写在最后
其余的一点思考created_by__user__password__regex 类似这种会不会造成数据库redos攻击因为之前学习过redos答案很明显几乎不大可能会。数据库的正则引擎为有限状态向量机。https://xz.aliyun.com/t/14653?