From a1efa1cca4d09265874a6a68b8e080fd779ea90f Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Sat, 30 Nov 2024 10:53:41 +0100 Subject: [PATCH] security.txt expert: fixes, updates to current standards --- docs/user/bots.md | 27 ++++++++++++------- intelmq/bots/experts/securitytxt/expert.py | 21 ++++++++++----- .../bots/experts/securitytxt/test_expert.py | 3 +++ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/docs/user/bots.md b/docs/user/bots.md index 3b1dd0fdf..56edbd158 100644 --- a/docs/user/bots.md +++ b/docs/user/bots.md @@ -3528,7 +3528,10 @@ true. ### SecurityTXT
-SecurityTXT is an initiative to standardize how websites publish their abuse contact information. Currently it is a `draft RFC `_. See this draft RFC for more information on security.txt. This bot automatically looks for security.txt files on a URL or IP, retrieves the primary contact information out of it and adds this to the event. +SecurityTXT is an initiative to standardize how websites publish their abuse contact information. +It is standardized in [RFC 9116 "A File Format to Aid in Security Vulnerability Disclosure"](https://datatracker.ietf.org/doc/rfc9116/). +Refer to the linked document RFC for more information on `security.txt`. +This bot looks for `security.txt` files on a URL or IP, retrieves the primary contact information out of it and adds this to the event. **Requirements** @@ -3540,31 +3543,35 @@ pip3 install -r intelmq/bots/experts/securitytxt/REQUIREMENTS.txt **Module:** `intelmq.bots.experts.securitytxt.expert` -**Parameters (also expects [cache parameters](#cache-parameters)):** +**Parameters** **`url_field`** -The field in the event that contains the URL/IP on which to look for the the security.txt file. +The field in the event that contains the URL/IP on which to look for the the security.txt file. Default: `source.reverse_dns` **`contact_field`** -The field in the event in which to put the found contact details +The field in the event in which to put the found contact details. Default: `source.abuse_contact` -**`only_email_address`** +**`only_email_address`** (bool) Contact details can be web URLs or email addresses. When this value is set to True, it only selects email addresses as contact information. +Default: `true` -**`overwrite`** +**`overwrite`** (bool) -Boolean indicating whether to override existing data in contact_field +Boolean indicating whether to override existing data in contact_field. +Default: `true` -**`check_expired`** +**`check_expired`** (bool) -Boolean indicating whether to check if the security.txt has expired according to its own expiry date +Boolean indicating whether to check if the security.txt has expired according to its own expiry date. +Default: `false` -**`check_canonical`** +**`check_canonical`** (bool) Boolean indicating whether to check if the url is contained in the list of canonical urls. +Default: `false` --- diff --git a/intelmq/bots/experts/securitytxt/expert.py b/intelmq/bots/experts/securitytxt/expert.py index dbbe6509e..27e0299df 100644 --- a/intelmq/bots/experts/securitytxt/expert.py +++ b/intelmq/bots/experts/securitytxt/expert.py @@ -1,9 +1,18 @@ +# SPDX-FileCopyrightText: 2022 Frank Westers, 2024 Institute for Common Good Technology +# +# SPDX-License-Identifier: AGPL-3.0-or-later + from typing import Optional import requests -from securitytxt import SecurityTXT from intelmq.lib.bot import ExpertBot +from intelmq.lib.exceptions import MissingDependencyError + +try: + from securitytxt import SecurityTXT +except ImportError: + SecurityTXT = None class SecurityTXTExpertBot(ExpertBot): @@ -27,8 +36,8 @@ class SecurityTXTExpertBot(ExpertBot): check_canonical: bool = False def init(self): - if not self.url_field or not self.contact_field: - raise AttributeError("Not all required fields are set.") + if SecurityTXT is None: + raise MissingDependencyError('wellknown-securitytxt') def process(self): event = self.receive_message() @@ -38,9 +47,9 @@ def process(self): primary_contact = self.get_primary_contact(event.get(self.url_field)) event.add(self.contact_field, primary_contact, overwrite=self.overwrite) except NotMeetsRequirementsError as e: - self.logger.debug(str(e) + " Skipping event.") + self.logger.debug("Skipping event (%s).", e) except ContactNotFoundError as e: - self.logger.debug(f"No contact found. {str(e)} Continue.") + self.logger.debug("No contact found: %s Continue.", e) self.send_message(event) self.acknowledge_message() @@ -101,4 +110,4 @@ class ContactNotFoundError(Exception): pass -BOT = SecurityTXTExpertBot \ No newline at end of file +BOT = SecurityTXTExpertBot diff --git a/intelmq/tests/bots/experts/securitytxt/test_expert.py b/intelmq/tests/bots/experts/securitytxt/test_expert.py index 6ece5bbef..cf01285ba 100644 --- a/intelmq/tests/bots/experts/securitytxt/test_expert.py +++ b/intelmq/tests/bots/experts/securitytxt/test_expert.py @@ -1,3 +1,5 @@ +# SPDX-FileCopyrightText: 2022 Frank Westers +# # SPDX-License-Identifier: AGPL-3.0-or-later # -*- coding: utf-8 -*- @@ -30,6 +32,7 @@ "source.fqdn": "test.local"} @requests_mock.Mocker() +@test.skip_exotic() class TestSecurityTXTExpertBot(test.BotTestCase, unittest.TestCase): """ A TestCase for the SecurityTXT Expert Bot