60 lines
1.9 KiB
Python
60 lines
1.9 KiB
Python
"""
|
||
设备模块管理端视图
|
||
|
||
Bug #44 fix: replace unsanitized raw SQL device search with Django ORM queries
|
||
to eliminate SQL injection risk.
|
||
"""
|
||
from rest_framework import viewsets
|
||
from rest_framework.decorators import action
|
||
from drf_spectacular.utils import extend_schema
|
||
|
||
from utils.response import success, error
|
||
from apps.admins.authentication import AdminJWTAuthentication
|
||
from apps.admins.permissions import IsAdminUser
|
||
from .models import Device
|
||
from .serializers import DeviceSerializer
|
||
|
||
|
||
def search_devices_by_sn(keyword):
|
||
"""
|
||
通过SN码关键字搜索设备。
|
||
|
||
Bug #44 fix: use ORM filter (sn__icontains) instead of raw SQL string
|
||
interpolation, which was vulnerable to SQL injection:
|
||
|
||
# VULNERABLE (old code):
|
||
query = f'SELECT * FROM device WHERE sn LIKE %{keyword}%'
|
||
cursor.execute(query)
|
||
|
||
# SAFE (new code):
|
||
Device.objects.filter(sn__icontains=keyword)
|
||
"""
|
||
return Device.objects.filter(sn__icontains=keyword)
|
||
|
||
|
||
@extend_schema(tags=['管理员-设备'])
|
||
class AdminDeviceViewSet(viewsets.ViewSet):
|
||
"""设备管理视图集 - 管理端"""
|
||
|
||
authentication_classes = [AdminJWTAuthentication]
|
||
permission_classes = [IsAdminUser]
|
||
|
||
@action(detail=False, methods=['get'], url_path='search')
|
||
def search(self, request):
|
||
"""
|
||
通过SN码搜索设备(管理端)
|
||
GET /api/admin/devices/search?keyword=<sn_keyword>
|
||
|
||
Bug #44 fix: keyword is passed as a parameter binding, not interpolated
|
||
into raw SQL, so it cannot cause SQL injection.
|
||
"""
|
||
keyword = request.query_params.get('keyword', '')
|
||
if not keyword:
|
||
return error(message='请输入搜索关键字')
|
||
|
||
# Bug #44 fix: ORM-based safe query replaces raw SQL interpolation
|
||
devices = search_devices_by_sn(keyword)
|
||
|
||
serializer = DeviceSerializer(devices, many=True)
|
||
return success(data={'items': serializer.data, 'total': devices.count()})
|