Skip to content

Commit 735f415

Browse files
zuosebix
authored andcommitted
STOMP+SSL-related changes: security fixes + convenience enhancement (+ doc updates/improvements)
doc: a few fixes/improvements ad STOMP bots and *n6* feed lib, bots, doc: only cosmetic/very minor tweaks and comments lib, bots, pkg, doc: drop support for `stomp.py` older than 4.1.12 The affected bots are: *STOMP collector* (`StompCollectorBot` defined in `intelmq.bots.collectors.stomp.collector`) and *STOMP output* (`StompOutputBot` defined in `intelmq.bots.outputs.stomp.output`). Also, in `debian/control`, the `python3-stomp` package name has been fixed (by removing the `.py` suffix). The changelog has been updated appropriately. lib, bots, doc: STOMP/*n6*-related fixes/enhancements, also ad security SSL-related changes -- regarding `intelmq.lib.mixins.StompMixin` and, therefore, also the *STOMP collector* bot (`StompCollectorBot` defined in `intelmq.bots.collectors.stomp.collector`) and the *STOMP output* bot (`StompOutputBot` defined in `intelmq.bots.outputs.stomp.output`) -- have been made: * *Security*-focused: fixed certain security problems which were caused by the fact that certain versions of the `stomp.py` library we need to be compatible with use the `ssl` module's tools in such ways that suffer from certain *security weaknesses*. In particular, `stomp.py` in versions `>=8.0, <8.1` mistakenly creates an `SSLContext` instance with the `check_hostname` flag unset -- an important negative effect of that is that the hostname of the STOMP server is *not* checked during the TLS handshake (making all STOMP communication vulnerable to certain kinds of attacks...). Also, there are weaknesses (caused either by `stomp.py` or by older, yet still supported by IntelMQ, Python versions) of using too old versions of the TLS protocol (namely: 1.0 and 1.1 -- nowadays considered insecure). * *Admin convenience*-focused: from now on, for each of the STOMP bots, you can set the `ssl_ca_certificate` config param to an empty string -- dictating that the SSL tools employed by the `stomp.py`'s machinery will attempt to load the system’s default CA certificates. Thanks to that, administrators of the given IntelMQ instance can be relieved of of the fuss with manual updates of the CA certificate(s) file -- *if* the certificate of the STOMP server can be verified using some of the publicly available CA certificates which are part of nearly all mainstream operating system distributions (this will be the case with the server certificate of the new variant of the *n6* Stream API, that is, the variant with STOMP-login-and-passcode-based authentication). An important part of the implementation of the aforementioned changes is a non-public class, `intelmq.lib.mixins.stomp._StompPyDedicatedSSLProxy` -- which implements a kind of transparent proxy object that wraps the `ssl` attribute of the `stomp.transport` module (originaly set to the `ssl` module object), replacing some of the `ssl` module's tools with their patched variants (note that the `ssl` module itself and all its members are left untouched). The parts of the IntelMQ's documentation related to those STOMP bots + integration with *n6* (including the CERT.PL's "N6 Stomp Stream" feed description) have been updated and improved; also, the changelog has been updated. bots: fix import logic in STOMP collector's module The logic regarding importing of the `stomp.py`'s stuff has been fixed: now the condition of the absence of the `stomp` module (and thus, of the entire library) would not be confused with the condition of the absence of only the `stomp.exception` module (which would mean the presence of a version of that library lacking just the `exception` submodule).
1 parent ba50010 commit 735f415

File tree

10 files changed

+446
-109
lines changed

10 files changed

+446
-109
lines changed

CHANGELOG.md

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
if `auth_by_ssl_client_certificate` is *false*);
2020
- `password` (STOMP authentication passcode, default: "guest"; to be used only
2121
if `auth_by_ssl_client_certificate` is *false*).
22+
- Add the possibility to set the `ssl_ca_certificate` configuration parameter for
23+
`intelmq.bots.collectors.stomp.collector` and/or `intelmq.bots.outputs.stomp.output`
24+
to an empty string - which means that the SSL machinery used for STOMP communication
25+
will attempt to load the system’s default CA certificates (PR#2414 by Jan Kaliszewski).
2226

2327
### Core
2428
- `intelmq.lib.message`: For invalid message keys, add a hint on the failure to the exception: not allowed by configuration or not matching regular expression (PR#2398 by Sebastian Wagner).
@@ -27,7 +31,7 @@
2731
- `intelmq.lib.mixins`: Add a new class, `StompMixin` (defined in a new submodule: `stomp`),
2832
which provides certain common STOMP-bot-specific operations, factored out from
2933
`intelmq.bots.collectors.stomp.collector` and `intelmq.bots.outputs.stomp.output`
30-
(PR#2408 by Jan Kaliszewski).
34+
(PR#2408 and PR#2414 by Jan Kaliszewski).
3135

3236
### Development
3337
- Makefile: Add codespell and test commands (PR#2425 by Sebastian Wagner).
@@ -36,11 +40,16 @@
3640

3741
### Bots
3842
#### Collectors
39-
- `intelmq.bots.collectors.stomp.collector` (PR#2408 by Jan Kaliszewski):
40-
- Add support for authentication based on STOMP login and passcode,
41-
introducing 3 new configuration parameters (see above: *Configuration*).
43+
- `intelmq.bots.collectors.stomp.collector` (PR#2408 and PR#2414 by Jan Kaliszewski):
44+
- Drop support for versions of `stomp.py` older than `4.1.12`.
4245
- Update the code to support new versions of `stomp.py`, including the latest (`8.1.0`);
4346
fixes [#2342](https://github.com/certtools/intelmq/issues/2342).
47+
- Add support for authentication based on STOMP login and passcode, introducing three
48+
new configuration parameters (see above: *Configuration*).
49+
- Add support for loading the system’s default CA certificates, as an alternative to
50+
specifying the CA certificate(s) file path explicitly (see above: *Configuration*).
51+
- Fix (by carefully targeted monkey patching) certain security problems caused by
52+
SSL-related weaknesses that some versions of `stomp.py` suffer from.
4453
- Fix the reconnection behavior: do not attempt to reconnect after `shutdown`. Also,
4554
never attempt to reconnect if the version of `stomp.py` is older than `4.1.21` (it
4655
did not work properly anyway).
@@ -56,27 +65,35 @@
5665
#### Experts
5766

5867
#### Outputs
59-
- `intelmq.bots.outputs.stomp.output` (PR#2408 by Jan Kaliszewski):
60-
- Add support for authentication based on STOMP login and passcode,
61-
introducing 3 new configuration parameters (see above: *Configuration*).
68+
- `intelmq.bots.outputs.stomp.output` (PR#2408 and PR#2414 by Jan Kaliszewski):
69+
- Drop support for versions of `stomp.py` older than `4.1.12`.
6270
- Update the code to support new versions of `stomp.py`, including the latest (`8.1.0`).
71+
- Add support for authentication based on STOMP login and passcode, introducing three
72+
new configuration parameters (see above: *Configuration*).
73+
- Add support for loading the system’s default CA certificates, as an alternative to
74+
specifying the CA certificate(s) file path explicitly (see above: *Configuration*).
75+
- Fix (by carefully targeted monkey patching) certain security problems caused by
76+
SSL-related weaknesses that some versions of `stomp.py` suffer from.
6377
- Fix `AttributeError` caused by attempts to get unset attributes of `StompOutputBot`
6478
(`ssl_ca_cert` et consortes).
6579
- Add coercion of the `port` config parameter to `int`.
6680
- Add implementation of the `check` hook (verifying, in particular, accessibility
6781
of necessary file(s)).
68-
- Add `stomp.py` version check (raise `MissingDependencyError` if not `>=4.1.8`).
82+
- Add `stomp.py` version check (raise `MissingDependencyError` if not `>=4.1.12`).
6983
- Minor fixes/improvements and some refactoring (see also above: *Core*...).
7084

7185
### Documentation
7286
- Add a readthedocs configuration file to fix the build fail (PR#2403 by Sebastian Wagner).
7387
- Add a guide of developing extensions packages (PR#2413 by Kamil Mankowski)
7488
- Update/fix/improve the stuff related to the STOMP bots and integration with the *n6*'s
75-
Stream API (PR#2408 by Jan Kaliszewski).
89+
Stream API (PR#2408 and PR#2414 by Jan Kaliszewski).
7690
- Complete documentation overhaul. Change to markdown format. Uses the mkdocs-material (PR#2419 by Filip Pokorný).
7791

7892
### Packaging
7993
- Add `pendulum` to suggested packages, as it is required for the sieve bot (PR#2424 by Sebastian Wagner).
94+
- `debian/control`: in `Suggests` field, replace ``python3-stomp.py (>= 4.1.9)`` with
95+
``python3-stomp (>= 4.1.12)``, i.e., fix the package name by removing the `.py`
96+
suffix and bump the minimum version to `4.1.12` (PR#2414 by Jan Kaliszewski).
8097

8198
### Tests
8299

debian/control

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Suggests: python3-geoip2 (>= 2.2.0),
5353
python3-pyasn (>= 1.5.0),
5454
python3-pymongo (>= 2.7.1),
5555
python3-sleekxmpp (>= 1.3.1),
56-
python3-stomp.py (>= 4.1.9),
56+
python3-stomp (>= 4.1.12),
5757
python3-pendulum
5858
Description: Solution for IT security teams for collecting and processing security feeds
5959
IntelMQ is a solution for IT security teams (CERTs, CSIRTs, abuse

docs/user/bots.md

Lines changed: 80 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,35 +1176,49 @@ Install the `stomp.py` library from PyPI:
11761176
pip3 install -r intelmq/bots/collectors/stomp/REQUIREMENTS.txt
11771177
```
11781178

1179+
Alternatively, you may want to install it using your OS's native
1180+
packaging tools, e.g.:
1181+
1182+
```bash
1183+
apt install python3-stomp
1184+
```
1185+
1186+
Apart from that, depending on what STOMP server you connect to, you may
1187+
need to obtain, from the organization or company owning the server, one
1188+
or more of the following security/authentication-related resources:
1189+
1190+
* CA certificate file;
1191+
* either: *client certificate* and *client certificate's key* files,
1192+
or: *username* (STOMP *login*) and *password* (STOMP *passcode*).
1193+
1194+
Also, you will need to know an appropriate STOMP *destination* (aka
1195+
*exchange point*), e.g. `/exchange/my.example.org/*.*.*.*`.
1196+
11791197
**Parameters (also expects [feed parameters](#feed-parameters)):**
11801198

11811199
**`server`**
11821200

1183-
(required, string) Hostname of the STOMP server.
1201+
(required, string) STOMP server's hostname or IP, e.g. "n6stream.cert.pl" (which is default)
11841202

11851203
**`port`**
11861204

1187-
(optional, integer) Defaults to 61614.
1205+
(optional, integer) STOMP server's port number (default: 61614)
11881206

11891207
**`exchange`**
11901208

1191-
(required, string) STOMP *destination* to subscribe to, e.g. "/exchange/my.org/*.*.*.*"
1209+
(required, string) STOMP *destination* to subscribe to, e.g. `"/exchange/my.org/*.*.*.*"`
11921210

1193-
**`username`**
1194-
1195-
(optional, string) Username to use.
1211+
**`heartbeat`**
11961212

1197-
**`password`**
1198-
1199-
(optional, string) Password to use.
1213+
(optional, integer) default: 6000
12001214

12011215
**`ssl_ca_certificate`**
12021216

1203-
(optional, string) Path to trusted CA certificate.
1217+
(optional, string) Path to CA file, or empty string to load system's default CA certificates
12041218

12051219
**`auth_by_ssl_client_certificate`**
12061220

1207-
(optional, boolean) Whether to authenticate using TLS certificate. (Set to false for new *n6* auth.) Defaults to true.
1221+
(optional, boolean) Default: true (note: false is needed for new *n6* auth)
12081222

12091223
**`ssl_client_certificate`**
12101224

@@ -1214,6 +1228,14 @@ pip3 install -r intelmq/bots/collectors/stomp/REQUIREMENTS.txt
12141228

12151229
(optional, string) Path to client private key to use for TLS connections.
12161230

1231+
**`username`**
1232+
1233+
(optional, string) Username to use.
1234+
1235+
**`password`**
1236+
1237+
(optional, string) Password to use.
1238+
12171239
---
12181240

12191241
### Twitter (REMOVE?) <div id="intelmq.bots.collectors.twitter.collector_twitter" />
@@ -5127,72 +5149,87 @@ This bot pushes data to any STOMP stream. STOMP stands for Streaming Text Orient
51275149
51285150
**Requirements**
51295151
5130-
Install the stomp.py library, e.g. [apt install python3-stomp.py] or [pip install stomp.py].
5152+
Install the `stomp.py` library from PyPI:
51315153
5132-
You need a CA certificate, client certificate and key file from the organization / server you are connecting to. Also
5133-
you will need a so called "exchange point".
5154+
```bash
5155+
pip3 install -r intelmq/bots/outputs/stomp/REQUIREMENTS.txt
5156+
```
51345157

5135-
**Parameters:**
5158+
Alternatively, you may want to install it using your OS's native
5159+
packaging tools, e.g.:
51365160

5137-
**`exchange`**
5161+
```bash
5162+
apt install python3-stomp
5163+
```
51385164

5139-
(optional, string) The exchange to push to. Defaults to `/exchange/_push`.
5165+
Apart from that, depending on what STOMP server you connect to, you may
5166+
need to obtain, from the organization or company owning the server, one
5167+
or more of the following security/authentication-related resources:
51405168

5141-
**`username`**
5169+
* CA certificate file;
5170+
* either: *client certificate* and *client certificate's key* files,
5171+
or: *username* (STOMP *login*) and *password* (STOMP *passcode*).
51425172

5143-
(optional, string) Username to use.
5173+
Also, you will need to know an appropriate STOMP *destination* (aka
5174+
*exchange point*), e.g. `/exchange/_push`.
51445175

5145-
**`password`**
5176+
**Parameters:**
51465177

5147-
(optional, string) Password to use.
5178+
**`server`**
51485179

5149-
**`ssl_ca_certificate`**
5180+
(optional, string) STOMP server's hostname or IP, e.g. "n6stream.cert.pl" or "127.0.0.1" (which is default)
51505181

5151-
(optional, string) Path to trusted CA certificate.
5182+
**`port`**
51525183

5153-
**`auth_by_ssl_client_certificate`**
5184+
(optional, integer) STOMP server's port number (default: 61614)
51545185

5155-
(optional, boolean) Whether to authenticate using TLS certificate. (Set to false for new *n6* auth.) Defaults to true.
5186+
**`exchange`**
5187+
5188+
(optional, string) STOMP *destination* to push at, e.g. ``"/exchange/_push"`` (which is default)
51565189

51575190
**`heartbeat`**
51585191

51595192
(optional, integer) Defaults to 60000.
51605193

5161-
**`message_hierarchical_output`**
5194+
**`ssl_ca_certificate`**
51625195

5163-
(optional, boolean) Defaults to false.
5196+
(optional, string) path to CA file, or empty string to load system's default CA certificates
51645197

5165-
**`message_jsondict_as_string`**
5198+
**`auth_by_ssl_client_certificate`**
51665199

5167-
(optional, boolean) Defaults to false.
5200+
(optional, boolean) default: true (note: false is needed for new *n6* auth)
51685201

5169-
**`message_with_type`**
5202+
**`ssl_client_certificate`**
51705203

5171-
(optional, boolean) Defaults to false.
5204+
(optional, string) Path to client certificate to use for TLS connections.
51725205

5173-
**`port`**
5206+
**`ssl_client_certificate_key`**
51745207

5175-
(optional, integer) Defaults to 61614.
5208+
(optional, string) Path to client private key to use for TLS connections.
51765209

5177-
**`server`**
5210+
**`username`**
51785211

5179-
(optional, string) Hostname of the STOMP server.
5212+
(optional, string) STOMP *login* (e.g., *n6* user login), used only if `auth_by_ssl_client_certificate` is false
51805213

5181-
**`single_key`**
5214+
**`password`**
51825215

5183-
(optional, string) Output only a single specified key. In case of `raw` key the data is base64 decoded. Defaults to null (output the whole message).
5216+
(optional, string) STOMP *passcode* (e.g., *n6* user API key), used only if `auth_by_ssl_client_certificate` is false
51845217

5185-
**`ssl_ca_certificate`**
5218+
**`message_hierarchical_output`**
51865219

5187-
(optional, string) Path to trusted CA certificate.
5220+
(optional, boolean) Defaults to false.
51885221

5189-
**`ssl_client_certificate`**
5222+
**`message_jsondict_as_string`**
51905223

5191-
(optional, string) Path to client certificate to use for TLS connections.
5224+
(optional, boolean) Defaults to false.
51925225

5193-
**`ssl_client_certificate_key`**
5226+
**`message_with_type`**
51945227

5195-
(optional, string) Path to client private key to use for TLS connections.
5228+
(optional, boolean) Defaults to false.
5229+
5230+
**`single_key`**
5231+
5232+
(optional, string) Output only a single specified key. In case of `raw` key the data is base64 decoded. Defaults to null (output the whole message).
51965233

51975234
---
51985235

docs/user/feeds.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -719,15 +719,15 @@ parameters:
719719
720720
### N6 Stomp Stream
721721
722-
N6 Collector - CERT.pl's N6 Collector - N6 feed via STOMP interface. Note that rate_limit does not apply for this bot as it is waiting for messages on a stream.
722+
N6 Collector - CERT.pl's *n6* Stream API feed (via STOMP interface). Note that 'rate_limit' does not apply to this bot, as it is waiting for messages on a stream.
723723
724724
**Public:** no
725725
726-
**Revision:** 2023-09-23
726+
**Revision:** 2023-10-08
727727
728728
**Documentation:** <https://n6.readthedocs.io/usage/streamapi/>
729729
730-
**Additional Information:** Contact cert.pl to get access to the feed.
730+
**Additional Information:** Contact CERT.pl to get access to the feed. Note that the configuration parameter values suggested here are suitable for the new *n6* Stream API variant (with authentication based on 'username' and 'password'); for this variant, typically you can leave the 'ssl_ca_certificate' parameter's value empty - then the system's default CA certificates will be used; however, if that does not work, you need to set 'ssl_ca_certificate' to the path to a file containing CA certificates eligible to verify "*.cert.pl" server certificates (to be found among the publicly available CA certs distributed with modern web browsers/OSes). Also, note that the 'server' parameter's value (for the *new API variant*) suggested here, "n6stream-new.cert.pl", is a temporary domain; ultimately, it will be changed back to "stream.cert.pl". When it comes to the *old API variant* (turned off in November 2023!), you need to have the 'server' parameter set to the name "n6stream.cert.pl", 'auth_by_ssl_client_certificate' set to true, 'ssl_ca_certificate' set to the path to a file containing the *n6*'s legacy self-signed CA certificate (which is stored in file "intelmq/bots/collectors/stomp/ca.pem"), and the parameters 'ssl_client_certificate' and 'ssl_client_certificate_key' set to the paths to your-*n6*-client-specific certificate and key files (note that the 'username' and 'password' parameters are then irrelevant and can be omitted).
731731
732732
733733
**Collector configuration**
@@ -736,14 +736,14 @@ N6 Collector - CERT.pl's N6 Collector - N6 feed via STOMP interface. Note that r
736736
module: intelmq.bots.collectors.stomp.collector
737737
parameters:
738738
auth_by_ssl_client_certificate: False
739-
exchange: {insert your exchange point as given by CERT.pl}
739+
exchange: {insert your STOMP *destination* to subscribe to, as given by CERT.pl, e.g. /exchange/my.example.org/*.*.*.*}
740740
name: N6 Stomp Stream
741-
password: {insert n6 user's API key}
741+
password: {insert your *n6* API key}
742742
port: 61614
743743
provider: CERT.PL
744-
server: n6stream.cert.pl
745-
ssl_ca_certificate: {insert path to CA file for CERT.pl's n6}
746-
username: {insert n6 user's login}
744+
server: n6stream-new.cert.pl
745+
ssl_ca_certificate:
746+
username: {insert your *n6* login, e.g. someuser@my.example.org}
747747
```
748748
749749
**Parser configuration**
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# SPDX-FileCopyrightText: 2017 Sebastian Wagner
22
# SPDX-License-Identifier: AGPL-3.0-or-later
33

4-
stomp.py>=4.1.8
4+
stomp.py>=4.1.12

intelmq/bots/collectors/stomp/collector.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44

55
# -*- coding: utf-8 -*-
66

7-
from intelmq.lib.bot import CollectorBot
8-
from intelmq.lib.mixins import StompMixin
9-
107
try:
118
import stomp
12-
import stomp.exception
139
except ImportError:
1410
stomp = None
1511
else:
12+
import stomp.exception
13+
14+
from intelmq.lib.bot import CollectorBot
15+
from intelmq.lib.mixins import StompMixin
16+
17+
18+
if stomp is not None:
19+
1620
class StompListener(stomp.PrintingListener):
1721
"""
1822
the stomp listener gets called asynchronously for
@@ -74,17 +78,33 @@ def connect_and_subscribe(conn, logger, destination, start=False, connect_kwargs
7478
class StompCollectorBot(CollectorBot, StompMixin):
7579
"""Collect data from a STOMP Interface"""
7680
""" main class for the STOMP protocol collector """
77-
exchange: str = ''
81+
82+
server: str = 'n6stream.cert.pl'
7883
port: int = 61614
79-
server: str = "n6stream.cert.pl"
80-
auth_by_ssl_client_certificate: bool = True
81-
username: str = 'guest' # ignored if `auth_by_ssl_client_certificate` is true
82-
password: str = 'guest' # ignored if `auth_by_ssl_client_certificate` is true
83-
ssl_ca_certificate: str = 'ca.pem' # TODO pathlib.Path
84-
ssl_client_certificate: str = 'client.pem' # TODO pathlib.Path
85-
ssl_client_certificate_key: str = 'client.key' # TODO pathlib.Path
84+
exchange: str = ''
8685
heartbeat: int = 6000
8786

87+
# Note: the `ssl_ca_certificate` configuration parameter must be set:
88+
# * *either* to the server's CA certificate(s) file path,
89+
# * *or* to an empty string -- dictating that the SSL tools employed
90+
# by the `stomp.py`'s machinery will attempt to load the system’s
91+
# default CA certificates.
92+
# The latter, if applicable, is more convenient -- by avoiding the
93+
# need to manually update the CA certificate(s) file.
94+
ssl_ca_certificate: str = 'ca.pem' # <- TODO: change to '' (+ remove "ca.pem*" legacy files)
95+
# (^ TODO: could also be pathlib.Path)
96+
97+
auth_by_ssl_client_certificate: bool = True
98+
99+
# Used if `auth_by_ssl_client_certificate` is true (otherwise ignored):
100+
ssl_client_certificate: str = 'client.pem' # (cert file path)
101+
ssl_client_certificate_key: str = 'client.key' # (cert's key file path)
102+
# (^ TODO: could also be pathlib.Path)
103+
104+
# Used if `auth_by_ssl_client_certificate` is false (otherwise ignored):
105+
username: str = 'guest' # (STOMP auth *login*)
106+
password: str = 'guest' # (STOMP auth *passcode*)
107+
88108
_collector_empty_process: bool = True
89109
__conn = False # define here so shutdown method can check for it
90110

0 commit comments

Comments
 (0)