├── .DS_Store
├── Archive
└── OCSF Schema Collaboration_ Initial Decisions.pdf
├── Articles
├── Defining and Using Observables.md
├── Patching Core Using Extensions.md
├── Profiles are Powerful.md
└── Representing Process Parentage.md
├── Contributors.md
├── FAQs
├── How to Model Alerts in OCSF.md
├── README.md
└── Schema FAQ.md
├── LICENSE
├── README.md
├── Understanding OCSF.md
└── Understanding OCSF.pdf
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ocsf/ocsf-docs/100ce76a6a2657fadf5a11cedf8a7a84ac6dd76c/.DS_Store
--------------------------------------------------------------------------------
/Archive/OCSF Schema Collaboration_ Initial Decisions.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ocsf/ocsf-docs/100ce76a6a2657fadf5a11cedf8a7a84ac6dd76c/Archive/OCSF Schema Collaboration_ Initial Decisions.pdf
--------------------------------------------------------------------------------
/Articles/Defining and Using Observables.md:
--------------------------------------------------------------------------------
1 | # Defining and Using Observables
2 | Rick Mouritzen,
3 | August 2024
4 |
5 | Observables provide a way to enrich OCSF events so that important data can be easily found and queried rather than having to walk though the rather rich and potentially deeply nested structure of an event. Observables are _not_ meant as place to be information that not present in other locations in an event. It is, then, an optional query optimization that is common enough to warrant direct support in the OCSF schema. As an example, if one was looking across all events for presence if a set of IP addresses known to be indicators of compromise, instead of manually look for all occurrences of all attributes of type `ip_t`, or worse, all fields ending with `_ip`, one could query each events `observables` array for `type_id` 2 and the set of IP addresses.
6 |
7 | Observables are defined in event class and object definitions in the OCSF metaschema. This is done by associating a data type, data attribute, event class, or object with an observable `type_id`.
8 |
9 | ## Defining Observables
10 | The following ways to define observables are supported:
11 |
12 | 1. Observable by dictionary type. All attributes of this type become observables. The generated observables include the attribute values.
13 | 2. Observable by dictionary attribute. All instances of this attribute become observables. The generated observables include the attribute values.
14 | 3. Observable by object. All attributes of this object type become observables. The generated observables do _not_ include a value.
15 | 4. Observable by event class attribute. The attribute in the event class or its subtypes become an observable. Note that these are attributes defined at the base of the event, and not in nested structures. Also note that the attribute type can be any valid attribute type: a primitive, a primitive subtype, or an object.
16 | 5. Observable by object attribute. The attribute in all instances of the object or its subtypes become observables. Note that these are attributes defined at the base of the object, and not in nested structures. Also note that the attribute type can be any valid attribute type: a primitive, a primitive subtype, or an object.
17 | 6. Observable by class-specific attribute path. Attributes on the specified attributes path become observables. (The plural wording is used because a path element may refer to an array, resulting in multiple observables.)
18 |
19 | In all cases, the definition of an observable is an integer number of OCSF type `integer_t`, a 32-bit signed integer. This number becomes the `observable` object's `type_id` value. The only values with a special meaning are the typical OCSF enum integer values of `0` (Unknown) and `99` (Other). There is no other special meaning or special ranges of values.
20 |
21 | As with most things in OCSF, these definitions can be in the base of the core schema, one of the core schema extensions, or any other private extension (those extensions outside of the core schema).
22 |
23 | As a historical note, definition types 1 and 3 have been in use since schema version 1.0, and the rest became available for use since 1.2.
24 |
25 | ### Definition Example: Observable by Dictionary Type
26 | Defining an observable by dictionary type is, naturally, done in a metaschema `dictionary.json` file. The definition is done by adding an `observable` field to a type definition.
27 |
28 | This, along with defining observable objects (which are also a kind of type) are the broadest ways to define observables. All attributes of this type (regardless of attribute name) become observables.
29 |
30 | Example in a `dictionary.json` file:
31 | ```jsonc
32 | {
33 | "name": "dictionary",
34 | // ... other dictionary fields (caption, description, attributes)
35 | "types": {
36 | // ... other "types" fields (caption, description)
37 | "attributes": {
38 | // ... other types
39 | "email_t": {
40 |
41 | // This is the observable definition for the email_t type, a subtype of string_t
42 | "observable": 5,
43 |
44 | "caption": "Email Address",
45 | "description": "Email address. For example: john_doe@example.com
.",
46 | "regex": "^[a-zA-Z0-9!#$%&'*+-/=?^_`{|}~.]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$",
47 | "type": "string_t",
48 | "type_name": "String"
49 | },
50 | // ...
51 | }
52 | }
53 | }
54 | ```
55 |
56 | ### Definition Example: Observable by Dictionary Attribute
57 | Defining an observable by dictionary attribute is also done in a metaschema `dictionary.json` file. The definition is done by adding an `observable` field to an attribute definition.
58 |
59 | Definitions done this way limit the creation of observable instances of this specific attribute, regardless of where it is used.
60 |
61 | Example in a `dictionary.json` file:
62 | ```jsonc
63 | {
64 | "name": "dictionary",
65 | // ... other dictionary fields (caption, description, types)
66 | "attributes": {
67 | // ... other attributes
68 | "cmd_line": {
69 | "caption": "Command Line",
70 | // ... other attribute fields
71 |
72 | // This is the observable definition for the cmd_line attribute
73 | "observable": 13
74 | },
75 | // ...
76 | },
77 | // ...
78 | }
79 | ```
80 |
81 | ### Definition Example: Observable by Object
82 | Defining an observable by object is done in a metaschema object definition file. The definition is done by adding an `observable` field directly in the object definition object. This also works for object definitions that extend another, including the special patch case. For both regular and patch extends cases, the observable definition adds or replaces any existing object-level observable definition.
83 |
84 | This, along with defining observables by dictionary type, are the broadest ways to define observables. All instances attributes of this type (regardless of attribute name) become observables.
85 |
86 | Example in object definition file `objects/container.json`:
87 | ```jsonc
88 | {
89 | "name": "container",
90 |
91 | // This is the observable definition for this object
92 | "observable": 27,
93 |
94 | // ... other object definition fields
95 | }
96 | ```
97 |
98 | ### Definition Example: Observable by Event Class Attribute / Observable by Object Attribute
99 | Observables can be defined in event class or object attributes. These are very similar and so are described together here. Defining observables this way limits the scope where these observables will occur. Note that definitions of this type are for attributes directly defined in the event class or object, not for attributes in a nested structure.
100 |
101 | Defining observables in event class or object attributes works just as with any other attribute definition at these levels: the fields defined override the same field defined in the dictionary or any event classes / objects the current item is derived from.
102 |
103 | Definitions of this type work for event class and object `extends` definitions both for the normal case (subclass / subtype) as well as the "patch extends" case, however "hidden" event classes and objects are not supported due to the potential of colliding observable `type_id` values. See [Appendix 2: Hidden Types](#appendix-2-hidden-types) for more about this issue.
104 |
105 | Example in object definition file `objects/cve.json`:
106 | ```jsonc
107 | {
108 | "name": "cve",
109 | // ... other object definition fields
110 | "attributes": {
111 | // ... other attributes
112 | "uid": {
113 | "caption": "CVE ID",
114 | // ... other attribute fields
115 |
116 | // This defines uid as an observable when directly inside a cve object
117 | "observable": 18
118 | },
119 | // ...
120 | },
121 | // ...
122 | }
123 | ```
124 |
125 | Event classes work identically: attribute observables are defined inside attribute details.
126 |
127 | ### Definition Example: Observable by Class-Specific Attribute Path
128 | This last observable definition type allows defining an observable for an attribute inside a nested structure for an event class, though it can be used for attributes directly defined in the class (in this case being a alternative to defining event class attribute observables).
129 |
130 | This type of definition is done by adding an top-level `observables` field to the event class definition whose value is a JSON object that maps from attribute paths to observable `type_id` values.
131 |
132 | Class-specific attribute path definitions also work for event class `extends` definitions both for the normal case (subclass / subtype) as well as the "patch extends" case. In the extends cases, the class-specific observable definitions replace a prior definition or add a new definition.
133 |
134 | Hidden event classes are not supported due to the potential of colliding observable `type_id` values. See [Appendix 2: Hidden Types](#appendix-2-hidden-types) for more about this issue.
135 |
136 | The attribute paths use a simple dotted notation. See [Appendix 1: Attribute Paths](#appendix-1-attribute-paths) for details about how attribute paths are defined in OCSF. Notably these attribute paths do _not_ contain array references. In this context it means all array items in the attribute path are considered.
137 |
138 | The following is an example showing the definition pattern for observables by class-specific attributes in an example "Bag" event class that holds an array of items, where each item has a `type_id` field that we want to become observables.
139 |
140 | Example in event class definition file `events/bag.json`:
141 | ```jsonc
142 | {
143 | "name": "bag",
144 | // ... other event class definition fields
145 | "attributes": {
146 | // ... other attributes
147 |
148 | // Here we add the items array: an array of item objects
149 | "items": {
150 | "requirement": "required"
151 | }
152 | },
153 |
154 | // Here we define the class-specific attribute observable as type_id 20
155 | "observables": {
156 | "items.type_id": 20
157 | }
158 | }
159 | ```
160 |
161 | This definition causes the `type_id` value of each item object to become an observable, but _only_ for events of the `bag` event class, and nowhere else.
162 |
163 | ### Definition Nuances
164 | Defining observables has a few nuances, described in the next few sections.
165 |
166 | #### Definition Nuance: Avoid Collisions
167 | When defining a new observable, be mindful of collisions. One can use the OCSF Server running with the core extensions plus any additional extensions that may be used in a specific environment, and then view all of the existing observable `type_id` values on the `observable` object page (https://schema.ocsf.io/objects/observable). Also note that for additions to the core schema, the commit process detects collisions by running the [OCSF Server](https://github.com/ocsf/ocsf-server) and running the [OCSF Validator](https://github.com/ocsf/ocsf-validator).
168 |
169 | Developers of private extensions should be extra wary to avoid collisions. Unlike most other unique identifier integer values in extensions, observable values are _not_ modified with tricky multiplication. Consider using using high integer numbers related to the extension's `uid`. For example for extension `uid` `999`, the observable numbers could start from `999000` (extension `uid` times `1000` plus observable number). This sort of precaution could become important as OCSF gains acceptance across the industry, and publishing and accepting OCSF events generated with private extensions begins to occur.
170 |
171 | #### Definition Nuance: Precedence and the "Use the Most General" Rule
172 | The definition types, as listed in the [Defining Observables](#defining-observables) section, establish a precedence with 1 being the most general to 6 being the most specific.
173 |
174 | In cases where an OCSF event has an attribute that is affected by more than one observable definition, _the most general_ should be used.
175 |
176 | #### Definition Nuance: Extends
177 | Observable definitions can be overridden in extensions (via `extends`) in event class and object definitions, including the special "patch" type of extends. This is also mentioned above, though repeated here to emphasize that this is a general rule for all types of observable definitions.
178 |
179 | #### Definition Nuance: Hidden Types Are Not Supported
180 | Defining observables in definitions of hidden event classes or object is not supported as this would lead to colliding observables `type_id` values. See [Appendix 2: Hidden Types](#appendix-2-hidden-types) for more information. This is also mentioned above, though repeated here to emphasize that this is a general rule for all types of observable definitions.
181 |
182 | #### Definition Nuance: Profiles
183 | Profile definitions can override attribute observables (as with any other attribute field), though cannot modify object or class-specific attribute path observables (the top-level `observable` definitions). In other words, with regard to observables profiles can only affect observables by attributes.
184 |
185 | > [!NOTE]
186 | > Implementation-wise, this restriction may not be difficult to overcome, however it does become difficult to conceptualize and visualize the effect of a profile if it can affect a top level property of event class or object this way. Constraints, another top-level event class / object concept, are similarly not controllable by profiles.
187 |
188 | #### Definition Nuance: New Object Observables Discouraged
189 | The OCSF community currently discourages defining objects as observables. The object observable merely indicates the presence of the object in the event on a specific path. A second query would be needed to interrogate the object. It is not terribly useful.
190 |
191 | #### Definition Nuance: Observable Values Are Strings
192 | The `observable` object's `value` field is used for attributes that are primitive types (strings, numbers, booleans), subtypes of primitive types, and arrays of primitive types or primitive subtypes. The type of the `observable` object's `value` field is always of type `string_t`, and so string conversion may be needed. The `value` field is not populated for objects or arrays of objects.
193 |
194 | For more, see [Populating The Value Field](#populating-the-value-field).
195 |
196 | #### Definition Nuance: Event Class Observables Are Not Supported
197 | Defining an event class as an observable is not supported. This would be essentially redundant with the `type_uid` field, which already uniquely identifies an OCSF event's event class. In other words, a query for an event class's observable ID might as well query for event classes `type_uid`. Further, the OCSF community is trying to move away from observables by object, which this would be similar to, since these do not populate the `observable` object's `value` field.
198 |
199 | The only thing this sort of definition would enable would be to detect events that are in an event class inheritance subtree at a finer grain than categories; a fairly esoteric use-case.
200 |
201 | ## Using Observables
202 | Observables can be generated automatically, though of course can also be created manually. Creating observables automatically requires walking an event's structure along with a compiled schema, looking for observable definitions at each level of the structure, as well at each leaf (each primitive value).
203 |
204 | A concrete example of this code can be found in the [`Schema` class](https://github.com/ocsf/ocsf-java-tools/blob/main/ocsf-schema/src/main/java/io/ocsf/schema/Schema.java) in the [`ocsf/ocsf-java-tools` repo](https://github.com/ocsf/ocsf-java-tools). Look at the `enrich(Map, boolean, boolean)` method and follow it along. As an aside, this same class and approach can be used to add enum sibling values, and indeed can (and should) be done in the same pass as adding observables.
205 |
206 | Whether creating observables manually -- a part of mapping process -- or automatically, care must be taken while populating the `name` and `value` fields.
207 |
208 | ### Populating Observable Path References
209 | The `observable` object's `name` attribute is an attribute path reference. See [Appendix 1: Attribute Paths](#appendix-1-attribute-paths) for details.
210 |
211 | ### Populating the Value Field
212 | The `observable` object's `value` field should be populated for all primitive types (strings, numbers, booleans), _and_ for arrays of primitive types (see next paragraph). The `value` field is specifically not meant to be used for observable objects, nor for for arrays of objects.
213 |
214 | For arrays of primitive types, one `observable` object should be created for each element of the array with the `value` field being set to the array element's value.
215 |
216 | #### All Observable Values Are Strings
217 | The `observable` object's `value` is defined as a type `string_t`. A primitive value that is not a string (either `string_t` or a subtype of `string_t`) must be converted to string.
218 |
219 | Suggested conversions of non-string values:
220 | * `integer_t` and `long_t`: base 10 string.
221 | * `float_t`: base 10 string using common standard library conversions, including exponential notation and "NaN".
222 | * `boolean_t`: the strings `"true"` and `"false"`.
223 | * Null should not be converted to string, but rather the encoding's equivalent of `null`. In other words, a null remains a null. In JSON encoded events, use `"value": null` and not `"value": "null"`.
224 |
225 | > [!NOTE]
226 | > About `null`, it's weird. Don't overthink it. OCSF does not have a null type. In practice this means OCSF does not distinguish between a field that has a `null` value and a missing field. For observables, when creating them for primitive fields (like strings and numbers), if the field's value is `null`, then you may either set the `observable` object's `value` to `null` or not set the `value` field -- the meaning of each is equivalent. (This is not true in general. For those of that remember the XML era, distinguishing `null` from missing was one of the consistently annoying edge cases you'd have to always keep in mind.)
227 |
228 | ## Appendix 1: Attribute Paths
229 | Attribute paths occur in two places: in the `observable` object's `name` attribute as a path reference to a field in the event, and in class-specific attribute observable definitions. In both cases the paths are the same. (Note: this is the only use of a JSON path-like capability in OCSF.)
230 |
231 | The general pattern is dot-separated attribute names, for example `foo.bar`. Using the dot (".") as a separator works well because OCSF does not use dots in attribute names. There is no special notation for arrays, so these paths only tell us that a reference is for _one of_ the items along a path that includes one or more arrays.
232 |
233 | These attribute path references are similar (at least in spirit) to [JSON Pointer](https://www.rfc-editor.org/rfc/rfc6901), [JSONPath](https://www.rfc-editor.org/rfc/rfc9535), and the syntax used by the [`jq` command-line tool](https://github.com/jqlang/jq), though simpler and notably without array notation.
234 |
235 | Let's say we have a event with a nested structure as follows:
236 | ```jsonc
237 | {
238 | // ... other event fields
239 | "devices": [
240 | {
241 | "hostname": "mercury",
242 | "network_interfaces": [
243 | {
244 | "ip": "10.0.0.5"
245 | }
246 | ]
247 | },
248 | {
249 | "hostname": "venus",
250 | "network_interfaces": [
251 | {
252 | "ip": "192.168.0.3"
253 | },
254 | {
255 | "ip": "10.100.0.42"
256 | }
257 | ]
258 | }
259 | ]
260 | }
261 | ```
262 |
263 | In this example, `ip` is an observable by dictionary type with `type_id` of `2`. The following shows what the observables for this event look like:
264 |
265 | ```jsonc
266 | {
267 | // ... other event fields
268 | "devices": [
269 | // ... as above
270 | ],
271 | "observables": [
272 | {
273 | "name": "devices.network_interfaces.ip",
274 | "type_id": 2,
275 | "value": "10.0.0.5"
276 | },
277 | {
278 | "name": "devices.network_interfaces.ip",
279 | "type_id": 2,
280 | "value": "192.168.0.3"
281 | },
282 | {
283 | "name": "devices.network_interfaces.ip",
284 | "type_id": 2,
285 | "value": "10.100.0.42"
286 | }
287 | ]
288 | }
289 | ```
290 |
291 | Notice that the attribute path in each `name` field is the same; the positions in the `devices` and `network_interfaces` arrays is not included.
292 |
293 | ## Appendix 2: Hidden Types
294 | It's a bit tedious to keep saying "event classes and objects". In Computer Science terms, these are both abstract data types, and specifically in object-oriented programming terms, their definitions are like classes. The OCSF terminology is a bit loose here. In this section, event class definitions and object definitions will simply be called types. Just note that OCSF also has primitive types (unstructured types) such as `string_t`, including subtypes of their primitive types like `email_t`.
295 |
296 | > [!NOTE]
297 | > Hidden types work like "inheritance for implementation". They exist so commonalities can be placed in a shared definitions, however these definitions are removed from the final compiled schema. Hidden event class definitions occur for definitions _without_ a `uid`, other than the special `base_event` definition which doesn't have a `uid` defined, but ends up with an effective `uid` of `0`. Hidden object definitions occur for object definitions where the `name` value has a leading underscore, for example `_hidden`.
298 |
299 | The net effect of hidden types is that each type that is derived from a hidden type gets all of the inherited information as if it was copied in by hand, essentially replicating the information in the hidden type. For observables, this would mean the `type_id` values would be replicated, and thus cause collisions among the type derived from the hidden type. (The only case where this wouldn't happen would be a hidden event class or object with only a single derivation. This isn't a useful case in practice, however.)
300 |
301 | This hidden type observable collision is detected and blocked for each of these cases:
302 | * A hidden event class definition with one or more attributes that define `observable`.
303 | * A hidden object definition with one or more attributes that define `observable`.
304 | * A hidden event class definition with class-specific attribute path observables defined via the top-level `observable` field.
305 | * A hidden object definition defining itself an observables via the top-level `observable` field.
306 |
307 | ### Example Hidden Object
308 | This is a concrete example using a hidden object that tries to define itself an observable by object type. The other cases work similarly.
309 |
310 | Let's say we have a hidden object definition with `name` `_foo`, as well as `bar` and `baz` object definitions that extend the hidden `_foo` object. Now let's say we want all instances of the `_foo` object to be an observable with `type_id` of `42`, so we add `"observable": 42,` to the `_foo` object's definition. Let's show this more concretely:
311 |
312 | `objects/_foo.json` (by convention, file names match the `name` attribute in the definition):
313 | ```jsonc
314 | {
315 | "name": "_foo",
316 | "observable": 42,
317 | // ... other object definition fields
318 | }
319 | ```
320 |
321 | `objects/bar.json`
322 | ```jsonc
323 | {
324 | "name": "bar",
325 | "extends": "_foo",
326 | // ... other definition fields
327 | }
328 | ```
329 |
330 | `objects/baz.json`
331 | ```jsonc
332 | {
333 | "name": "baz",
334 | "extends": "_foo",
335 | // ... other definition fields
336 | }
337 | ```
338 |
339 | After compilation, `_foo` disappears, and both `bar` and `baz` are defined as observables by object with the `type_id` value `42`. This is a collision and if done manually would be flagged an an error between `bar` and `baz`.
340 |
341 | What actually happens in this case is that when the hidden type definition like `_foo` is encountered, the OCSF Server and OCSF Validator ensure that it does not attempt to define observables of any kind.
342 |
--------------------------------------------------------------------------------
/Articles/Patching Core Using Extensions.md:
--------------------------------------------------------------------------------
1 | # Patching the Core Schema With Extensions
2 | Paul Agbabian,
3 | August 2024
4 |
5 | Extensions have been around since the earliest days of OCSF. We knew that it was impossible to cover every type of event in a standard way, and that vendors will have special event classes, attributes and objects that only pertain to their products. Customers may have their own enrichment pipelines with specific attributes that need to be type-checked, etc.
6 |
7 | A somewhat subtle and hidden feature of the extension mechanism is how the core schema itself can be patched, meaning added to, without having to create new classes and new objects. That is to say, an extension can have new attributes and new objects added to existing core classes without having to create an extension class. An extension can add new attributes to a core object or class without having to create a new object or class. An extension can even create new data types for new attributes that can be added to existing core classes and objects.
8 |
9 | Before we learn how to patch the core schema, we will review standard schema extensions. You will see later that patching the core schema is much simpler than having to create a standard extension, if all you want to do is add some attributes and constraints to existing classes or objects.
10 |
11 | ## Standard Approach for Extensions
12 |
13 | Here is an example of a normal extension in a folder named `ocsf-extension` that adds an attribute, `a1` of type `string_t` via a new object that extends the core `metadata` object:
14 |
15 | #### Extension example registration in `ocsf-extension/extension.json` file. The name, version and uid are example names.
16 |
17 | ```json
18 | {
19 | "caption": "Generic Extension",
20 | "name": "extension",
21 | "version": "1.1.0",
22 | "uid": 500
23 | }
24 |
25 | ```
26 |
27 | The `uid` and `version` are arbitrary here. For a real extension, you should request a unique extension ID via a Pull Request to the ocsf-schema repository. This prevents collisions with other extensions. Note that having a reserved public extension ID does not mean your actual extensions need be made public.
28 |
29 | #### Dictionary entry in `ocsf-extension/dictionary.json` file.
30 |
31 | ```json
32 | {
33 | "caption": "Generic Extension Attribute Dictionary",
34 | "description": "The Attribute Dictionary defines schema attributes and includes references to the events and objects in which they are used.",
35 | "name": "dictionary",
36 | "attributes": {
37 | "a1": {
38 | "caption": "An attribute",
39 | "description": "A generic extension attribute.",
40 | "is_array": false,
41 | "type": "string_t"
42 | }
43 | }
44 | }
45 | ```
46 |
47 | #### Object entry `extra_metadata.json` in `ocsf-extension/objects` subdirectory.
48 | ```json
49 | {
50 | "caption": "Extra Metadata",
51 | "description": "The Generic Extension Extra Metadata object.",
52 | "name": "extra_metadata",
53 | "extends": "metadata",
54 | "attributes": {
55 | "a1": {
56 | "requirement": "recommended"
57 | }
58 | }
59 | }
60 |
61 | ```
62 |
63 | This metaschema code will add a new object `extra_metadata` to the schema with a new attribute `a1` when the schema server loads and compiles the extension `ocsf-extension`. If you are running your own schema server, you can do this at startup with the environment variable, or you can issue a reload at the Elixir command prompt: `Schema.reload(["extensions", "../ocsf-extension"])`, for this example, if your extension folder is parallel to the OCSF Schema repo folder.
64 |
65 | If you do not include a caption or a description, the default is to use the caption or description of the object being extended. The same holds for extension classes.
66 |
67 | But, you may ask, how do I use this new `extra_metadata` object I created in my extension? Although it is now visible to the schema server when loaded, it can only be used within a new extension class. You would need to create a new class or extend an existing class, likely in the core schema, so that you can add it to that class. Let's say you want to create a new Base class, and add it to that class.
68 |
69 | First, you would need to add an attribute, for example `new_metadata`, to the extension dictionary of type `extra_metadata`:
70 |
71 | ```json
72 | {
73 | "caption": "Attribute Dictionary",
74 | "description": "The Attribute Dictionary defines schema attributes and includes references to the events and objects in which they are used.",
75 | "name": "dictionary",
76 | "attributes": {
77 | ...
78 | "new_metadata": {
79 | "caption": "New Metadata",
80 | "description": "A new metadata object that can work with a new base class.",
81 | "type": "extra_metadata"
82 | }
83 | }
84 | }
85 | ```
86 |
87 | There are two ways of creating a new base class: either extend the core Base event class, or create a new base class for your extension.
88 |
89 | To create a new base class, you would write something like the following metaschema code. This example copies some of the core Base class attributes but not all, for example purposes. Note the `new_metadata` attribute as well as the `"uid": 0"` statement. As this is an extension, you must give the class an ID, which will be used to calculate a concrete class ID based on the extension master ID, in this case 500. The core schema Base event class defaults to 0, as the core schema doesn't have an extension ID. In most cases it is likely you will not be starting with a new base class in your extension, but rather extending the core Base event class, or some other core event class.
90 |
91 | ```json
92 | {
93 | "caption": "New Base Event",
94 | "category": "other",
95 | "uid": 0,
96 | "description": "The new base event is a generic and concrete event. It also defines a set of attributes available in most event classes. As a generic event that does not belong to any event category, it could be used to log events that are not otherwise defined by the schema.",
97 | "name": "new_base_event",
98 | "attributes": {
99 | "$include": [
100 | "includes/classification.json",
101 | "includes/occurrence.json"
102 | ],
103 | "message": {
104 | "group": "primary",
105 | "requirement": "recommended"
106 | },
107 | "new_metadata": {
108 | "group": "context",
109 | "requirement": "required"
110 | },
111 | "raw_data": {
112 | "group": "context",
113 | "requirement": "optional"
114 | },
115 | "severity": {
116 | "group": "classification",
117 | "requirement": "optional"
118 | },
119 | "severity_id": {
120 | "group": "classification",
121 | "requirement": "required"
122 | },
123 | "status": {
124 | "group": "primary",
125 | "requirement": "recommended"
126 | },
127 | "status_code": {
128 | "group": "primary",
129 | "requirement": "recommended"
130 | },
131 | "status_detail": {
132 | "group": "primary",
133 | "requirement": "recommended"
134 | },
135 | "status_id": {
136 | "group": "primary",
137 | "requirement": "recommended"
138 | },
139 | "unmapped": {
140 | "group": "context",
141 | "requirement": "optional"
142 | }
143 | }
144 | }
145 |
146 | ```
147 |
148 | If you really just wanted to add the `new_metadata` attribute to the existing Base event class, you could extend the Base event class in your extension, rather than create a new one:
149 |
150 | ```json
151 | {
152 | "caption": "Extended Base Event",
153 | "category": "other",
154 | "uid": 1,
155 | "description": "The Extended Base event adds new attributes to the core Base event.",
156 | "extends": "base_event",
157 | "name": "extended_base",
158 |
159 | "attributes": {
160 | "new_metadata": {
161 | "group": "context",
162 | "requirement": "required"
163 | }
164 | }
165 | }
166 |
167 | ```
168 |
169 | To keep things separated, this extended class uses a different `uid` value. Note that only the `new_metadata` attribute was needed with this approach, as all of the standard Base event class attributes will still be present.
170 |
171 | However, now you will have two metadata attributes, the core `metadata` attribute of type `metadata` as well as the extended metadata object `extra_metadata`. Since `extra_metadata` extended `metadata` you now have two versions of most of the `metadata` attributes. This is probably not what you wanted. Maybe that's why you created a new class and copied most but not all of the attributes, so that you would only have one extended metadata object in the class. You just wanted to add some extra attributes to the `metadata` object in the core schema's Base event class. That's where Patching Extensions comes in.
172 |
173 | ## A Patching Approach for Extensions
174 |
175 | Let's now say that we just want the attribute `a1` to be directly added to the core `metadata` object.
176 |
177 | ```
178 | {
179 | "caption": "Metadata Extension",
180 | "description": "The Generic Extension metadata object.",
181 | "extends": "metadata",
182 | "attributes": {
183 | "a1": {
184 | "requirement": "recommended"
185 | }
186 | }
187 | }
188 | ```
189 | The key enabling feature is the omission of the `name` field. This indicates to the schema compilation process that no new class or object should be generated.
190 |
191 | The metaschema code above will add a new attribute `a1` directly into the existing `metadata` object when the schema server loads the extension `ocsf-extension` and compiles the schema. In this case, the caption and description in the extension object will be ignored by the server but are useful for documentation purposes.
192 |
193 | I think you will agree this is a much simpler way to add attributes to an object in the core schema. When your extension is loaded and compiled, they will be added to the core schema. *There is no need to create a new class to add your attributes - they will be added directly into core.*
194 |
195 | The same approach can be used to add attributes directly to a core event class. You would just extend the core class without declaring a new `name` and add the attributes from your extension dictionary.
196 |
197 | ```json
198 | {
199 | "caption": "Patched Event",
200 | "description": "The Extended Base event adds new attributes to the core Base event.",
201 | "extends": "base_event",
202 |
203 | "attributes": {
204 | "a1": {
205 | "group": "context",
206 | "requirement": "recommended"
207 | }
208 | }
209 | }
210 |
211 | ```
212 |
213 | The core Base event class will now have a new attributes from the `ocsf-extension` extension dictionary, `a1`, directly added to the class, rather than to the `metadata` object (you would need to remove the `metadata` patch extension otherwise you would also have `a1` in the object). Pretty simple. Again, note that `name` is omitted and the `caption` and `description` are useful for documentation only - they will not be used in the schema.
214 |
215 | More generally, a patching extension will do the following things:
216 | - Profiles are merged
217 | - Attributes are merged
218 | - Class and object level observable definitions override / replace
219 | - Constraints override / replace
220 | - Caption and description are not patched but are good for documentation
221 |
222 | ## Constraints in Patching Extensions
223 |
224 | As of OCSF Schema Server vs. 2.72.0 patching extensions can add overriding constraints to core classes and objects. This was always possible with ordinary extension classes and objects, but was not supported by the server for patching constraints until 2.72.0. An example of this for `metadata` is shown below with two attributes, `a1` from the prior examples and `a2` so that a constraint on the two can be added.
225 |
226 | ```
227 | {
228 | "caption": "Attribute Dictionary",
229 | "description": "The Attribute Dictionary defines schema attributes and includes references to the events and objects in which they are used.",
230 | "name": "dictionary",
231 | "attributes": {
232 | "a1": {
233 | "caption": "An attribute",
234 | "description": "A generic extension attribute.",
235 | "is_array": false,
236 | "type": "string_t"
237 | },
238 | "a2": {
239 | "caption": "A second attribute",
240 | "description": "A second generic extension attribute",
241 | "is_array": false,
242 | "type": "integer_t"
243 | }
244 | }
245 | }
246 | ```
247 |
248 | ```
249 | {
250 | "description": "The Generic Extension metadata object.",
251 | "extends": "metadata",
252 | "attributes": {
253 | "a1": {
254 | "requirement": "recommended"
255 | },
256 | "a2": {
257 | "requirement": "recommended"
258 | }
259 | },
260 |
261 | "constraints": {
262 | "just_one": [
263 | "a1",
264 | "a2"
265 | ]
266 | }
267 | }
268 | ```
269 |
270 | Note that if existing parent class or object constraints exist, they will be removed and replaced unless they are also included in the extension. Also note that multiple constraints may be applied, as long as they don't conflict. For example:
271 |
272 | ```json
273 | {
274 | "caption": "Patched Event",
275 | "description": "The Extended Base event adds new attributes to the core Base event.",
276 | "extends": "base_event",
277 |
278 | "attributes": {
279 | "a1": {
280 | "group": "context",
281 | "requirement": "recommended"
282 | },
283 | "a2": {
284 | "group": "context",
285 | "requirement": "recommended"
286 | },
287 | "b1": {
288 | "group": "context",
289 | "requirement": "recommended"
290 | },
291 | "b2": {
292 | "group": "context",
293 | "requirement": "recommended"
294 | }
295 | },
296 | "constraints": {
297 | "just_one": [
298 | "a1",
299 | "a2"
300 | ],
301 | "at_least_one": [
302 | "b1",
303 | "b2"
304 | ]
305 | }
306 |
307 | }
308 | ```
309 |
310 | As can be seen in the above example, the same capability is possible when patching event classes; you can add constraints in the patching extension class and they will replace any constraints of the class being extended.
311 |
312 | ## Conclusion
313 | Patching extensions are a powerful yet simple way to add attributes to existing core schema classes and objects rather than having to introduce new extension classes with distinct names and IDs. With the most recent OCSF Schema Server update, patching extensions also support constraints which replace any constraints of the extended class or object. Existing queries will not need to change with the caveat that new patching constraints need to be carefully considered as they can change the validation of the core classes.
314 |
--------------------------------------------------------------------------------
/Articles/Profiles are Powerful.md:
--------------------------------------------------------------------------------
1 | # Profiles are Powerful
2 | Paul Agbabian
3 |
4 | I’ve mentioned OCSF Profiles in blogs, but I want to go into more detail here, as they are becoming more important and sometimes misunderstood as to how they can be constructed. There are four ways of modeling using profiles:
5 |
6 | 1. Augmentation profiles
7 | 2. Native profiles
8 | 3. Partially native profiles
9 | 4. Hybrid profiles
10 |
11 | An OCSF Profile is a framework construct that cuts across categories and classes to augment classes and objects with focused ‘mix-in’ attributes that better describe aspects of activities and findings in certain situations. Rather than have an explosion of classes that combine attributes for these situations, profiles are an elegant way of reusing the semantics of fundamental classes without extending them with new classes. If you are a Java or C++ developer, they will resemble implementing additional interfaces on top of a class, and similarly, in OCSF, Profiles are an event type that cuts across event classes.
12 |
13 | Hence a profile is two things: a mix-in attribute set and an alternate typing of the event class or object where it is registered. This is accomplished via a “profiles” array at the head of the class or object. The OCSF schema server will take care of filtering or augmenting classes and objects appropriately. In this way, a related set of attributes can be added selectively independent of class or category when its type cross-cuts the structural taxonomy. For example, the Host profile can be applied to the Network Activity category classes for host-based network activity coming from an EDR security agent. Querying on events WHERE “Host” IN metadata.profiles[] retrieves all events from the System Activity category and the Network Activity classes.
14 |
15 | ```
16 | {
17 | "description": "The attributes that identify host/device attributes.",
18 | "meta": "profile",
19 | "caption": "Host",
20 | "name": "host",
21 | "annotations": {
22 | "group": "primary"
23 | },
24 | "attributes": {
25 | "device": {
26 | "requirement": "recommended"
27 | },
28 | "actor": {
29 | "requirement": "optional"
30 | }
31 | }
32 | }
33 | ```
34 |
35 | ## Augmentation Profiles
36 |
37 | The most common way of designing and using a profile is to define it in the metaschema profiles folder via a profile name and the profile attributes, as above; then declare the profile in the class or object, and finally include the profile to bring in its attributes, as below; the attributes will be added when the profile is applied to an event class or object.
38 |
39 | ```
40 | {
41 | "caption": "Network",
42 | "category": "network",
43 | "description": "Network event is a generic event that defines a set of attributes available in the Network category.",
44 | "extends": "base_event",
45 | "name": "network",
46 | "profiles": [
47 | "host",
48 | "network_proxy",
49 | "security_control",
50 | "load_balancer"
51 | ],
52 | "attributes": {
53 | "$include": [
54 | "profiles/host.json",
55 | "profiles/network_proxy.json",
56 | "profiles/security_control.json",
57 | "profiles/load_balancer.json"
58 | ],
59 | ...
60 | ```
61 |
62 | This is the augmentation profile approach. When the profile is enabled in the schema browser, the respective classes and objects are augmented with the profile attributes, and schema samples will include the profile name in the metadata.profiles[] array, effectively typing the event or object as a kind of the profile.
63 |
64 | ```
65 | {
66 | "type_name": "Network Activity: Open",
67 | "activity_id": 4,
68 | "type_uid": 400104,
69 | "class_uid": 4001,
70 | "category_uid": 4,
71 | "class_name": "Network Activity",
72 | "metadata": {
73 | "version": "1.1.0",
74 | "profiles": ["host"]
75 | }
76 | "category_name": "Network Activity",
77 | ...
78 | ```
79 |
80 | All events matching the profile will be returned if an event is queried by its profile name, irrespective of class or category. However, there are three other ways to use profiles in the schema.
81 |
82 | ## Native Profiles
83 |
84 | The second approach is where the attributes of a profile definition are already natively defined within the event class or object. Think of this as the built-in or native profile approach. For the profiles system and typing to be consistent, those classes and objects must declare the profile within the class as with the augmentation approach. Still, there is no need to include the profile in the attributes section since those attributes (in the case of the Host profile, actor and device) are already defined there.
85 |
86 | ```
87 | {
88 | "caption": "System Activity",
89 | "category": "system",
90 | "extends": "base_event",
91 | "name": "system",
92 | "profiles": [
93 | "host",
94 | "security_control"
95 | ],
96 | "attributes": {
97 | "$include": [
98 | "profiles/security_control.json"
99 | ],
100 | "actor": {
101 | "group": "primary",
102 | "requirement": "required"
103 | },
104 | "device": {
105 | "group": "primary",
106 | "requirement": "required"
107 | }
108 | }
109 | }
110 | ...
111 | ```
112 |
113 | ## Partially Native Profiles
114 |
115 | What happens when only some of the attributes of the profiles are native to an event class or object? This is the partially native profile approach. Using the augmentation profile approach, where the profile is $included into the class or object, the schema server will remove the native attributes when the profile is not applied, which isn’t what you would want. For these cases, a “profile”: null statement should be added to the potentially affected native attribute, which tells the server to leave it alone regardless of the profile application. In the example below, actor is native to the Authentication class, but device is not. When the profile is applied, only device will be added, and when not applied, actor will stay put.
116 |
117 | ```
118 | {
119 | "caption": "Authentication",
120 | "extends": "iam",
121 | "name": "authentication",
122 | "uid": 2,
123 | "profiles": [
124 | "host"
125 | ],
126 | "attributes": {
127 | "$include": [
128 | "profiles/host.json"
129 | ],
130 | "actor": {
131 | "description": "The actor that requested the authentication.",
132 | "group": "context",
133 | "profile": null
134 | },
135 | ...
136 | ```
137 |
138 | ## Hybrid Profiles
139 |
140 | Finally, what if a class or object wants to be considered as part of the profile family but wants to add new attributes that are only relevant to the one particular class or object? This may sound a bit esoteric, but it has already been used in the resource_details object for the Cloud profile. When the Cloud profile is applied to classes with attributes of the resource_details object type, for example, API Activity, the cloud_partition and region attributes defined within the object are added, but only when the Cloud profile is applied to the class. The event now includes the api and cloud attributes, while the resource_details object of the class adds the other two attributes - effectively creating a custom hybrid profile.
141 |
142 | If you $included the profile attributes, as with the augmented profile, you would also get the Cloud profile’s attributes in the object as well as the class. You don’t want to duplicate those attributes applied by the profile to the class into the objects too. To make the object’s native attributes aware of the profile (such that the server switches them on, and the event validator won’t complain), you add “profile”: within your object’s attribute clause, as well as the usual declaration within the profiles array at the head of the class or object.
143 |
144 | The example below assigns the Cloud profile to the specific native attributes cloud_partition and region of the Resource Details object. These attributes are not part of the Cloud profile definition, so only this specific object will include them when the Cloud profile is applied to its enclosing class. In this way, applying a profile can add its attributes to a class, and different attributes can be added to an object within that class.
145 |
146 | ```
147 | {
148 | "caption": "Resource Details",
149 | "extends": "_resource",
150 | "name": "resource_details",
151 | "profiles": ["cloud"],
152 | "attributes": {
153 | "agent_list": {
154 | "requirement": "optional"
155 | },
156 | "cloud_partition": {
157 | "profile": "cloud",
158 | "requirement": "optional"
159 | },
160 | "owner": {
161 | "description": "The service or user account that owns the resource.",
162 | "requirement": "recommended"
163 | },
164 | "region": {
165 | "description": "The cloud region of the resource.",
166 | "profile": "cloud",
167 | "requirement": "optional"
168 | },
169 | ...
170 | ```
171 |
--------------------------------------------------------------------------------
/Articles/Representing Process Parentage.md:
--------------------------------------------------------------------------------
1 | # Representing Process Parentage
2 | Mitchell Wasson
3 | February 2025
4 |
5 | Effectively representing endpoint process parentage is frequently discussed, because the OCSF schema has several fields that support this use case (`actor.process`, `process.parent_process`, `process.lineage` and `process.ancestry`).
6 | This article clarifies and expands on those discussions to provide presecriptive guidance for representing process parentage within the OCSF schema.
7 |
8 | ## Actor/Creator or Parent
9 |
10 | [Confusion on this topic]((https://github.com/ocsf/ocsf-schema/discussions/1194)) arises from the fact that the OCSF schema enables the simultaneous expression of `.actor.process` and `.process.parent_process` in `Process Activity: Launch` events.
11 | People are usually wondering if they should put the launched process's parent in `.actor.process`, `.process.parent_process` or both.
12 | Again, presecriptive guidance will be provided, but it is important to understand the difference between the actor (aka the "creator") and the parent in a process launch/creation event.
13 |
14 | The creator is the process that initiated the creation of a new process with the endpoint operating system.
15 | The parent is the process that the newly created process inherits properties from according to operating system rules.
16 | The creator and the parent are _usually_ the same process.
17 | Additionally, on many platforms they are guaranteed to always be the same.
18 |
19 | However, this guarantee is not present on Windows.
20 | [Pavel Yosifovich's blog on "Parent Process vs. Creator Process"](https://scorpiosoftware.net/2021/01/10/parent-process-vs-creator-process/) shows exactly how one can create a process on Windows with a parent different from the creator.
21 | This is a straightforward technique and has many legitimate use cases.
22 |
23 | Note this situation shouldn't be confused with creating a process through a layer of indirection or communicating with another common process that will create a process for you.
24 | The above disinction of creator vs parent applies to mechanisms natively supported through operating system APIs that can't be modelled otherwise.
25 | Process creation through a layer of process indirection (e.g. starting a shell to start your program) is modelled through two `Process Activity: Launch` events.
26 | Asking another process to create a process is modelled through some sort of communication event and a single `Process Activity: Launch` event.
27 |
28 | For `Process Activity: Launch` events, one should set both `.actor.process` and `.process.parent_process` if the ability to know both is present.
29 | This will provide the visiblity to know when they differ.
30 | However, your endpoint software must be aware of this difference in order to effectively populate both locations.
31 | If your endpoint software only reports on parent, then only set `.process.parent_process`.
32 | However, if your query patterns demand that `.actor.process` be set, you can duplicate the parent information there knowing that this information would be the same the majority of the time anyway.
33 | Inform your downstream data consumers this approach is being taken so they do not rely on being able to detect when creator and parent differ.
34 |
35 | Note that there is no explicit attribute for creator inside the process object.
36 | As mentioned above, the creator and the parent will be the same process the majority of the time.
37 | We currently believe it is sufficient to only provide one location in which this difference is expressed: the `Process Activity: Launch` event.
38 |
39 | Depending on the situation, the creator may be desired instead of the parent.
40 | When a data consumer is specifically interested in the creator, they should consult the `Process Activity: Launch` event for the process in question.
41 | It is possible to add attributes for creator to the process object in the future.
42 | However, the added value will need to be carefully weighed against the incurred bloat.
43 |
44 | ## Extended Ancestry
45 |
46 | OCSF primarily models process ancestry through process object recursion with the `process.parent_process` attribute.
47 | In theory this recursion ends once you get to the root of the ancestry tree.
48 | In practice, endpoint software must stop closer to the process in question.
49 |
50 | Current guidance is to only populate `process.parent_process` for the top-level process object in an event.
51 | This guidance is given in order to prevent deep nesting in events.
52 | Additionally, there are diminishing returns to going further and further up the process tree.
53 |
54 | The `parent_process` attribute in the top-level process object should be set if possible as the primary mechanism for communicating ancestry.
55 | Parent process and all the fields in the process object are often critical context in security investigations.
56 |
57 | When going beyond immediate parent, the OCSF 1.4 `process.ancestry` attribute should be used.
58 | This attribute provides the ability to supply references to processes going up the process ancestry tree (e.g. parent, grandparent, great grandparent, ...).
59 | The process entity objects in this array contain a small subset of process object atrtributes.
60 | These fields are meant to enable a lookup of full process details and enable a basic preview of the process.
61 | It is left up to the implementer to determine how far back to report process ancestry.
62 |
63 | Prior to OCSF 1.4, the `process.lineage` field (now deprecated) enabled a preview of ancestry.
64 |
65 | ## `Process Activity: Launch` Sample Event
66 |
67 | Here is a `Process Activity: Launch` event that adheres to the above guidance on Actor/Creator, Parent and Ancestry.
68 | Note that the creator and parent are different.
69 |
70 | ```json
71 | {
72 | "activity_id": 1,
73 | "activity_name": "Launch",
74 | "actor": {
75 | "process": {
76 | "ancestry": [
77 | {
78 | "cmd_line": "C:\\windows\\System32\\cmd.exe",
79 | "created_time": 1738156431386,
80 | "pid": 43548,
81 | "uid": "3831f89a-5b2c-8fc2-8396-794f0d877672"
82 | },
83 | {
84 | "cmd_line": "\"C:\\Program Files\\WindowsApps\\Microsoft.WindowsTerminal_1.21.3231.0_x64__8wekyb3d8bbwe\\WindowsTerminal.exe\" ",
85 | "created_time": 1737662946236,
86 | "pid": 10464,
87 | "uid": "9263fade-d82f-8780-95da-203a95408580"
88 | },
89 | {
90 | "cmd_line": "C:\\windows\\Explorer.EXE",
91 | "created_time": 1737662110682,
92 | "pid": 7956,
93 | "uid": "2d7576cb-b5f9-8eee-b209-2022749157d1"
94 | }
95 | ],
96 | "cmd_line": "cuckoo.exe 7956 powershell -command \"echo Hello.\"",
97 | "created_time": 1738271124947,
98 | "file": {
99 | "hashes": [
100 | {
101 | "algorithm": "SHA-256",
102 | "algorithm_id": 3,
103 | "value": "3dab543070797f16f874caf518807ca9d3e81376daf9eccce34d69bec2e8a7a5"
104 | }
105 | ],
106 | "name": "cuckoo.exe",
107 | "path": "C:\\Users\\test\\source\\repos\\cuckoo\\x64\\Release\\cuckoo.exe",
108 | "size": 169472,
109 | "type": "Regular File",
110 | "type_id": 1
111 | },
112 | "name": "cuckoo.exe",
113 | "pid": 61320,
114 | "uid": "2b2de22a-2818-8819-8bdb-67379aa6b98b"
115 | }
116 | },
117 | "category_name": "System Activity",
118 | "category_uid": 1,
119 | "class_name": "Process Activity",
120 | "class_uid": 1007,
121 | "device": {
122 | "hostname": "test hostname",
123 | "type": "Desktop",
124 | "type_id": 2
125 | },
126 | "message": "Process 61320 (cuckoo.exe) created process 14148 (powershell.exe) as a child of process 7956 (explorer.exe).",
127 | "metadata": {
128 | "product": {
129 | "name": "A creator-aware endpoint security product"
130 | },
131 | "version": "1.4.0"
132 | },
133 | "process": {
134 | "ancestry": [
135 | {
136 | "cmd_line": "C:\\windows\\Explorer.EXE",
137 | "created_time": 1737662110682,
138 | "pid": 7956,
139 | "uid": "2d7576cb-b5f9-8eee-b209-2022749157d1"
140 | }
141 | ],
142 | "cmd_line": "powershell -command \"echo Hello.\"",
143 | "created_time": 1738271124954,
144 | "file": {
145 | "hashes": [
146 | {
147 | "algorithm": "SHA-256",
148 | "algorithm_id": 3,
149 | "value": "3247bcfd60f6dd25f34cb74b5889ab10ef1b3ec72b4d4b3d95b5b25b534560b8"
150 | }
151 | ],
152 | "name": "powershell.exe",
153 | "path": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
154 | "size": 450560,
155 | "type": "Regular File",
156 | "type_id": 1
157 | },
158 | "name": "powershell.exe",
159 | "parent_process": {
160 | "cmd_line": "C:\\windows\\Explorer.EXE",
161 | "created_time": 1737662110682,
162 | "file": {
163 | "hashes": [
164 | {
165 | "algorithm": "SHA-256",
166 | "algorithm_id": 3,
167 | "value": "6b45e1b4d3af9ae92c6aec095579571317924f50d12f13f0ed6a82b91c6fab83"
168 | }
169 | ],
170 | "name": "explorer.exe",
171 | "path": "C:\\Windows\\explorer.exe",
172 | "size": 5575536,
173 | "type": "Regular File",
174 | "type_id": 1
175 | },
176 | "name": "explorer.exe",
177 | "pid": 7956,
178 | "uid": "2d7576cb-b5f9-8eee-b209-2022749157d1"
179 | },
180 | "pid": 14148,
181 | "uid": "a5f0e1f1-8e89-8b58-98ea-3d5ba1a3d07e"
182 | },
183 | "severity": "Informational",
184 | "severity_id": 1,
185 | "time": 1738271124958,
186 | "type_name": "Process Activity: Launch",
187 | "type_uid": 100701
188 | }
189 | ```
190 |
191 | ## Pre-existing Processes
192 |
193 | Endpoint security software may report on the existence of processes that were created while the security software was not running.
194 | For example, some processes will be created before endpoint security software is started at system boot.
195 | Care should be taken to correctly represent process ancestry in these situations.
196 |
197 | First, the type of event used to report process existence is important.
198 | `Process Query: Query` events should be used when the existence of a process is reported, and `Process Activity: Launch` events should be used when a directly observed process creation is reported.
199 | If these two situations can't be distinguished in an endpoint dataset, then one may use `Process Activity: Launch` events for both cases.
200 |
201 | Communicating this distinction through `Process Query: Query` and `Process Activity: Launch` event types is greatly preferred,
202 | because more information is available to endpoint security software if it directly observes a process creation.
203 | Most importantly, information on process creator is only available at process creation time.
204 | Additionally, if reporting on an already existing process, that process's parent may have terminated already and there will be little information available about it.
205 | Using two different event types allows one to easily communicate a different schemas to data consumers based on event type.
206 |
207 | When reporting on already existing processes, `.actor.process` should not be supplied to reflect that no information on process creator is available.
208 | `Process Query: Query` does not have the `actor` attribute by default, so this advice only applies if enabling the Host profile.
209 | `.process.parent_process` should be set and populated if the reported process's parent hasn't terminated yet.
210 | If the parent process has terminated, then it is likely that only the parent's PID will be available.
211 | In this situation `.process.parent_process` may be set with only the `pid` attribute supplied, or the PID can be reported in the `process.ancestry` array.
212 |
213 | ## `Process Query: Query` Sample Event
214 |
215 | Here is a `Process Query: Query` event that adheres to the above guidance pre-existing processes where creator information is not available.
216 |
217 | ```json
218 | {
219 | "activity_id": 1,
220 | "activity_name": "Query",
221 | "category_name": "Discovery",
222 | "category_uid": 5,
223 | "class_name": "Process Query",
224 | "class_uid": 5015,
225 | "message": "Process 8732 (svchost.exe) is pre-existing.",
226 | "metadata": {
227 | "product": {
228 | "name": "A creator-aware endpoint security product"
229 | },
230 | "version": "1.4.0"
231 | },
232 | "process": {
233 | "ancestry": [
234 | {
235 | "cmd_line": "C:\\Windows\\system32\\services.exe",
236 | "created_time": 1738348318013,
237 | "pid": 864,
238 | "uid": "88b1f102-1c47-8051-8f81-728b01bd7343"
239 | },
240 | {
241 | "cmd_line": "wininit.exe",
242 | "created_time": 1738348317989,
243 | "pid": 952,
244 | "uid": "06b14610-be3d-8a4a-b7c1-e41c25f0fbe3"
245 | }
246 | ],
247 | "cmd_line": "C:\\Windows\\System32\\svchost.exe -k swprv",
248 | "created_time": 1738349093722,
249 | "file": {
250 | "hashes": [
251 | {
252 | "algorithm": "SHA-256",
253 | "algorithm_id": 3,
254 | "value": "6fc3bf1fdfd76860be782554f8d25bd32f108db934d70f4253f1e5f23522e503"
255 | }
256 | ],
257 | "name": "svchost.exe",
258 | "path": "C:\\Windows\\System32\\svchost.exe",
259 | "size": 57528,
260 | "type": "Regular File",
261 | "type_id": 1
262 | },
263 | "name": "svchost.exe",
264 | "parent_process": {
265 | "cmd_line": "C:\\Windows\\system32\\services.exe",
266 | "created_time": 1738348318013,
267 | "file": {
268 | "hashes": [
269 | {
270 | "algorithm": "SHA-256",
271 | "algorithm_id": 3,
272 | "value": "1efd9a81b2ddf21b3f327d67a6f8f88f814979e84085ec812af72450310d4281"
273 | }
274 | ],
275 | "name": "services.exe",
276 | "path": "C:\\Windows\\System32\\services.exe",
277 | "size": 716544,
278 | "type": "Regular File",
279 | "type_id": 1
280 | },
281 | "name": "services.exe",
282 | "pid": 864,
283 | "uid": "88b1f102-1c47-8051-8f81-728b01bd7343"
284 | },
285 | "pid": 8732,
286 | "uid": "52bc2416-2c6b-811c-a031-43ba9b58ec7e"
287 | },
288 | "query_result": "Exists",
289 | "query_result_id": 1,
290 | "severity": "Informational",
291 | "severity_id": 1,
292 | "time": 1738792775574,
293 | "type_name": "Process Query: Query",
294 | "type_uid": 501501
295 | }
296 | ```
297 |
--------------------------------------------------------------------------------
/Contributors.md:
--------------------------------------------------------------------------------
1 | # Contributors
2 | | Organization |
3 | | ------------ |
4 | 3OPS
5 | Accenture
6 | Akamai
7 | Amazon
8 | Anomali
9 | Apple
10 | Aqua Security
11 | Aquia
12 | Norwegian Labor Inspection Authority
13 | Arctic Wolf
14 | University of Arizona
15 | Arklay
16 | Atlassian
17 | AT&T
18 | IBM
19 | Autodesk
20 | Automax
21 | Avalor
22 | Aviz Networks
23 | Axiad
24 | Barracuda
25 | Bestgate Engineering
26 | Beyond Identity
27 | Block
28 | Blue Cycle
29 | BlueVoyant
30 | blyx
31 | Bricklayer AI
32 | Broadcom
33 | IBM
34 | Cargill
35 | Carnegie Melon CERT
36 | Cisco
37 | Cloud Software Group
38 | CloudFabrix
39 | Cloudflare
40 | Comcast
41 | ComplianceCow
42 | Cornell University
43 | Crash Override
44 | Cribl
45 | Crogl
46 | CrowdStrike
47 | Crystal Matrix Software
48 | Canadian Centre for Cyber Security
49 | CyberActive
50 | CyberArk
51 | Cyber Sanik
52 | Cybersixgill
53 | Cyware
54 | Darktrace
55 | Databahn
56 | Databricks
57 | Decathlon
58 | Deepwatch
59 | Deloitte
60 | Devo
61 | Disney
62 | DNIF
63 | DoDIIS
64 | DTEX Systems
65 | Duo Security
66 | AI EdgeLabs
67 | Elastic
68 | Elysium Analytics
69 | Ermetic
70 | eSentire
71 | F5
72 | Grab
73 | Grafana
74 | Hi Bob
75 | Hunters
76 | Bosch
77 | Infopercept
78 | Infosys
79 | Innotac
80 | Interpublic Group
81 | Intuit
82 | iSenpai
83 | ITV
84 | Jamf
85 | Johns Hopkins Applied Physics Laboratory
86 | JupiterOne
87 | Keos Technology
88 | KKR
89 | Kyndryl
90 | Lacework
91 | Laminar Security
92 | Leidos
93 | LimaCharlie
94 | MalwareBytes
95 | ManTech
96 | Mekanoid Corporation
97 | MetricStream
98 | Metron Security
99 | Microsoft
100 | MITRE
101 | Monad
102 | MongoDB
103 | NETSCOUT
104 | Netskope
105 | Networkology
106 | Nokia
107 | Northeastern University
108 | NowSecure
109 | NXLog
110 | OISF
111 | Okta
112 | OLX
113 | Orca Security
114 | OSRS Group
115 | Own Company
116 | Palo Alto Networks
117 | Palosade
118 | Panther
119 | Planned Systems International
120 | Praxis Engineering
121 | Priam Cyber AI
122 | PrimeOrbit
123 | Prowler
124 | PWC
125 | Qualys
126 | QueryAI
127 | Rapid7
128 | RedBear
129 | Red Canary
130 | Reddit
131 | Red Panda
132 | Devoteam Revolve
133 | Ripjar
134 | Rooted Insights
135 | Sailpoint
136 | Salesforce
137 | Sandia National Laboratories
138 | SAS
139 | Scanner
140 | Secureworks
141 | Security Compass
142 | SecurityScorecard
143 | Securonix
144 | SeeMetrics
145 | Sekoia
146 | SentinelOne
147 | sFractal Consulting
148 | Sinko Sinko
149 | Skyscanner
150 | Snowflake
151 | SOC Prime
152 | Sophos
153 | Southern Company
154 | Splunk
155 | Stellar Cyber
156 | Stripe
157 | Sumo Logic
158 | Swimlane
159 | Symmetry Systems
160 | Syncbak
161 | Synqly
162 | SysDig
163 | Tanium
164 | Tarsal
165 | Tech Mahindra
166 | Tenable
167 | Tenzir
168 | Torq
169 | Trellix
170 | Trend Micro
171 | TUI
172 | University of Cincinatti
173 | Uptycs
174 | Vectra
175 | Veeam
176 | Venafi
177 | Verica
178 | Veriti
179 | Vipre
180 | VMWare
181 | WithSecure
182 | Wiz
183 | ZeroFox
184 | Zscaler
185 | Zurich Services
186 |
--------------------------------------------------------------------------------
/FAQs/How to Model Alerts in OCSF.md:
--------------------------------------------------------------------------------
1 | # How to Model Alerts with OCSF
2 |
3 | Through version 1.3 of OCSF the concept of an alert, or alertable signal, was not explicitly defined. In practice any event might be considered an alert, if it was deemed important and in many cases worthy of some additional form of notification. All OCSF events have a required `severity_id` attribute. Elevated values such as `Major` or `Critical` could be interpreted to be alertable signals, indirectly. Examples of alertable signals then might be events with high severity, elevated risk scores, detected malware, MITRE ATT&CK annotations, and rule or policy violations. Other alertable signals might be the creation of a Finding based on some type of analysis.
4 |
5 | `Security Control` profile events, available since version 1.0, are often alerts (the profile was factored out from a series of 'Detection' events). More directly, `Detection Findings` when created might be considered alertable signals. However, there was no way to express the intent of the event producer or event mapper that the event should be interpreted as an alert. And yet alerts are extremely important and prevalent in security event processing.
6 |
7 | In OCSF version 1.4, an explicit alertable signal is an event with the `is_alert` attribute set to `true`. This is a newer attribute that is not required. The intent of `is_alert = true` is to signal that the event may require immediate attention by its consumer, which might be a stream processor, a SIEM system or the product’s management console where an analyst can be notified, tickets created or the events prioritized.
8 |
9 | Not all OCSF events are potential alertable signals, i.e. carry the `is_alert` attribute, and as of this writing only the `Detection Finding`, `Data Security Finding` event classes and the `Security Control` profile carry the `is_alert` boolean attribute. Note the `Security Control` profile may be applied to many activity oriented classes, as well as the two aforementioned `Finding` classes, hence when applied any instances of these classes can be explicit alertable signals.
10 |
11 |
12 | ## Detection Finding and Security Control Alerts
13 |
14 | There is a fundamental difference between `Detection Finding` (or `Data Security Finding`) events and `Security Control` profile augmented events (aside from when the profile is applied to `Detection Finding` or `Data Security Finding`).
15 |
16 | ### What is a Security Control?
17 |
18 | `Security Control` profile attributes represent the augmentation of ordinary activities monitored by a technical security control program or sensor, or an access control system. This profile has been available since version 1.0 but has been expanded to address access control events and risk scoring.
19 |
20 | An Intrusion Detection System (IDS), Intrusion Prevention System (IPS) sensor, firewall, anti-malware agent, or Data Loss Prevention (DLP) agent are security controls. Role Based Access Control (RBAC) enforcement points are security controls. They monitor normal activities watching for suspicious or malicious activity, or policy violations. These controls usually emit single events that include the attempted activity (the class's `activity_id`) along with the control’s judgements (for example risk level or MITRE Techniques), and disposition of what was done in real time.
21 |
22 | For example, the file open activity was blocked, the control detected malware and quarantined the file. The file access was denied due to policy. A firewall rule was violated and the connection denied. These events are generally consumed by an incident management system or a SIEM in the form of alerts. In these example cases, the `is_alert` attribute should be set to `true` and the `severity_id` set to an appropriate level. For example, if malware was detected but blocked, the severity might be low but the event may still be considered an alertable signal.
23 |
24 | ### What is a Detection Finding?
25 |
26 | `Detection Finding` is a complex class that evolved from the original `Security Finding` in version 1.0 and has a lifecycle: the `activity_id`s are Create, Update, Close. `Detection Finding`s are best suited to systems that consume other events, perform some analysis on them, detect something suspicious or malicious and then have further investigation and workflow, compiling evidence, updating the finding, possibly including it into an `Incident Finding`, assigning it to an analyst, and ultimately closing it out. An MSSP or a SIEM might consume alerts and convert them into `Detection Finding`s.
27 |
28 | The `Analytic` object is a required attribute of `Detection Finding`, which describes the type of analysis done on the event or events. `related_events` refer to other events that are relevant to the Finding and were analyzed by the analytic algorithm, for example machine learning or anomaly detection.
29 |
30 | Examples of products that create `Detection Finding`s would be User and Entity Behavioral Analysis (UEBA) systems, SIEMs, and Endpoint Detection and Response (EDR) systems. EDRs are systems having both an agent that can monitor activities as well as an analysis system that can apply analytics to the activity events to determine a detection. In some cases the producing agent can make the determination at the point of the threat, while in other cases the associated analysis system will do so. Hence an EDR agent or similar may need to apply the `Security Control` profile to the `Detection Finding` class to produce a detection but also a disposition.
31 |
32 | When a Detection Finding is created (`activity_id = 1 Create`), `is_alert` may be set to `true` to indicate the detection is an alertable signal to a system, e.g. a ticketing system. However, other lifecycle Finding events such as `Update` and `Close` activities are not likely to be considered alertable signals. `is_alert` would be set to `false` or omitted.
33 |
34 | ## Conclusion
35 | In conclusion, one can use the `is_alert` attribute and set it to `true` when applying the `Security Control` profile to monitored activities for alertable actions and dispositions. Set the `is_alert` attribute to `true` with a `Detection Finding` or `Data Security Finding` event when they are created to signal an alertable detection. Apply the `Security Control` profile to `Detection Finding` or `Data Security Finding` when the analytic on multiple events happens at a control or enforcement point.
--------------------------------------------------------------------------------
/FAQs/README.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions
2 |
3 | ## What is OCSF?
4 | Open Cybersecurity Schema Framework (OSCF)
5 | is an open-source effort to create a common schema
6 | for security events across the cybersecurity ecosystem.
7 |
8 | See [this whitepaper](https://github.com/ocsf/ocsf-docs/blob/main/Understanding%20OCSF.pdf)
9 | for more info.
10 |
11 | ## What Problems does OCSF solve for?
12 | One of the primary challenges of cybersecurity analytics
13 | is that there is no common and agreed-upon format
14 | and data model for logs and alerts.
15 | As a result, pretty much everyone in the space creates
16 | and uses their own format and data model
17 | (IE sets of fields).
18 | There are *many* such models that exist,
19 | including some open ones like
20 | STIX, OSSEM, and the Sigma taxonomy.
21 | The challenge to date is that none of these
22 | models have become widely adopted by practitioners
23 | for logging and event purposes,
24 | and thus it requires a lot of manual work
25 | in order to derive value.
26 | This poses a challenge to
27 | detection engineering, threat hunting,
28 | and analytics development,
29 | not to mention AI – as Rob Thomas said,
30 | “There is no AI without IA”.
31 | Despite the issues this causes in the industry,
32 | there has been no significant progress on the problem space,
33 | because until now there has been lack of a “critical mass”
34 | of major players willing to tackle the problem head-on, and
35 | with efforts like this, timing is everything.
36 | With OCSF,
37 | we are now at a moment where we have
38 | that critical mass as well
39 | as a real willingness to tackle these challenges.
40 |
41 | ## How can I contribute to OCSF?
42 | See the
43 | [OCSF Contribution Guide](https://github.com/ocsf/ocsf-schema/blob/main/CONTRIBUTING.md)
44 |
45 | ## What is OCSF Governance Model?
46 | See [OCSF Governance](https://github.com/ocsf/governance/blob/main/Governance.md)
47 |
48 | ## How does OCSF relate to STIX?
49 | OCSF and STIX are compatible and complementary. While STIX is focused on threat intelligence, campaigns and actors, OCSF is focused on events representing the activities on computer systems, networks and cloud platforms that may have security implications. Observables represented OCSF can be matched with IOCs from STIX, for example, to determine whether a threat or malicious actor has compromised a system or enterprise environment.
50 |
51 | Structured Threat Information Expression (STIX™)
52 | is a open-source language and serialization format
53 | used to exchange cyber threat intelligence (CTI).
54 | For more info on STIX, see
55 | [this info](https://oasis-open.github.io/cti-documentation/stix/intro.html)
56 | or the
57 | (spec itself](https://docs.oasis-open.org/cti/stix/v2.1/csprd01/stix-v2.1-csprd01.html)
58 |
59 | ## How does OCSF relate to the Sigma taxonomy?
60 | Sigma is a SIEM language format for detection rules.
61 | Sigma rules can be written against OCSF events and complement OCSF. The
62 | essence of Sigma is the logic of what to look for
63 | within events to yield security findings.
64 |
65 | See
66 | [Sigma Taxomomy](https://github.com/SigmaHQ/sigma/wiki/Taxonomy)
67 | for more info on it.
68 |
69 | ## How does OCSF relate to Kestrel?
70 | OCSF and Kestrel are complementary, solving different problems.
71 |
72 | The Kestrel Threat Hunting Language
73 | provides an abstraction for threat hunters
74 | to focus on what to hunt instead of how to hunt.
75 | See their
76 | [repo](https://github.com/opencybersecurityalliance/kestrel-lang)
77 | for more information.
78 |
79 | ## How does OCSF relate to OSSEM?
80 |
81 | Open Source Security Events Metadata (OSSEM)
82 | is a community-led project focused
83 | primarily on the documentation,
84 | standardization and modeling of security event logs.
85 | See [OSSEM repo](https://github.com/OTRF/OSSEM).
86 |
87 | ## How does OCSF relate to OpenC2?
88 | OCSF and OpenC2 are complementary.
89 |
90 | OpenC2 is a standardized language
91 | for the command and control of technologies
92 | that provide or support cyber defenses.
93 | By providing a common language
94 | for machine-to-machine communication,
95 | OpenC2 is vendor and application agnostic,
96 | enabling interoperability
97 | across a range of cyber security tools and applications.
98 | The use of standardized interfaces and protocols
99 | enables interoperability of different tools,
100 | regardless of the vendor that developed them,
101 | the language they are written in
102 | or the function they are designed to fulfill.
103 | For more info on OpenC2, see
104 | [info](https://openc2.org/).
105 |
106 |
107 |
--------------------------------------------------------------------------------
/FAQs/Schema FAQ.md:
--------------------------------------------------------------------------------
1 | # Schema FAQ
2 | This document answers common questions about how to use the OCSF Schema
3 |
4 | ## How do I create a typical OCSF event?
5 | Depending on the type of event, a data producer or data mapper should first determine what event class best suits your event. Start with the OCSF category to narrow down the choices. For example, an endpoint security product would likely choose an event class from the System Activity category, for example, File System Activity for an AV product. Every event class has an `activity_id` enumeration which narrows down the intended activity of the event. Sometimes these are simple CRUD activities, but often they are more specific to the class, such as `Logon` for the `Authentication` class in the `Identity and Access Management` category.
6 |
7 | Since endpoint security products typically send alert events when malware is detected, the producer or mapper would apply the Security Control profile, which adds important attributes to the File System Activity event class, e.g. a Malware object, a MITRE ATT&CK object, the disposition etc. These profiles have their own attributes that must be populated.
8 |
9 | If your endpoint security product also has network security capabilities, you would choose an event class from the Network Activity category, for example the general Network Activity event class. Given that the endpoint product will have information about the host system, you would apply the Host profile, as well as the Security Control profile. The Host profile includes attributes about the device and the actor (e.g. process or user) on the host.
10 |
11 | Every OCSF event must have all of its event class Required attributes populated, and should have its Recommended attributes populated, if possible. This includes any of the embedded objects, such as the Malware, Process and Device objects above.
12 |
13 | All OCSF events have a set of required classification attributes from the Base Event class: the `class_uid` the `category_uid` the `activity_id` and the derived `type_uid`. Their associated `*_name` attributes are optional.
14 |
15 | In addition to the classification attributes, a number of other Base Event class attributes are required and must be populated: the `time` `metadata` and `severity` attributes. The `metadata` attribute is an object that itself requires the `product` and associated `version` of the reporting event, as well as the version of the OCSF schema adhered to with the event.
16 |
17 | Note that the product should be the originating event producer (i.e. not the mapping system, nor any intermediary event processing systems) in order to best represent the origin of the event. The `time` should be the time that the event actually occurred assuming that information is known, or the earliest possible time available to the event producer or mapper.
18 |
19 | Although the `observables` array attribute is optional, populating it can make things easier for event consumers and analysts. Each Observable object surfaces an important attribute of the event in a common location in a simple tuple: name, value, type. For example, if the event class has a `device` `user` and `process` populated, an array of three Observable objects will refer to them in a common location to all OCSF events.
20 |
21 | ---
22 |
23 | ## How would I populate the `observables` array?
24 |
25 | There are three important attributes of the `Observable` object, and the Base Event class allows for an array of these objects with the `observables` attribute: `name`, `type_id` and `value`. The first two are required attributes, while `value` is optional. Why it is optional will become clear soon. There can be multiple observables within an event, even of the same type. This is why `observables` is an array.
26 |
27 | The required `name` attribute of the `Observable` object should be the fully qualified attribute name within the event. E.g. `fingerprint.value` or `actor.process.file` or `actor.process.file.name`. In other words, `observable.name` is the locator of that observable within the instance of the event. Note that the observable attribute can be a scalar, like `device.ip`, or it can be an object, like `actor.process.file`.
28 |
29 | When the `type_id` of the observable indicates that the observable's `name` attribute is of object type, e.g. Fingerprint, the observable's `value` attribute is not populated. When the `type_id` indicates the observable's `name` is a scalar, e.g. File Hash or File Name, then the observable's `value` should be populated with the value of that attribute, that is, a copy of the value from the event.
30 |
31 | ---
32 |
33 | ## When should I use a Finding event class?
34 |
35 | A Finding in OCSF represents the result of some type of enrichment, correlation, aggregation, analysis or other processing of one or more events or alerts, producing a derived insight. Most security events and alerts are activity events with a dispostion (e.g. Blocked), for example when using the Security Control profile. Findings in OCSF are not always alerts themselves, although alerts may be triggered by findings or findings might be added to an incident further downstream.
36 |
37 | For example, an email security product may determine that a user has been phished or an email attachment is malicious. It would send an email activity event (from its standpoint an alert) containing the user and sender, supplemented by the Security Control profile with a disposition of Blocked, and information about the Malware, to its management console which in turn sends it to a SIEM.
38 |
39 | The SIEM might receive other related events or alerts, for example for other users in the same circumstance or for general email activity from the same sender. The SIEM might enrich the events with information from a Threat Intelligence Platform or threat feed pertaining to the email sender. The result of the aggregation, and enrichment would constitute an OCSF Finding. The SIEM might create an incident that includes or refers to the finding, in the event that there are remediation steps required.
40 |
41 | Note that in a more complex processing architecture, there may be layered findings. That is, the original event may go to product A which eventually triggers a finding. Product B meanwhile may take in a lot of other events and findings (including those from product A) and make its own findings. In the example above, the originating email alert might have been a finding from the producer's standpoint if the event was enriched by its management system before being collected by the SIEM, which then produced a more complete finding.
42 |
43 | ---
44 |
45 | ## When should I use metadata.correlation_uid?
46 |
47 | When an event producer or mapper emits multiple events that have some grouping characteristic, or similarity of any form, it should populate the `metadata.correlation_uid` attribute with a constant identifier. This allows consumers and analysts of the set of events to more easily aggregate and correlate the events.
48 |
49 | A simple example would be a vulnerability scanner that emits events at the start of a scan of a system, at the end of the scan, and separate events for each vulnerability discovered. If these are separate events, they would all have their `metadata.correlation_uid` set to the same value.
50 |
51 | It is possible for an intermediary system to determine the grouping characcteristic as well, populating the attribute after collection of the events, although when OCSF events are immutable a copy of the original events would be made with added correlation information. See the next question.
52 |
53 | ---
54 |
55 | ## Can Finding events be correlated with each other too?
56 |
57 | Yes, they are also events with a base class metadata object that can follow the same pattern.
58 | E.g. a SIEM that creates findings may have enough knowledge and state to tie multiple findings together with a metadata.correlation_uid.
59 |
60 | ---
61 |
62 | ## How do I use the Actor object?
63 | The Actor object is intended for use in event classes when knowledge of one entity that is initiating or causing some action on another entity.
64 | For example, a process deleting a file is the actor in a Filesystem Activity event.
65 |
66 | From a structural standpoint, the `actor` attribute avoids name collisions with the other end of the activity in cases where a process acts on another process, as those attribute names would be in contention at the same level within the class.
67 |
68 | Currently the Actor object has a `process` and `user` attribute, where one or the other is in the role of the actor in the activity. It also has Optional attributes for Session, `authorizations`, `idp`, and `invoked_by`.
69 |
70 | The `idp` is populated in IAM category event classes, when the actor's identity provider is known and logged with Authentication and related events.
71 |
72 | The `authorizations` attribute is an array of information pertaining to what permissions and privileges the actor has at the time of the event, if known.
73 |
74 | The `invoked_by` attribute is populated with the name of the service or application through which the actor's activity was initiated.
75 |
76 | ---
77 |
78 | ## When should I use the session attribute?
79 | The `session` attribute is usually paired with the `user` attribute. A Session object has information pertaining to a particular user session through which the activity was initiated. User is an entity object that isn't always associated with a session, and isn't always an actor, hence Session isn't part of the User object, but is included with the Actor object for actor semantics.
80 |
81 | Related to this, the `process` attribute of type Process has a User object which represents the user's account that the process runs under or is impersonating. Hence, the Process object also has a `session` attribute paired with its `user` attribute.
82 |
83 | Often, User and Session objects will be paired in many event classes.
84 |
85 | ---
86 |
87 | ## When should I use the unmapped attribute?
88 | The `unmapped` attribute is a catchall for event producers and mappers when there is data that doesn't populate the more specific attributes of the class. For example, product specific data that is extracted into fields and values from a log that aren't mapped.
89 |
90 | Where `unmapped` is best used, is for a mapper who is mapping events from multiple vendors where each vendor may have unique fields not common to other vendors for the same type of data source.
91 |
92 | However, using `unmapped` is not recommended for event producers. A native event producer should extend the schema to properly capture the data that can't be mapped. For product specific data, an extension is preferred, using either a vendor developed profile, or in some cases a new event class if the core event class doesn't adequately represent the event due to data that can't be naturally mapped, or activities not captured by the core class.
93 |
94 | ---
95 |
96 | ## unmapped is of Object type. What does that mean and is it different from JSON or a String type?
97 |
98 | Object is the empty complex data type from which all OCSF objects extend with JSON formatted attributes, requirements, and descriptions. Think of `unmapped` as if it were an OCSF object that you created on the fly. In the Java programming language, it would be like an inner class that doesn't need to be declared externally or globally. That is to say, it is used within the instance of an OCSF class only, and not part of the schema.
99 |
100 | JSON is more free form data, hence the `data` attribute is of type JSON. It can be anything encapsulated within JSON and does not need to look like an OCSF object. It should not be used for unmapped extracted fields, but rather other data that may be captured with the event. It is used, for example, within the Enrichment object (the `enrichments` array attribute of the Base Event) to augment one or more of the mapped or unmapped attributes.
101 |
102 | A String type is reserved for unformatted text, such as the `raw_data` attribute of the Base Event class. Binary data is Base64 encoded in an attribute of `bytestring_t` type, currently not used in the core schema but may be used in extensions or within the `unmapped` object.
103 |
104 | ---
105 |
106 | ## When should I use Authorize Session from Identity and Access Management vs. Web Resource Access Activity from the Application category?
107 | These two event classes are complementary. Changes to a security principal's permissions, privileges, roles are authorization activities, while the access of web resources by a security principal is logged as Web Access Activity. IAM category authorization or change events are independent of a particular resource access, while enforcement of authorization restrictions is made at access time and is logged as such. For example, when a new Logon session is created, authorization checks are made and if logged, belong in the Authorize Session class. However, when the user or process that has those permissions accesses a web resource, and it is granted or denied, the Web Access Activity class is used.
108 |
109 | ---
110 |
111 | ## When should I use HTTP Activity vs. Web Resource Access Activity?
112 | HTTP Activity is information focused on the network protocol, and not the gating of the resource. While access to a resource is often requested via a web service or REST APIs, the HTTP Activity is the protocol activity for that access, not the activity of the gating service to the resource, which might be via the HTTP server nevertheless. And of course access activity in general is not uniquely via HTTP: Kerberos and LDAP servers grant and deny access to resources over their respective protocols.
113 |
114 | ---
115 |
116 | ## Can you explain Profiles to me?
117 | Profiles in OCSF are a way to uniformly add a set of attributes to one or more event classes or objects. Event classes provide the basic structure and type of an event, while objects provide the structure of complex types. Their definitions can indicate that additional attributes may be included with an event instance via profiles specified with the class or object definition. In effect, adding a profile or profiles to the definition gives you the permission to dynamically include those attributes. When constructing an event, you would add an OCSF profile name to the `metadata.profiles` array to mix-in the additional attributes with the event.
118 |
119 | An event that has that profile applied is then a kind of that profile, as well as a kind of the event class. For example, if the `Host` profile was applied to the `HTTP Activity` class to add the `actor.process` making a request, the event would be queriable either via the metadata.profiles[] as `Host` or via class_name as `HTTP Activity`. If using `Host` other events from `System Activity` could also be returned with the same actor.
120 |
121 | Not all of the attributes from the profile need be added together. For example, a profile with attributes A, B, C can be defined within the definition of class D and object E. Class D can include A and B, while object E can include attribute C. You can also build in a profile, by adding the attributes of the profile directly into your class, and referencing the profile in your class definition. In this case, as with class and object extensions, the profile defined requirements, group or description can be overridden within the definition of the class or object, although this is not recommended. Only the attribute data type and constraints cannot be overridden.
122 |
123 | ---
124 |
125 | ## Is there a simiilarity between OCSF and LDAP (and X.500)?
126 | Yes there is, although OCSF is considerably simpler. At a fundamental level LDAP consists of attributes and object classes, while OCSF consists of attributes and event classes. Attributes in LDAP have syntaxes and in OCSF have data types (OCSF objects are complex data types). An event class is similar to an LDAP structural object class; it defines the basic structure of an event, as the LDAP object class defines the structure of an entry. Like LDAP, an OCSF event class can be constructed via extending a super class to inherit attributes. And an OCSF profile is similar to an LDAP auxiliary class which can be applied to a structural object class so that an entry can mix in additional attributes, independent of structural hierarchy of the entry.
127 |
128 | ---
129 |
130 | ## How should the attribute suffixes `_uid` and `_id` be used and what are "siblings?"
131 | These are naming conventions rather than metaschema or data type validation factors. `_id` is the convention for OCSF enumerated attributes. These attributes can be integer data types, or string data types, although OCSF favors integer data types with string labels. Every integer enum attribute SHOULD have standard values of `0` for `Unknown` and `99` for `Other`. There is no requirement that the integers stay within those bounds, or that they increment by `1`. Every enum attribute SHOULD have a string sibling attribute of the same name but without the `_id` suffix. A sibling is declared within the attribute definition of the enum attribute. When the logged value is not mappable within the enum listed values, `Other` can be set and a source specific label can populate the sibling attribute. The exception to this convention is when an enum attribute mirrors an external standard, for example with the `dns_query` object's `opcode_id` which mirrors the values requested from a resolver. It is recommended that the sibling attribute is populated with the enum label so that human queries can be made against a more easily remembered string, rather than a number.
132 |
133 | `_uid` suffix attributes are for unique identifier values within the schema, or external identifier values, e.g. coming from a public cloud resource or similar entity. For this reason `_uid` suffix attributes are usually strings, in order to accomodate any type of alphanumeric format, but they MAY be integers (or longs). Within OCSF Classification attributes, `_uid` attributes are integers or longs (see `class_uid` or `type_uid`). The sibling for `_uid` attributes is an attribute of the same base name with the `_name` suffix (see `class_name` or `type_name`). The exception for Classification attributes is `activity_id` which is an enum rather than a singular identifier. However its sibling is also of suffix `_name`: `activity_name` following the convention for `_uid` attributes of the Classification group.
134 |
135 | Note that sibling string attributes can be used standalone, i.e. without an associated enum or unique identifier.
136 |
137 | ---
138 |
139 | ## How is backwards compatibility managed?
140 | OCSF follows the [semver](https://semver.org/) versioning scheme.
141 |
142 | From the semver documentation:
143 |
144 | > Given a version number MAJOR.MINOR.PATCH, increment the:
145 | >
146 | > MAJOR version when you make incompatible API changes
147 | > MINOR version when you add functionality in a backward compatible manner
148 | > PATCH version when you make backward compatible bug fixes
149 |
150 | In terms practical to OCSF users, this means:
151 | - PATCH version increments may change documentation values like `description`.
152 | - MINOR version increments may add new schemata like attributes or events.
153 | - MAJOR version increments may add and remove anything.
154 |
155 | So any version in the 1.x line should be backwards-compatible with previous 1.x versions.
156 |
157 | ---
158 |
159 | ## What changes are not backwards compatible?
160 |
161 | 1. The removal of an event, object, attribute, data type, or enum member.
162 | 1. The `name` of an event or object is missing in the NEW schema.
163 | 2. The dictionary key of an attribute or data type (its implied `name`) is missing in the NEW schema.
164 | 3. The dictionary key of an enum member (its value) is missing in the NEW schema.
165 | 4. The `uid` or `class_uid` of an event is missing in the NEW schema.
166 | 2. Renaming an event, object, attribute, or enum member.
167 | 1. A special case of removal in which the same `caption` belongs to an element with a different `name`, key, or `class_uid`; or the same `class_uid` belongs to an event with a different name.
168 | 3. Changing the data type of an attribute **unless**:
169 | 1. The data type is changing from `int` to `long`. This exception is allowed on the basis that *nearly* all encodings use variable lengths by default, meaning that data written in nearly all encodings as an `int` can be safely interpreted as a `long`.
170 | 2. Changing a scalar type when the underlying type (e.g. `string_t`) remains the same and there are no constraints on the new type.
171 | 4. Changing the `requirement` value of an attribute from `optional` or `recommended` to `required`.
172 | 5. Making the `constraints` of a data type more restrictive.
173 | 6. Adding a `required` attribute to an existing event or object.
174 | 7. Changing the `caption` of an event, enum member, or category.
175 |
176 | ---
177 |
178 | ## When should I use `status` and when should I use `state` when adding to the schema?
179 |
180 | The convention we try to stick to when authoring OCSF classes and objects is to use `status_id` and its sibling `status` for the result of an activity, usually as a class attribute, and use `state_id` and its sibling `state` for the state of an object. The latter might sound obvious but it may not be obvious to not use `status` for objects. The reasoning is that an object exist independent of time or an activity or action, and therefore it has a state. It could have just as easily had a status, over an indeterminate period of time, but we have tried to distinguish between the two situations by reserving `status` for the point in time result of an activity or action.
181 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OCSF Documentation
2 | The ocsf-docs repository is intended to be the location where relevant proposals, documentation or other descriptive information for the schema are stored.
3 | Documents such as Understanding OCSF.pdf are point in time snapshots of current work before public release.
4 | Over time, documents will be organized based on version of schema.
5 |
6 | Common questions are answered in the FAQs folder of this repo. Schema specific questions are answered in FAQs/Schema FAQ.md
7 |
8 | The governance repo holds the governance material.
9 |
--------------------------------------------------------------------------------
/Understanding OCSF.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Understanding the Open Cybersecurity Schema Framework
4 |
5 | Author: Paul Agbabian
6 |
7 | Date: September 2024
8 |
9 | Status: RFC - Corresponds to schema version 1.0.0
10 |
11 | Version: 1.16
12 |
13 | ## Introduction to the Framework and Schema
14 |
15 | This document describes the Open Cybersecurity Schema Framework (OCSF) and its taxonomy, including the core cybersecurity event schema built with the framework.[^1]
16 |
17 | The framework is made up of a set of data types and objects, an attribute dictionary, and the taxonomy. It is not restricted to the cybersecurity domain nor to events, however the initial focus of the framework has been a schema for cybersecurity events. A schema browser for the schema can be found at [schema.ocsf.io](https://schema.ocsf.io).
18 |
19 | OCSF is agnostic to storage format, data collection and ETL processes. The core schema is intended to be agnostic to implementations. The schema framework definition files and the resulting normative schema are written as JSON.
20 |
21 | ### Personas
22 |
23 | There are four personas that are users of the framework and the schema built with the framework.
24 |
25 | The _author_ persona is who creates or extends the schema. The _producer_ persona is who generates events natively into the schema, or via a translation from another schema. The _mapper_ persona is who translates or creates events from another source to the schema. The _analyst_ persona is the end user who searches the data, writes rules or analytics against the schema, or creates reports from the schema. The analyst may also be considered the _consumer_ persona.
26 |
27 | For example, a vendor may write a translation from some external source format into the schema but also extend the schema to accommodate source specific attributes or operations. The vendor is operating as both the mapper and author personas. A SOC analyst that collects the data in a SIEM system writes rules against the events and searches events during investigation. The SOC analyst is operating as the analyst persona. Finally, a vendor that emits events natively in OCSF form, even if translated, is a data producer.
28 |
29 | ### Taxonomy Constructs
30 |
31 | There are 5 fundamental constructs of the OCSF taxonomy:
32 |
33 | 1. Data Types, Attributes and Arrays
34 | 2. Event Class
35 | 3. Category
36 | 4. Profile
37 | 5. Extension
38 |
39 | The scalar data types are defined on top of primitive data types such as strings, integers, floating point numbers and booleans. Examples of scalar data types are Timestamp, IP Address, MAC Address, and User Name.
40 |
41 | An _attribute_ is a unique identifier name for a specific validatable data type, either scalar or complex.
42 |
43 | Complex data types are termed objects. An _object_ is a collection of contextually related attributes, usually representing an entity, and may include other objects. Each object is also a data type in OCSF. Examples of object data types are Process, Device, User, Malware and File.
44 |
45 | _Arrays_ support any of the data types.
46 |
47 | Most scalar data types have constraints on their valid values or ranges, for example Enum integer types are constrained to a specific set of integer values. Enum integer typed attributes are an important part of the framework constructs and used in place of strings where possible to ensure consistency.
48 |
49 | Complex data types, or objects, can also be validated based on their particular structure and attribute requirements. Attribute requirements are discussed in a subsequent section.
50 |
51 | Appendix A and B describe the OCSF Guidelines and data types respectively.[^2]
52 |
53 | The _attribute dictionary_ of all available attributes, and their types are the building blocks of the framework. Event classes are particular sets of attributes from the dictionary.
54 |
55 | Events in OCSF are represented by _event classes_ which structure a set of attributes that attempt to describe the semantics of the event in detail. An individual event is an instance of an event class. Event classes have schema-unique IDs. Individual events may have globally unique IDs.
56 |
57 | Each event class is grouped by category, and has a unique `category_uid` attribute value which is the category identifier. Categories also have friendly name captions, such as System Activity, Network Activity, Findings, etc. Event classes are grouped into categories for a number of purposes: a container for a particular event domain, documentation convenience and search, reporting, storage partitioning or access control to name a few.
58 |
59 | _Profiles_ overlay additional related attributes into event classes and objects, allowing for cross-category event class augmentation and filtering. Event classes register for profiles that when optionally applied, can be mixed into event classes and objects, by a producer or mapper. For example, System Activity event classes may also include attributes for malware detection or vulnerability information when an endpoint security product is the data source. Network Activity event classes from a host computer may carry the device, process and user associated with the activity. A Security Control profile or Host profile can be applied in these cases, respectively.
60 |
61 | Finally, _extensions_ allow the schema to be extended using the framework without modification of the core schema. New attributes, objects, event classes, categories and profiles are all available to extensions. Existing profiles can be applied to extensions, and new extension profiles can be applied to core event classes and objects as well as to other extensions.
62 |
63 | The [schema browser](https://schema.ocsf.io) visually represents the categories, event classes, dictionary, data types, profiles and extensions in a navigable portal. The schema for an event class, and an event example for a class can be generated via menu options of the browser, which also serves as a validation server via the server APIs, whose documentation is also available from the browser.
64 |
65 | #### Comparison with MITRE ATT&CK[^3] Framework
66 |
67 | The MITRE ATT&CK Framework is widely used in the cybersecurity domain. While the purpose and content type of the two frameworks are different but complementary, there are some similarities with OCSF’s taxonomy that may be instructive to those with familiarity with ATT&CK.
68 |
69 | Categories are similar to Tactics, which have unique IDs. Event Classes are similar to Techniques, which have unique IDs. Profiles are similar to Matrices[^4], which have unique names. Type IDs are similar to Procedures which have unique IDs. Profiles can filter the Event Classes and Categories similar to how Matrices filter Techniques and Tactics.
70 |
71 | Differences from MITRE ATT&CK are that in OCSF, Event Classes are in only one Category, while MITRE ATT&CK Techniques can be part of multiple Tactics. Similarly MITRE ATT&CK Procedures can be used in multiple Techniques. MITRE ATT&CKTM has Sub-techniques while OCSF does not have Sub-Event Classes.[^5]
72 |
73 | OCSF is open and extensible by vendors, and end customers while the content within MITRE ATT&CKTM is released by MITRE.
74 |
75 | ## Attributes
76 |
77 | Attributes and the dictionary are the building blocks of a schema. This section discusses OCSF attribute conventions, requirements, groupings, constraints, and some of the special attributes used in the core cybersecurity schema.
78 |
79 | In general, an attribute from the dictionary has the same meaning everywhere it is used in a schema. Some attributes can have a meaning that is overloaded depending on the event class context where they are used. In these cases the description of the attribute will be generic and include a ‘see specific usage’ instruction to override its description within the event class context rather than in the dictionary.
80 |
81 | ### Conventions
82 |
83 | OCSF adheres to naming conventions in order to more easily identify attributes with similar semantics. These conventions take the form of standard suffixes and prefixes. The standard suffixes are:
84 |
85 | ```
86 | _id, _ids, _uid, _uuid, _ip, _name, _info, _detail, _time, _dt, _process, _ver, _list
87 | ```
88 |
89 | #### Arrays
90 |
91 | Attribute names used for arrays end with `s`. For example `category_ids`. A MITRE ATT&CKTM array is named `attacks`.
92 |
93 | #### Unique IDs
94 |
95 | Attribute names for classification values that are unique within the schema end with `_uid`. Schema classification attributes that have the `_uid` suffix are integers, preset by the schema definition (i.e. they must be populated as defined by the schema).
96 |
97 | Certain schema-unique attributes that also have a friendly name or caption have the same prefix but by convention use the `_name` suffix. For example, `class_uid` and `class_name`, or `category_uid` and `category_name`.
98 |
99 | Other attributes with the `_uid` suffix convention may be strings or integers, depending on their purpose, although the majority are strings.
100 |
101 | A `uid` core attribute is used wherever a producer or mapper populates an identifier for an entity object. Entity objects also have a corresponding `name` attribute by convention. Both are of type string (`string_t`).
102 |
103 | Attribute names for values that are globally unique end with _uuid. They do not have friendly names. For example GUIDs.
104 |
105 | #### Enum Attributes
106 |
107 | Attributes that are of an Enum integer type end with `_id`. Enum constant identifiers are integers from a defined set where each has a friendly name label. Arrays of enum attributes end with `_ids`.
108 |
109 | By convention, every Enum type has two common values with integer value 0 for `Unknown` and 99 for `Other`.
110 |
111 | If a source event has missing values that are required by the event class for that event, an `Unknown` value should be set for Enum types which is also the default.
112 |
113 | If a mapped event attribute does not have a defined enumeration value corresponding to a value of the event, `Other` is used which indicates that a sibling string attribute is populated with the custom attribute value. The sibling string attribute has the same name, minus the suffix. For example, `activity_id` and `activity`, or `severity_id` and `severity`.
114 |
115 | Sibling string attributes are optional, but if the enum value is `Other` (`99`) then the sibling string **must** be populated with the custom label (i.e. not “Other”).
116 |
117 | For all defined enumeration integer values, including `Unknown`, the enum label text for the item **may** populate the sibling string attribute. That is, both the integer value and the string attribute are set. If the Enum attribute is required, then both the integer attribute and the sibling string attribute **should** be populated. Attribute requirements are discussed in a subsequent section.
118 |
119 | ### Attribute Requirement Flags
120 |
121 | Attributes in the context of an event class have a requirement flag, that depends on the semantics of the event class. Attributes themselves do not have a requirement flag, only within the context of event classes.[^6]
122 |
123 | The requirement flags are:
124 |
125 | * Required
126 | * Recommended
127 | * Optional
128 |
129 | Event classes are designed so that the most essential attributes are required, to give enough meaning and context to the information reported by the data source. If an attribute is required, then a consumer of the event can count on the attribute being present, and its value populated. If a required attribute cannot be populated for a particular event class, a default value is defined by the event class, usually `Unknown`.[^7]
130 |
131 | Recommended attributes should be populated but cannot be in all cases and unlike required attributes are not subject to validation. They do not have default values.
132 | Optional attributes may be populated to add context and when data sources emit richer information.
133 | Data onboarders should place more weight on recommended attributes versus optional attributes.
134 |
135 | Some event classes may specify constraints on recommended attributes.
136 |
137 | ### Constraints
138 |
139 | A _Constraint_ is a documented rule subject to validation that requires at least one of the specified recommended attributes of a class to be populated. Constraints are used in classes where there are attributes that cannot be required in all use cases, but in order to have unambiguous meaning, at least one of the attributes in the constraint is required. Attributes in a constraint must be Recommended.
140 |
141 | The two constraints are: `at_least_one` and `just_one`. These will be explained further in the section on Event Classes.
142 |
143 | ### Attribute Groups
144 |
145 | Attributes are grouped for documentation purposes into _Primary_, _Classification_, _Occurrence_, and _Context_ groups. Classification and Occurrence groupings are independent of event class and are defined with the attribute in the dictionary. Primary and Context attributes’ groupings are based on their usage within a given event class.
146 |
147 | Each event class has primary attributes, the attributes that are indicative of the event semantics in all use cases. Primary attributes are typically Required, or Recommended per event class, based on their use in each class. Primary attributes in the Base Event class apply to all event classes.
148 |
149 | Attributes that are important for the taxonomy of the framework are designated as Classification attributes. The classification attributes are marked as Required as part of the Base Event class. Their values are nominally `Unknown` or `Other` and will be overridden within specific event classes.
150 |
151 | Attributes that are related to time and time ranges are designated as Occurrence attributes. The occurrence attributes may be marked with any requirement level, depending on their usage within an event class.
152 |
153 | Attributes that are used for variations on typical use cases, to enhance the meaning or enrich the content of an event are designated as Context attributes. The context attributes may be marked with any requirement level, but most often are marked as Optional.
154 |
155 | ### Timestamp and Datetime Attributes
156 |
157 | Representing time values is one of the most important aspects of OCSF. For an event schema it is even more important. There are time attributes associated with events that need to be captured in a number of places throughout the schema, for example when a file was opened or when a process started and stopped. There are also times that are directly related to the event stream, for example event creation, collection, processing, and logging. The nominal data type for these attributes is `timestamp_t` based on Unix time or number of milliseconds since the Unix epoch. The `datetime_t` data type represents times in human readable RFC3339 form.
158 |
159 | The Date/Time profile when applied adds a sibling attribute of data type `datetime_t `wherever a `timestamp_t `attribute appears in the schema.
160 |
161 | The following terms are used below:
162 |
163 | Event Producer -- the system (application, services, etc.) that generates events. Related to the producer persona.
164 |
165 | Event Consumer -- the system that receives the events generated by the event producer. Related to the analyst persona.
166 |
167 | Event Processor -- a system that processes and logs, including an ETL chain, the events received by the event consumer. Related to the mapper and analyst personas.
168 |
169 | The core time attributes may be present in all events as they are from the Base Event class. They are:
170 |
171 | * `original_time: string` \
172 | The original event time, as created by the event producer as part of the Metadata object of the Base Event class. The time format is not specified by OCSF and as such is a non-validated string. The time could be UTC time in milliseconds (1659378222123), ISO 8601 (2019-09-07T15:50-04:00), or any other value (12/13/2021 10:12:55 PM).
173 | * `time: timestamp_t` \
174 | The normalized event occurrence time. Normalized time means the original event time `original_time` is corrected for the clock skew of the source if any, and batch submission delay and after it was converted to the OCSF `timestamp_t`.
175 | * `processed_time: timestamp_t` \
176 | The time when the event (or batch of events) was sent by the event processor to the event consumer. The processed time can be used to determine the clock skew at the earliest known event source. Clock skew occurs when the UTC clock time on one computer differs from the UTC clock time on another computer. It is assumed that the transport latency is very small compared to the clock skew, therefore if the `processed_time` is very close to the `logged_time`, no correction should be made, notwithstanding any known hops.
177 | * `logged_time: timestamp_t` \
178 | The time when the event consumer logged the event. It must be equal or greater than the normalized event occurrence time.
179 | * `modified_time: timestamp_t` \
180 | The time when the event was last updated or enriched. It must be equal or greater than the normalized event occurrence time. It could be less-than, equal, or greater-than the `logged_time`.
181 | * `start_time/end_time: timestamp_t` \
182 | The start and end event times of the Base Event class are used when the event represents some activity that happened over a time range, for example a vulnerability or virus scan, or a discovery run. The other use-case is event aggregation. Aggregation is a mechanism that allows for a number of events of the same event type to be summarized into one for more efficient processing. For example netflow events. In this use case, the `count` integer attribute is also populated.
183 |
184 | #### Time Zone
185 |
186 | The time zone where the event occurred is represented by the `timezone_offset` attribute of data type Integer. Although time attributes are otherwise UTC except for the pass through attribute original_time, most security use cases benefit from knowing what time of day the event occurred at the event source.
187 |
188 | `timezone_offset` is the number of minutes that the reported event time is ahead or behind UTC, in the range -1,080 to +1,080. It is a recommended attribute of the Base Event class.
189 |
190 | ### Metadata
191 |
192 | Metadata is an object referenced by the required Base Event attribute `metadata`. As its name implies, the attribute is populated with data outside of the source event. Some of the attributes of the object are optional, such as `logged_time` and `uid`, while the `version` attribute is required - the schema version for the event. It is expected that a logging system _may_ assign the `logged_time` and `uid` at storage time.
193 |
194 | Metadata attributes such as `modified_time` and `processed_time` are optional. `modified_time` is populated when an event has been enriched or mutated in some way before analysis or storage. `processed_time` is populated typically when an event is collected and submitted to a logging system.[^8]
195 |
196 | **Version.** OCSF core schema version uses Semantic Versioning Specification (SemVer), e.g. `0.99.0,` which indicates to consumers of the event which attributes may be found in the event, and what the class and category structure are. The convention is that the major version, after `1.0.0`, or first part, remains the same while versions of the schema remain backwards compatible with previous versions of the schema and framework. As new classes, attributes, objects and profiles are added to the schema, the minor version, or second part of the version increases. The third part is reserved for corrections that don’t break the schema, for example documentation or caption changes.
197 |
198 | Extensions, discussed later, have their own versions and can change at their own pace but must remain compatible and consistent with the major version of the core schema that they extend. The optional `extension` attribute of type Schema Extension carries the version of an extension.
199 |
200 | ### Observables
201 |
202 | Observable is an object referenced by the primary Base Event class array attribute `observables`. It is populated from other attributes produced or mapped from the source event. An Observable object surfaces attribute information in one place irrespective of event class, while the security relevant indicators that populate the observable may occur in many places across event classes. In effect it is an array of summaries of those attributes regardless of where they stem from in the event based on their data type or object type (e.g. `ip_address`, `process`, `file`, etc).
203 |
204 | For example, an IP address may populate multiple attributes: `public_ip, intermediate_ips, ip` (as part of objects Endpoint, Device, Network Proxy, etc.). An analyst may be interested to know if a particular IP address is present anywhere in any event. Searching for the IP address value from the Base Event `observables` attribute surfaces any of these events more easily than remembering all of the attributes across all event classes that may have an IP address.
205 |
206 | There are three important attributes in the Observable object: `name`, `value`, and `type_id`. For scalar attributes within an event, all three observable attributes are populated, where the `type_id` declares what the type of attribute is, the `name` is the fully qualified attribute name within the event, and `value` is the value of that attribute.
207 |
208 | For complex (object type) attributes, Observable.`name` is the pointer or reference to the attribute, but as an object has more than one value, Observable.`value` is not populated.
209 |
210 | ```json
211 | "observables": [
212 | {
213 | "name": "actor.process.name",
214 | "type": "Process Name",
215 | "type_id": 9,
216 | "value": "Notepad.exe"
217 | },
218 | {
219 | "Name": "tls.ja3_hash",
220 | "Type": "Fingerprint",
221 | "Type_id": "30"
222 | },
223 | {
224 | "name": "file.name",
225 | "type": "File Name",
226 | "type_id": 7,
227 | "value": "Notepad.exe"
228 | }
229 | ]
230 | ```
231 |
232 | ### Enrichments
233 |
234 | Enrichment is an object referenced by the Base Event array attribute `enrichments`. An Enrichment object describes additional information added to the event during collection or event processing but before an immutable operation such as storage of the event. An example would be looking up location data on an IP address, or IOCs against a domain name or file hash.
235 |
236 | Because enriching data can be extremely open-ended, the object uses generic string attributes along with a JSON `data` attribute that holds an arbitrary enrichment in a form known to the processing system. Similar to the Observable object, `name` and `value` attributes are required to point to the event class attribute that is being enriched. Unlike Observable, there is no predefined set of attributes that are tagged for enrichment, therefore only a recommended `type` attribute is specified (i.e. there is no `type_id` Enum).
237 |
238 | Also unlike Observable, which is synchronized with the time of the event, it is assumed that there is some latency between the event time and the time the event is enriched, hence the Base Event class `metadata`.`modified_time` should be populated at the time of enrichment.
239 |
240 | For example
241 |
242 | ```json
243 | "metadata": {
244 | "logged_time": 1659056959885,
245 | "modified_time": 1659056959885,
246 | "processed_time": 1659056959885,
247 | "sequence": 69,
248 | "uid": "1310fc5c-0edb-11ed-88fc-0242ac110002",
249 | "version": "1.0.0"
250 | },
251 | "enrichments": [
252 | {
253 | "data": {
254 | "hash": "0c5ad1e8fe43583e279201cdb1046aea742bae59685e6da24e963a41df987494"
255 | },
256 | "name": "ip",
257 | "provider": "media.defense.gov",
258 | "type": "IP Address",
259 | "value": "103.216.221.19"
260 | },
261 | {
262 | "data": {
263 | "yara_rule": "rule \"wellmail_unique_strings\"{...}"
264 | },
265 | "name": "ip",
266 | "provider": "media.defense.gov",
267 | "type": "IP Address",
268 | "value": "103.216.221.19"
269 | }
270 | ]
271 | ```
272 |
273 | ## Event Classes
274 |
275 | **Events are represented by instances of Event Classes**, which are particular sets of attributes and objects representing a log line or telemetry submission at a point in time. Event classes have semantics that describe what happened: either a particular activity, disposition or both.
276 |
277 | It is the intent of the schema to allow for the mapping of any raw event to a single event class. This is achieved by careful design using composition rather than a multiple inheritance approach. In order to completely capture the information in a rich data source, many attributes may be required.
278 |
279 | Unfortunately, not every data source emits the same information for the same observed behavior. In the interest of consistency, accuracy and precision, the schema event classes specify which dictionary attributes are essential, (recommended or required), while others are optional as not all are needed across different data sources. Attribute requirements, aside from Classification attributes from the Base Event class, are always within the scope of the event class definition and not tied to the attributes themselves.
280 |
281 | By convention, all event classes extend the Base Event event class. Attributes of the Base Event class can be present in any event class and are termed Base Attributes.
282 |
283 | ### Base Event Class Attributes
284 |
285 | The Base Event class has required, recommended, and optional attributes that apply to all core schema classes. The required attributes must be populated for every core schema event. Optional Base Event class attributes may be included in any event class, along with event class-specific optional attributes. Individual event classes will include their own required and recommended attributes.
286 |
287 | Examples of required base attributes are `class_uid`, `category_uid`, `activity_id`, `severity_id`.
288 |
289 | Examples of recommended base attributes are `timezone_offset, status_id, message.`
290 |
291 | Examples of optional base attributes are `activity_name`, `start_time`, `end_time`, `count`, `duration`, `unmapped`.
292 |
293 | **Each event class has a unique `class_uid` attribute value** which is the event class identifier. It is a required attribute whose value overrides the nominal Base Event class value of `0`. Event class friendly names are defined by the schema, optionally populate the `class_name` attribute and are descriptive of the specific class, such as File System Activity or Process Activity.
294 |
295 | **Every event class has a `category_uid` attribute value** which indicates which OCSF Category the class belongs to. An event class may be of only one category. Category friendly names are defined by the schema, optionally populate the category_name
attribute and are descriptive of the specific category the class belongs to, such as System Activity or Network Activity.
296 |
297 | **Every event class has an `activity_id` Enum attribute**, constrained to the values appropriate for each event class. The semantics of the class are further defined by the `activity_id` attribute, such as Open for File System Activity or Launch for Process Activity. By convention, `activity_id` Enum labels are present tense imperatives. The Enum label optionally may populate the `activity_name` attribute, which is a sibling to the `activity_id` Enum attribute but as a Classification group attribute, follows the `_name` suffix convention.
298 |
299 | ### Special Base Attributes
300 |
301 | There are a few base attributes that are worth calling out specifically. These are the `unmapped` attribute, the `raw_data` attribute and the `type_uid` attribute.
302 |
303 | While most if not all fields from a raw event can be parsed and tokenized, not all are mapped to the schema. The fields that are not mapped may be included with the event in the optional `unmapped` attribute.
304 |
305 | The `raw_data` optional attribute holds the event data as received from the source. It is unparsed and represented as a String type.
306 |
307 | The `type_uid` required attribute is constructed by the combination of the event class of the event (`class_uid`) and its activity (`activity_id`). It is unique across the schema hence it has a `_uid` suffix. The `type_uid` friendly name, `type_name,` is a way of identifying the event in a more readable and complete way. It too is a combination of the names of the two component parts.
308 |
309 | The value is calculated as: `class_uid` `* 100 + activity_id`. For example:
310 |
311 | `type_uid` = `3001 * 100 + 1 = 300101`
312 |
313 | `type_name` = “Authentication: Logon”
314 |
315 | A snippet of a File Activity event example with random values is shown below[^9]:
316 |
317 | ```json
318 | {
319 | "activity_id": 11,
320 | "activity_name": "Decrypt",
321 | "actor": {},
322 | "category_name": "System Activity",
323 | "category_uid": 1,
324 | "class_name": "File System Activity",
325 | "class_uid": 1001,
326 | "device": {},
327 | "end_time": 1685403212867,
328 | "file": {},
329 | "message": "entry queue amateur",
330 | "metadata": {},
331 | "observables": [],
332 | "severity": "Low",
333 | "severity_id": 2,
334 | "start_time": 1685403212792,
335 | "status": "img logs grove",
336 | "status_detail": "barrier filled clothes",
337 | "time": 1685403212834,
338 | "type_name": "File System Activity: Decrypt",
339 | "type_uid": 100111
340 | }
341 | ```
342 |
343 | ### Constraints
344 |
345 | As discussed in a previous section, an event class can have constraints that are more versatile than simple Required attribute requirements. When at least one of a set of recommended attributes must be present, the class can assert the `at_least_one` constraint:
346 |
347 | ```json
348 | "constraints": {
349 | "at_least_one": [
350 | "ip",
351 | "mac",
352 | "name",
353 | "hostname"
354 | ]
355 | }
356 | ```
357 |
358 | Or the `just_one` constraint:
359 |
360 | ```json
361 | "constraints": {
362 | "just_one": [
363 | "privileges",
364 | "group"
365 | ]
366 | }
367 | ```
368 |
369 | ### Associations
370 |
371 | Attributes within an event class are sometimes associated with each other and in some cases only one of them is present in the event while another may be looked up at processing or storage time. OCSF denotes this within a class definition via the association construct:
372 |
373 | ```json
374 | "associations": {
375 | "actor.user": [
376 | "src_endpoint"
377 | ],
378 | "dst_endpoint": [
379 | "user"
380 | ],
381 | "src_endpoint": [
382 | "actor.user"
383 | ],
384 | "user": [
385 | "dst_endpoint"
386 | ]
387 | }
388 | ```
389 |
390 | In this example from the Authentication class, the `user` as actor associates with its endpoint, the `src_endpoint` attribute of the class, while the target `user` associates with its endpoint, the `dst_endpoint` of the class. Note that the associations in this class are bi-directional, which is common, although uni-directional associations are also possible in other situations.
391 |
392 | The construct may be useful for automated processing systems where a lookup service is available for an attribute that isn’t or can’t be populated via the source event producer. In these cases the `processor_time` should be populated at the time of the association, as with other types of enrichments.
393 |
394 | ## Categories
395 |
396 | **A Category organizes event classes that represent a particular domain.** For example, a category can include event classes for different kinds of events that may be found in an access log, or audit log, or network and system events. Each category has a unique `category_uid` attribute value which is the category identifier. Category IDs also have `category_name` friendly name attributes, such as System Activity, Network Activity, Audit, etc.
397 |
398 | An example of categories with some of their event classes is shown in the below table.
399 |
400 | | **System Activity** | **Network Activity** | **Identity & Access Management** | **Findings** | **Discovery** | **Application Activity** |
401 | | ------------------------- | --------------------- | -------------------------------- | ---------------- | --------------------- | ---------------------------- |
402 | | File System Activity | Network Activity | Account Change | Security Finding | Device Inventory Info | Web Resources Activity |
403 | | Kernel Extension Activity | HTTP Activity | Authentication | | Device Config State | Application Lifecycle |
404 | | Kernel Activity | DNS Activity | Authorize Session | | | API Activity |
405 | | Memory Activity | DHCP Activity | Entity Management | | | Web Resrouce Access Activity |
406 | | Module Activity | RDP Activity | User Access Management | | | |
407 | | Scheduled Job Activity | SMB Activity | Group Management | | | |
408 | | Process Activity | SSH Activity | | | | |
409 | | | FTP Activity | | | | |
410 | | | Email Activity | | | | |
411 | | | Network File Activity | | | | |
412 | | | Email File Activity | | | | |
413 | | | Email URL Activity | | | | |
414 |
415 |
416 | Finding the right granularity of categories is an important modeling topic. Categorization is weakly structural while event classification is strongly structural (i.e. it defines the particular attributes, their requirements, and specific Enum values for the event class).
417 |
418 | Many events produced in a cloud platform can be classified as network activity. Similarly, many host system events include network activity. The key question to ask is, do the logs from these services and hosts provide the same context or information? Would there be a family of event classes that make sense in a single category? For example, does the NLB Access log provide context/info similar to a Flow log? Does network traffic from a host provide similar information to a firewall or router? Are they structured in the same fashion? Do they share attributes? Would we obscure the meaning of these logs if we normalize them under the same category? Would the resultant category make sense on its own or will it lose its contextual meaning all together?
419 |
420 | Using profiles, some of these overlapping categorical scenarios can be handled without new partially redundant event classes.
421 |
422 | ## Profiles
423 |
424 | **Profiles are overlays on event classes and objects,** effectively a dynamic mix-in class of attributes with their requirements and constraints. While event classes specialize their category domain, a profile can augment existing event classes with a set of attributes independent of category. Attributes that must or may occur in any event class are members of the Base Event class. Attributes that are specialized for selected classes are members of a profile.
425 |
426 | Multiple profiles can be added to an event class via an array of profile values in the optional `profiles` attribute of the Base Event class. This mix-in approach allows for reuse of event classes vs. creating new classes one by one that include the same attributes. Event classes and instances of events that support the profile can be filtered via the `profiles` attribute across all categories and event classes, forming another dimension of classification.
427 |
428 | For example, a `Security Controls` profile that adds MITRE ATT&CKTM Attack and Malware objects to System Activity classes avoids having to recreate a new event class, or many classes, with all of the same attributes as the System Activity classes. A query for events of the class will return all the events, with or without the security information, while a query for just the profile will return events across all event classes that support the `Malware` profile. A `Host` profile can add `Device`, and `Actor` objects to Network Activity event classes when the network activity log source is a user’s computer. Note that the `Actor` object includes `Process` and `User` objects, so a Host profile can include all of these when applied. A Cloud profile could mix-in cloud platform specific information onto Network Activity events.
429 |
430 | The `profiles` attribute is an optional array attribute of the Base Event class. The absence of the `profiles` attribute means no profile attributes are added as would be expected. Attributes defined with a profile have requirements that cannot be overridden, since profiles are themselves optional; it is assumed that the application of a profile is because those attributes are desired and can be populated.
431 |
432 | However some classes, such as System Activity classes, build-in the attributes of a profile, for example the `Host` profile attributes `device` and `actor` are defined in the class. When a class definition includes the profile attributes, it still registers for that profile in the class definition so as to match any searches across events for that profile. In this case the class defined attribute requirement definitions take precedence.
433 |
434 | Core schema profiles for `Security Control`, `Host`, `Cloud`, `Container` and `Linux` (for the Linux extension described later) are shown in the below table with their attributes.
435 |
436 | | **Security Control** | **Host** | **Cloud** | **Container** | **Linux** |
437 | | :--------------------------- | -------- | --------- | ------------- | --------- |
438 | | attacks | actor | api | container | group |
439 | | disposition_id / disposition | device | cloud | namespace_pid | euid |
440 | | malware | | | | egid |
441 | | | | | | auid |
442 |
443 | A special `Date/Time` profile adds `Datetime` typed time attributes in every class where there is a `Timestamp` time attribute. This allows for human readable RFC-3339 strings paired with epoch UTC integer values.
444 |
445 | Other profiles could be product oriented, such as Firewall, IDS, VA, DLP etc. if they need to add attributes to existing classes. They can also be more general, platform oriented, such as for Mac, Linux or Windows environments.
446 |
447 | The core schema comes with a Linux profile via the Linux platform extension.
448 |
449 | Vendors can add profiles via extensions. For example, Splunk Technical Add-ons might define a profile that could be added to all events with Splunk’s standard `source`, `sourcetype`, `host` attributes.
450 |
451 | ### Disposition
452 |
453 | The `disposition_id` attribute of the Security Control profile indicates the outcome or state of the event class’ activity at the time of event capture and is an Enum with a standard set of values, such as Blocked, Quarantined, Deleted, Delayed.
454 |
455 | Only event classes that register for the profile may have a `disposition_id` but all have an `activity_id`. A typical use of `disposition_id` is when a security protection product detects a threat and blocks it. The activity might have been a file open, but if the file was infected, the disposition would be that the file open was blocked. As of this writing, `disposition_id` is added to core schema classes only via the Security Controls profile.
456 |
457 | ### Profile Application Examples
458 |
459 | Using example categories and event classes from a preceding section, examples of how profiles might be applied to event classes are shown below.
460 |
461 | #### System Activity
462 |
463 | The event classes **would** all include the Host profile and **may** include the Security Controls or Cloud profile.
464 |
465 | #### Network Activity
466 |
467 | The event classes **may** include the Host profile and **may** include the Security Controls or Cloud profile.
468 |
469 | #### Identity & Access Management
470 |
471 | The event classes **would** include the Host profile, (due to actor.user), **may **include the Cloud profile, and **would not** include the Security Control profile.
472 |
473 | ### Personas and Profiles
474 |
475 | The personas called out in an earlier section, producer, author, mapper, analyst, all can consider the profile from a different perspective.
476 |
477 | Producers, who can also be authors, can add profiles to their events when the events will include the additional information the profile adds. For example a vendor may have certain system attributes that are added via an extension profile. A network vendor that can detect malware would apply the Security Controls profile to their events. An endpoint security vendor can apply the Host, User and Security Controls profile to network events.
478 |
479 | Authors define profiles, and the profiles are applicable to specific classes, objects or categories.
480 |
481 | Mappers can add the profile ID and associated attributes to specific events mapped to logs in much the same way producers would apply profiles.
482 |
483 | Analysts, e.g. end users, can use the browser to select applicable profiles at the class level. They can use the profile identifier in queries for hunting, and can use the profile identifiers for analytics and reporting. For example, show all malware alerts across any category and class.
484 |
485 | ## Extensions
486 |
487 | OCSF schemas can be extended by adding new attributes, objects, categories, profiles and event classes. A schema is the aggregation of core schema entities and extensions.
488 |
489 | Extensions allow a particular vendor or customer to create a new schema or augment an existing schema.[^10] Extensions can also be used to factor out non-essential schema domains keeping a schema small. Extensions to the core schema use the framework in the same way as a new schema, optionally creating categories, profiles or event classes from the dictionary. Extensions can add new attributes to the dictionary, including new objects. Extended attribute names can be the same as core schema names but this is not a good practice for a number of reasons. As with categories, event classes and profiles, extensions have unique IDs within the framework as well as versioning.[^11]
490 |
491 | As of this writing, two platform extensions augment the core schema: Linux and Windows. The Linux extension adds a profile, while the Windows extension adds three classes to the System Activity category.
492 |
493 | Another use of extensions to the core schema is the development of new schema artifacts, which later may be promoted into the core schema or to a platform extension. Another use of extensions is to add vendor specific extensions in addition to the core schema. In this case, a best practice is to prefix the schema artifacts with a short identifier associated with the extension range registered.[^12] Lastly, as mentioned above, entirely new schemas can be constructed as extensions.
494 |
495 | Examples of new experimental categories, new event classes that contain some new attributes and objects are shown in the table below with a `Dev` extension superscript convention. In the example, extension classes were added to the core Findings category, and three extension categories were added, Policy, Remediation and Diagnostic, with extension classes.
496 |
497 | | **Findings** | **PolicyDev** | **RemediationDev** | **DiagnosticDev** |
498 | | ------------------------------------ | ------------------------------------------ | --------------------------------------------- | ---------------------------- |
499 | | Incident CreationDev | Clipbaord Content ProtectionDev | File RemediationDev | CPU UsageDev |
500 | | Incident AssociateDev | ComplianceDev | Folder RemediationDev | Memory UsageDev |
501 | | Incident ClosureDev | Compliance ScanDev | Startup Application RemediationDev | ThroughputDev |
502 | | Incident UpdateDev | Content ProtectionDev | User Session RemediationDev | |
503 | | Email Delivery FindingDev | Information ProtectionDev | | |
504 |
505 |
506 | A brief discussion of how to extend the schema is found in Appendix C.
507 |
508 | ## Appendix A - Guidelines and Conventions
509 |
510 | ### Guidelines for attribute names
511 |
512 | * Attribute names must be a valid UTF-8 sequence.
513 | * Attribute names must be all lower case.
514 | * Combine words using underscore.
515 | * No special characters except underscore.
516 | * Reserved attributes are prefixed with an underscore.
517 | * Use present tense unless the attribute describes historical information.
518 | * `activity_id` enum labels should be present tense. For example, `Delete`. `disposition_id` enum labels should be past tense. For example, `Blocked.`
519 | * Use singular and plural names properly to reflect the attribute content. \
520 | For example, use `events_per_sec` rather than `event_per_sec`.
521 | * When an attribute represents multiple entities, the attribute name should be pluralized and the value type should be an array. \
522 | Example: `process.loaded_modules` includes multiple values -- a loaded module names list.
523 | * Avoid repetition of words where possible. \
524 | Example: `device.device_ip` should be `device.ip`.
525 | * Avoid abbreviations when possible. \
526 | Some exceptions can be made for well-accepted abbreviations. Example: `ip`, or `os`.
527 | * For vendor extensions to the dictionary, prefix attribute names with a 3-letter moniker in order to avoid name collisions. Example: `aws_finding, spk_context_ids`.
528 |
529 | ## Appendix B - Data Types
530 |
531 | Refer to [https://schema.ocsf.io/data_types](https://schema.ocsf.io/data_types) for the OCSF data types and their validation constraints.
532 |
533 | ## Appendix C - Schema Construction and Extension
534 |
535 | The OCSF schema repository can be found at [https://github.com/ocsf/ocsf-schema](https://github.com/ocsf/ocsf-schema).
536 |
537 | The repository is structured as follows:
538 |
539 | | **File or Folder** | **Purpose** |
540 | | ------------------ | :------------------------------------------------------------------------------------ |
541 | | categories.json | the schema categories are defined and must be present for classes to be in a category |
542 | | dictionary.json | the schema dictionary is where all attributes must be defined |
543 | | version.json | the schema semver version, every change to the schema requires this file be updated |
544 | | enums/ | the schema enum definitions, optional if enums are shared |
545 | | events/ | the schema event classes |
546 | | extensions/ | the schema extensions, a similar structure is set per extension |
547 | | includes/ | the schema shared files |
548 | | objects/ | the schema object definitions |
549 | | profiles/ | the schema profiles |
550 |
551 | For information and examples about how to add to the schema, see [CONTRIBUTING.md](https://github.com/ocsf/ocsf-schema/blob/a46b6df1d60ad052739caa96c29109e9b233ef82/CONTRIBUTING.md) in the OCSF GitHub.
552 |
553 | ### Extending the Schema
554 |
555 | To extend the schema create a new directory using a unique extension name (e.g. dev) in the extensions directory. The directory structure is the same as the top level repository structure above, and it may contain the following files and subdirectories, depending on what type of extension is desired:
556 |
557 | | **File or Folder** | **Purpose** |
558 | | ------------------ | --------------------------------------------------------------------- |
559 | | categories.json | Create to define a new event category to reserve a range of class IDs |
560 | | dictionary.json | Create to define new attributes |
561 | | events/ | Create to define new event classes |
562 | | objects/ | Create to define new objects |
563 | | profiles/ | Create to define new profiles |
564 |
565 | In order to reserve an ID space, and make your extension public, add a UID to your extension name in the OCSF Extensions Registry [here](https://github.com/ocsf/ocsf-schema/blob/main/extensions.md) to avoid collisions with core or other extension schemas. For example, the dev extension would have a row in the table as follows:
566 |
567 | | **Extension Name** | **Type** | **UID** | **Notes** |
568 | | ------------------ | -------- | ------- | --------------------------------- |
569 | | Development | dev | 999 | The development schema extensions |
570 |
571 | New categories and event classes will have their unique IDs offset by the UID.
572 |
573 | More information about extending existing schema artifacts can be found at [extending-existing-class.md](https://github.com/ocsf/ocsf-schema/blob/a46b6df1d60ad052739caa96c29109e9b233ef82/doc/extending-existing-class.md).
574 |
575 |
576 | ## Notes
577 |
578 | [^1]:
579 | OCSF includes concepts and portions of the ICD Schema, developed by Symantec, a division of Broadcom and has been generalized and made open under Apache 2 license with their permission.
580 |
581 | [^2]:
582 | For the most up-to-date guidelines and data types, refer to the schema browser at [https://schema.ocsf.io](https://schema.ocsf.io).
583 |
584 | [^3]:
585 | MITRE ATT&CKTM: https://attack.mitre.org/
586 |
587 | [^4]:
588 | MITRE ATT&CKTM Matrix: https://attack.mitre.org/matrices/enterprise/
589 |
590 | [^5]:
591 | The internal source definition of an OCSF schema can be hierarchical but the resulting compiled schema does not expose sub classes.
592 |
593 | [^6]:
594 | Event class validation is enforced via the required attributes, in particular the classification attributes, which by necessity need to be kept to a minimum, as well as attribute data type validation and the event class structure
595 |
596 | [^7]:
597 | Required attributes that cannot be populated due to information missing from a data source must be carried with the event as _unknown_ values - asserting that the information was missing.
598 |
599 | [^8]:
600 | Note that a non-trivial difference between the processed_time and the logged_time in UTC may indicate a clock synchronization problem with the source of the event (but not necessarily the actual source of the event if there is an intermediate collection system or forwarder).
601 |
602 | [^9]:
603 | Objects have been collapsed to save space. You can generate full examples with dummy data at [https://schema.ocsf.io/doc/swagger.json](https://schema.ocsf.io/doc/swagger.json) or from within the browser.
604 |
605 | [^10]:
606 | An extension does not need to extend the core schema base class if it is a new schema.
607 |
608 | [^11]:
609 | Reserved identifier ranges are registered within a file in the project GitHub repository. Extended events should populate the `metadata.version` attribute with the extended schema version.
610 |
611 | [^12]:
612 | The Schema Browser will label extensions with a superscript.
613 |
--------------------------------------------------------------------------------
/Understanding OCSF.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ocsf/ocsf-docs/100ce76a6a2657fadf5a11cedf8a7a84ac6dd76c/Understanding OCSF.pdf
--------------------------------------------------------------------------------