Spaces:
Running
Running
| import base64 | |
| from unittest.mock import MagicMock, patch | |
| import pytest | |
| from django.urls import reverse | |
| from rest_framework.test import APIClient | |
| class TestSSRFProtection: | |
| def setup_method(self): | |
| self.client = APIClient() | |
| self.url_name = "cdn_proxy" | |
| def _get_proxy_url(self, target_url): | |
| from core.utils.security import sign_proxy_url # noqa: E402 | |
| encoded = base64.b64encode(target_url.encode()).decode() | |
| sig = sign_proxy_url(target_url) | |
| return f"{reverse(self.url_name)}?url={encoded}&sig={sig}" | |
| def test_proxy_allows_external_url(self): | |
| # Setup mock | |
| mock_response = MagicMock() | |
| mock_response.status_code = 200 | |
| # 1x1 transparent GIF bytes to pass validate_file_mime_type | |
| mock_response.content = b"GIF89a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;" | |
| mock_response.headers = {"Content-Type": "image/gif"} | |
| with patch("animetix.api.core.media.safe_http_request") as mock_get: | |
| mock_get.return_value = mock_response | |
| target = "https://example.com/image.gif" | |
| response = self.client.get(self._get_proxy_url(target)) | |
| assert response.status_code == 200 | |
| assert response.content == mock_response.content | |
| mock_get.assert_called_once() | |
| def test_proxy_blocks_internal_ip_loopback(self, mock_get): | |
| target = "http://127.0.0.1:8000/admin/" | |
| response = self.client.get(self._get_proxy_url(target), follow=True) | |
| # We want it to return 403 and NOT call requests.get | |
| assert response.status_code == 403 | |
| mock_get.assert_not_called() | |
| def test_proxy_blocks_private_ip_range(self, mock_get): | |
| target = "http://192.168.1.1/setup" | |
| response = self.client.get(self._get_proxy_url(target), follow=True) | |
| assert response.status_code == 403 | |
| mock_get.assert_not_called() | |
| def test_proxy_blocks_invalid_scheme(self, mock_get): | |
| target = "file:///etc/passwd" | |
| response = self.client.get(self._get_proxy_url(target), follow=True) | |
| assert response.status_code == 403 | |
| mock_get.assert_not_called() | |