""" 设备模块管理端视图 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= 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()})