Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question about multi-layered or nested relationship structure #852

Open
chripluEri opened this issue Dec 24, 2024 · 0 comments
Open

Question about multi-layered or nested relationship structure #852

chripluEri opened this issue Dec 24, 2024 · 0 comments

Comments

@chripluEri
Copy link

chripluEri commented Dec 24, 2024

Given a product consisting of multiple services each consisting of multiple assemblies which consist of multiple libraries/packages, how to best describe the relationships?

Example Product P1

image

This is a simplified representation, containing only two Services S1, S2, and the Services S1, S2 containing only two assemblies A1 and A2, and the assemblies only containing one library. But in reality, the product can contain multiple services, each service can contain many assemblies, and each assembly can contain many libraries.

Vulnerability CVE1 in library L1

Let's assume, a vulnerability CVE1 is discovered in library L1. How do we represent the different vulnerability product status information?

Table representation

Product Service Assembly Library CVE VEX Status Flag
P1, v1 S1, v1 A1, v1 L1, v1 CVE1 Known_not_affected vulnerable_code_not_in_execute_path
P1, v1 S1, v1 A2, v1 L1, v1 CVE1 Known_affected
P1, v1 S2, v1 A1, v1 L1, v1 CVE1 Known_not_affected vulnerable_code_cannot_be_controlled_by_adversary
P1, v1 S2, v1 A2, v1 L1, v1 CVE1 Known_not_affected inline_mitigations_already_exist

The difference is that assembly A2 as component of Service S1 is known_affected, while A2 is as component of S1 is not affected, nor are the assemblies of S2 affected.

The yellow and the black arrows in the diagram distinguish the different paths via S1 or S2.
Essentially, the product has 4 different paths through which the vulnerability in library L1 can affect the product and all of these paths can have different characteristics (equivalent to the rows in the above table):

  • Path 1: P1-S1-A1-L1
  • Path 2: P1-S1-A2-L1
  • Path 3: P1-S2-A1-L1
  • Path 4: P1-S2-A2-L1

If assemblies are container images, then vulnerability scanning can be performed on the container image level and it is useful to preserve the information which assembly or image is affected.

How can we represent the same information in CSAF?

Below I use CSAF-pseudo-code to simplify a possibly CSAF representation:
Assuming the product, service and assemblies are from vendor V1, the library from vendor V2. In order to distinguish the library as component of an assembly that belongs to a specific service, we need to use relationships of relationships.

Product_tree
	- Vendor: V1
		- product name: Product P1 
			- Product version: P1v1
		- product name: Service S1 
			- Product version: S1v1
		- product name: Service S2 
			- Product version: S2v1
		- product name: Assembly A1 
			- Product version: A1v1
		- product name: Assembly A2 
			- Product version: A2v1
	- Vendor: V2
		- product name: Library L1
			- Product version: L1v1
	- Relationships
		- Rel1: S1v1 is default_component_of P1v1
		- Rel2: S2v1 is default_component_of P1v1
		- Rel3: A1v1 is default_component_of Rel1
		- Rel4: A2v1 is default_component_of Rel1
		- Rel5: A1v1 is default_component_of Rel2
		- Rel6: A2v1 is default_component_of Rel2
		- Rel7: L1v1 is default_component_of Rel3
		- Rel8: L1v1 is default_component_of Rel4
		- Rel9: L1v1 is default_component_of Rel5
		- Rel10: L1v1 is default_component_of Rel6

Without Relationships of Relationships
For the discussion, the simple relationships referencing products directly and not relationships, would not allow to differentiate the path P1-S1-A2-L1 from the path P1-S2-A2-L1. Example with simple relationships:

Relationships

- 	Rel1: S1v1 is default_component_of P1v1
- 	Rel2: S2v1 is default_component_of P1v1
- 	Rel3: A1v1 is default_component_of S1v1
- 	Rel4: A2v1 is default_component_of S1v1
- 	Rel5: A1v1 is default_component_of S1v1
- 	Rel6: A2v1 is default_component_of S1v1
- 	Rel7: L1v1 is default_component_of A1v1
- 	Rel8: L1v1 is default_component_of A2v1

Relationships of Relationships

Using the relationship of relationship approach where the "relates_to_product_reference" references the product_id of another relationship, we can differentiate each of the above described four paths through which the library L1 is a component of the product P1.
Using this approach the vulnerability part of the CSAF could like the following in pseudo-code:

Vulnerabilities
	- CVE1
		- Product_status
			- Known_affected
				- Rel8
			- Known_not_affected
				- Rel7
				- Rel9
				- Rel10

Problem Statement

The above example product might seem particularly complex. However, with cloud native microservice based architecture, a product with a four-layer component tree with services that contain assemblies (like pods, container images or VM images) is not uncommon. The above pseudo-code exemplifies how such a complex product component tree can be represented in CSAF using relationships of relationships.

The problem with relationships of relationships
In my view, the problem with this approach is its complexity. This is not simple and likely to invite misunderstanding and mistakes. It also adds significant boilerplate json to the CSAF. For describing four distinct path, we require 10 relationship objects. Of these 10 different relationship objects, only the last 4 are actually used in the vulnerability object e.g. in status-statements, scores, remediation, flags...

The problem of not using relationships of relationships
One could argue that simplicity shall beat complexity and that the above example is purely theoretical. Furthermore, if one path (here Path 2: P1-S1-A2-L1) shows that the whole product is affected, why bother with the details about the other paths?

Loss of information
Given cloud native and microservice based architectures, the above product example is not purely theoretical. VA scans on container images, pods or VM images are common and aggregating the scan results for a complex product into a single big table is an obvious activity. Therefore, the above table representation is also not uncommon.
If the product vulnerability information aggregated into a simple table cannot be represented in CSAF without the loss of information (ability to differentiate between different paths), then this can be seen as limitation of CSAF.

Questions for Discussion and Options

Can you follow my line of thinking and the problem statement or am I misunderstanding the CSAF standard?

The way I see it is that sooner or later the need to represent and differentiate different paths in which a library can affect a complex product component tree will emerge. Since currently, there is little documentation on how to address this, this can easily lead to various less compatible approaches and misunderstandings. Therefore, would like to hear your thoughts on the following questions:

  • Does it make sense to discourage the use of relationships of relationships? This would avoid above complexity but reduce the ability of CSAF to represent product vulnerability information with product component trees of (3) 4 and more layers. I think this would be a significant limitation of CSAF.

  • Would it make sense to define a simple representation of component-paths? Two different approaches could be interesting to consider:

    • Extending the existing relationship object with an array of intermediate compound components product_ids. This might be the simplest approach. However, it would set the category of the relationship only once for all referenced product_ids including the intermediate ones. This could make sense if all referenced products are default_component_of.
    • Create a new "relationship-path"-object (or more suitably named object) to represent a single path from root node to leaf node via multiple intermediary nodes. This more complex object could specify the relationship category for each referenced product_id.

Quick drafts

1 Extending relationship-object

{
    "category": "default_component_of",
    "full_product_name": {
        "name": "L1v1 as component of P1v1",
        "product_id": "P1v1:S1v1:A1v1:L1v1"
    },
    "product_reference": "L1v1",
    "relates_to_product_reference": "P1v1",
   "intermediary_product_ids": [ "A1v1", "S1v1"]
}

2 Extending relationship-object

{
"category": "default_component_of",
    "full_product_name": {
        "name": "L1v1 as component of P1v1",
        "product_id": "P1v1:S1v1:A1v1:L1v1"
    },
    "product_reference": "L1v1",
    "relates_to_product_reference": "P1v1",
    "intermediary_products": [
        {
            "category": "default_component_of",
            "relates_to_product_reference": "A1v1"
        },
        {
            "category": "default_component_of",
            "relates_to_product_reference": "S1v1"
        }
    ]
}

Christoph Plutte, TC member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant