mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-10 16:26:06 +01:00
Enforce IF-Match for DELETE requests as well
This commit is contained in:
@@ -308,6 +308,9 @@ class NetBoxModelViewSet(
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
instance = self.get_object_with_snapshot()
|
||||
|
||||
# Enforce If-Match precondition (RFC 9110 §13.1.1)
|
||||
self._validate_etag(request, instance)
|
||||
|
||||
# Attach changelog message (if any)
|
||||
serializer = ChangeLogMessageSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
@@ -322,7 +325,16 @@ class NetBoxModelViewSet(
|
||||
logger = logging.getLogger(f'netbox.api.views.{self.__class__.__name__}')
|
||||
logger.info(f"Deleting {model._meta.verbose_name} {instance} (PK: {instance.pk})")
|
||||
|
||||
return super().perform_destroy(instance)
|
||||
try:
|
||||
with transaction.atomic(using=router.db_for_write(model)):
|
||||
# Re-check the If-Match ETag under a row-level lock to close the TOCTOU window
|
||||
# between the initial check in destroy() and the actual delete.
|
||||
if self._get_if_match(self.request):
|
||||
locked = model.objects.select_for_update().get(pk=instance.pk)
|
||||
self._validate_etag(self.request, locked)
|
||||
super().perform_destroy(instance)
|
||||
except ObjectDoesNotExist:
|
||||
raise PermissionDenied()
|
||||
|
||||
|
||||
class MPTTLockedMixin:
|
||||
|
||||
Reference in New Issue
Block a user