From 6ea567db76c0aff1a55bb057177dbb9fdb92d961 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Date: Sun, 31 Mar 2024 22:41:32 +0200 Subject: [PATCH 1/6] Remove scheduled_in and scheduled_time_unit from tasks --- src/backend/tasks/models.py | 11 ----------- src/backend/tasks/queues.py | 12 ------------ src/backend/tasks/serializers.py | 15 ++++----------- src/backend/tests/test_tasks.py | 2 -- 4 files changed, 4 insertions(+), 36 deletions(-) diff --git a/src/backend/tasks/models.py b/src/backend/tasks/models.py index ab48e5958..a26e860aa 100644 --- a/src/backend/tasks/models.py +++ b/src/backend/tasks/models.py @@ -1,5 +1,4 @@ from django.db import models - from framework.models import BaseModel from processes.models import Process from rekono.settings import AUTH_USER_MODEL @@ -38,16 +37,6 @@ class Task(BaseModel): null=True, validators=[FutureDatetimeValidator(code="scheduled_at")], ) - # Amount of time before task execution - scheduled_in = models.IntegerField( - blank=True, - null=True, - validators=[TimeAmountValidator(code="scheduled_in")], - ) - # Time unit to apply to the 'sheduled in' value - scheduled_time_unit = models.TextField( - max_length=10, choices=TimeUnit.choices, blank=True, null=True - ) # Amount of time to wait until repeating the task execution repeat_in = models.IntegerField( blank=True, diff --git a/src/backend/tasks/queues.py b/src/backend/tasks/queues.py index cbcb0568e..39ef2cc18 100644 --- a/src/backend/tasks/queues.py +++ b/src/backend/tasks/queues.py @@ -34,18 +34,6 @@ def enqueue(self, task: Task) -> Job: logger.info( f"[Task] Task {task.id} will be enqueued at {task.scheduled_at}" ) - elif task.scheduled_in and task.scheduled_time_unit: - delay = {task.scheduled_time_unit.lower(): task.scheduled_in} - task.enqueued_at = timezone.now() + timedelta(**delay) - job = queue.enqueue_in( - timedelta(**delay), - self.consume, - task=task, - on_success=self._scheduled_callback, - ) - logger.info( - f"[Task] Task {task.id} will be enqueued in {task.scheduled_in} {task.scheduled_time_unit}" - ) else: task.enqueued_at = timezone.now() job = queue.enqueue( diff --git a/src/backend/tasks/serializers.py b/src/backend/tasks/serializers.py index 41a9c62b5..86afc3720 100644 --- a/src/backend/tasks/serializers.py +++ b/src/backend/tasks/serializers.py @@ -1,10 +1,9 @@ from typing import Any, Dict, cast from django.core.exceptions import ValidationError -from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField - from processes.models import Process from processes.serializers import SimpleProcessSerializer +from rest_framework.serializers import ModelSerializer, PrimaryKeyRelatedField from targets.models import Target from targets.serializers import SimpleTargetSerializer from tasks.models import Task @@ -57,8 +56,6 @@ class Meta: "intensity", "executor", "scheduled_at", - "scheduled_in", - "scheduled_time_unit", "repeat_in", "repeat_time_unit", "creation", @@ -99,13 +96,9 @@ def validate(self, attrs: Dict[str, Any]) -> Dict[str, Any]: "process": "Invalid task. Process or configuration is required", } ) - for field, unit in [ - ("scheduled_in", "scheduled_time_unit"), - ("repeat_in", "repeat_time_unit"), - ]: - if not attrs.get(field) or not attrs.get(unit): - attrs[field] = None - attrs[unit] = None + if not attrs.get("repeat_in") or not attrs.get("repeat_time_unit"): + attrs["repeat_in"] = None + attrs["repeat_time_unit"] = None return super().validate(attrs) def create(self, validated_data: Dict[str, Any]) -> Task: diff --git a/src/backend/tests/test_tasks.py b/src/backend/tests/test_tasks.py index 205aebd38..cbb325dd9 100644 --- a/src/backend/tests/test_tasks.py +++ b/src/backend/tests/test_tasks.py @@ -19,7 +19,6 @@ "configuration_id": 25, "intensity": Intensity.SNEAKY.name.capitalize(), } -invalid_task4 = {**task1, "scheduled_in": -1, "scheduled_time_unit": TimeUnit.MINUTES} class TaskTest(ApiTest): @@ -122,7 +121,6 @@ class TaskTest(ApiTest): ApiTestCase(["admin1", "auditor1"], "post", 400, invalid_task1), ApiTestCase(["admin1", "auditor1"], "post", 400, invalid_task2), ApiTestCase(["admin1", "auditor1"], "post", 400, invalid_task3), - ApiTestCase(["admin1", "auditor1"], "post", 400, invalid_task4), ApiTestCase(["admin2", "auditor2", "reader1", "reader2"], "post", 403, task1), ApiTestCase( ["admin1"], From 013fd32732d9565dd06c592c52b32dca51484a05 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Date: Sun, 31 Mar 2024 22:43:44 +0200 Subject: [PATCH 2/6] Fix code style --- src/backend/http_headers/models.py | 6 ++++-- src/backend/parameters/models.py | 6 ++++-- src/backend/security/validators/input_validator.py | 8 ++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/backend/http_headers/models.py b/src/backend/http_headers/models.py index 5fdc12283..be19fb653 100644 --- a/src/backend/http_headers/models.py +++ b/src/backend/http_headers/models.py @@ -26,10 +26,12 @@ class HttpHeader(BaseInput): null=True, ) key = models.TextField( - max_length=100, validators=[Validator(Regex.NAME.value, code="key", deny_injections=True)] + max_length=100, + validators=[Validator(Regex.NAME.value, code="key", deny_injections=True)], ) value = models.TextField( - max_length=500, validators=[Validator(Regex.TEXT.value, code="value", deny_injections=True)] + max_length=500, + validators=[Validator(Regex.TEXT.value, code="value", deny_injections=True)], ) filters = [BaseInput.Filter(type=str, field="key")] diff --git a/src/backend/parameters/models.py b/src/backend/parameters/models.py index df6e4d60c..581b60d4d 100644 --- a/src/backend/parameters/models.py +++ b/src/backend/parameters/models.py @@ -16,7 +16,8 @@ class InputTechnology(BaseInput): Target, related_name="input_technologies", on_delete=models.CASCADE ) name = models.TextField( - max_length=100, validators=[Validator(Regex.NAME.value, code="name", deny_injections=True)] + max_length=100, + validators=[Validator(Regex.NAME.value, code="name", deny_injections=True)], ) version = models.TextField( max_length=100, @@ -69,7 +70,8 @@ class InputVulnerability(BaseInput): Target, related_name="input_vulnerabilities", on_delete=models.CASCADE ) cve = models.TextField( - max_length=20, validators=[Validator(Regex.CVE.value, code="cve", deny_injections=True)] + max_length=20, + validators=[Validator(Regex.CVE.value, code="cve", deny_injections=True)], ) filters = [ diff --git a/src/backend/security/validators/input_validator.py b/src/backend/security/validators/input_validator.py index 6cfb463ab..cc47e48fb 100644 --- a/src/backend/security/validators/input_validator.py +++ b/src/backend/security/validators/input_validator.py @@ -32,7 +32,7 @@ def __init__( code: str | None = None, inverse_match: bool | None = ..., # type: ignore flags: RegexFlag | None = None, - deny_injections: bool = False + deny_injections: bool = False, ) -> None: self.deny_injections = deny_injections super().__init__(regex, message, code, inverse_match, flags) @@ -46,7 +46,11 @@ def __call__(self, value: str | None) -> None: invalid_input = ( not bool(regex_matches) if self.inverse_match else bool(regex_matches) ) - is_injection = bool(re.fullmatch(Regex.IS_INJECTION, value)) if self.deny_injections else False + is_injection = ( + bool(re.fullmatch(Regex.IS_INJECTION, value)) + if self.deny_injections + else False + ) if invalid_input or is_injection: logger.warning( f"[Security] Invalid value that doesn't match the regex '{self.regex}'" From 4e36efa72e6110df20fba499949f0464de7a716c Mon Sep 17 00:00:00 2001 From: Pablo Santiago Date: Sun, 31 Mar 2024 22:46:42 +0200 Subject: [PATCH 3/6] Fix code style --- src/backend/security/validators/input_validator.py | 2 +- src/backend/tests/test_tasks.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/security/validators/input_validator.py b/src/backend/security/validators/input_validator.py index cc47e48fb..940a0546d 100644 --- a/src/backend/security/validators/input_validator.py +++ b/src/backend/security/validators/input_validator.py @@ -47,7 +47,7 @@ def __call__(self, value: str | None) -> None: not bool(regex_matches) if self.inverse_match else bool(regex_matches) ) is_injection = ( - bool(re.fullmatch(Regex.IS_INJECTION, value)) + bool(re.fullmatch(Regex.IS_INJECTIO.value, value)) if self.deny_injections else False ) diff --git a/src/backend/tests/test_tasks.py b/src/backend/tests/test_tasks.py index cbb325dd9..814b651e5 100644 --- a/src/backend/tests/test_tasks.py +++ b/src/backend/tests/test_tasks.py @@ -1,7 +1,6 @@ from typing import Any from executions.enums import Status -from tasks.enums import TimeUnit from tests.cases import ApiTestCase from tests.framework import ApiTest from tools.enums import Intensity From 452d4288105fe11fa3e5e84b33767f250ece76b6 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Date: Sun, 31 Mar 2024 22:48:17 +0200 Subject: [PATCH 4/6] Fix typo --- src/backend/security/validators/input_validator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/security/validators/input_validator.py b/src/backend/security/validators/input_validator.py index 940a0546d..abee1661c 100644 --- a/src/backend/security/validators/input_validator.py +++ b/src/backend/security/validators/input_validator.py @@ -47,7 +47,7 @@ def __call__(self, value: str | None) -> None: not bool(regex_matches) if self.inverse_match else bool(regex_matches) ) is_injection = ( - bool(re.fullmatch(Regex.IS_INJECTIO.value, value)) + bool(re.fullmatch(Regex.IS_INJECTION.value, value)) if self.deny_injections else False ) From 70502b8e81601e722e4e856be5db421ac73ab004 Mon Sep 17 00:00:00 2001 From: Pablo Santiago Date: Sun, 31 Mar 2024 23:05:47 +0200 Subject: [PATCH 5/6] Remove debug input --- src/backend/tests/cases.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/backend/tests/cases.py b/src/backend/tests/cases.py index 21eb26f84..6eb255574 100644 --- a/src/backend/tests/cases.py +++ b/src/backend/tests/cases.py @@ -60,11 +60,7 @@ def test_case(self, *args: Any, **kwargs: Any) -> None: data=self.data, format=self.format, ) - try: - self.tc.assertEqual(self.status_code, response.status_code) - except Exception as ex: - input(response.content) - raise ex + self.tc.assertEqual(self.status_code, response.status_code) if self.expected is not None: content = json.loads((response.content or "{}".encode()).decode()) if isinstance(self.expected, dict): From 971bf31c191595380867edc3193778db5c9a58ae Mon Sep 17 00:00:00 2001 From: Pablo Santiago Date: Mon, 1 Apr 2024 00:59:58 +0200 Subject: [PATCH 6/6] Fix input validation --- src/backend/security/validators/input_validator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/security/validators/input_validator.py b/src/backend/security/validators/input_validator.py index abee1661c..738a60efd 100644 --- a/src/backend/security/validators/input_validator.py +++ b/src/backend/security/validators/input_validator.py @@ -21,7 +21,7 @@ class Regex(Enum): PATH_WITH_QUERYPARAMS = r"[\w\.\-_/\\#?&%$]{0,500}" CVE = r"CVE-\d{4}-\d{1,7}" SECRET = r"[\w\./\-=\+,:<>¿?¡!#&$()@%\[\]\{\}\*]{1,500}" - IS_INJECTION = r"[^;\"&$]*" + INJECTION = r"[;\"&$]+" class Validator(RegexValidator): @@ -47,13 +47,13 @@ def __call__(self, value: str | None) -> None: not bool(regex_matches) if self.inverse_match else bool(regex_matches) ) is_injection = ( - bool(re.fullmatch(Regex.IS_INJECTION.value, value)) + bool(re.findall(Regex.INJECTION.value, value)) if self.deny_injections else False ) if invalid_input or is_injection: logger.warning( - f"[Security] Invalid value that doesn't match the regex '{self.regex}'" + f"[Security] Value '{value}' doesn't match the allowed regex" ) raise ValidationError(self.message, code=self.code, params={"value": value})