usnistgov / SCAP

The repository will be used to track issues and post specifications related to the Security Automation Protocol (SCAP).
1 stars 0 forks source link

Update XCCDF to support passing data from OCIL to OVAL by means of "hybrid" variables #3

Open vanderpol opened 3 weeks ago

vanderpol commented 3 weeks ago

Some policies are written which to not clearly define the exact requirement to be verified, but state things such as "verify that the database owner matches system documentation". Without the ability to pass the end user provided data from OCIL to OVAL, this can only be a manual test, but if we pass data to OVAL, then this can be automated, based on end user feedback.

This has been implemented in the SCAP Compliance Checker (SCC) application for the last few years, primarily in support of DISA's SQL STIG content. Examples can be found at https://www.niwcatlantic.navy.mil/Technology/SCAP/SCAP-Content-Repository/. The current SCC implementation overloads the existing check-content element with several pieces of delimited data, which is all schema valid, but only will work in SCC. Our goal here is to provide the capability to any SCAP content/SCAP application that supports both OVAL and OCIL. We have dubbed this check type as "hybrid" as it's a combination of manual and automated tests.

The specific format in XCCDF is open for discussion/debate, but below is a potential solution. Essentially taking our check-content overloaded method and clearly specifying the attributes.

Example:

Add a new element name called "check-content-hybrid" of datatype checkContentHybridType

<xsd:element name="check-content-hybrid" minOccurs="0" maxOccurs="1" type="cdf:checkContentHybridType">
    <xsd:annotation>
        <xsd:documentation xml:lang="en">Holds data obtained from an OCIL questionnaire, which is used to populate an external variable in an OVAL check.  This allows for end users to define the required policy for certain policy situations.  These hybrid variables should only be used in OVAL states, in order to prevent malicious data injections into OVAL objects. </xsd:documentation>
    </xsd:annotation>
</xsd:element>

Where checkContentHybridType is (refer to #1) for details on new targetType


<xsd:complexType name="checkContentHybridType">
    <xsd:annotation>
        <xsd:documentation xml:lang="en"> Data type for the &lt;xccdf:check-content-ref&gt; element, which points to the code for a detached check in another file. This element has no body, just a
            couple of attributes: @href and @name. The @name is optional, if it does not appear then this reference is to the entire document. </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="variable-name" type="xsd:string">
        <xsd:annotation>
            <xsd:documentation xml:lang="en">Identifies the name of the OVAL external variable to be populated with data from OCIL questionnaire.</xsd:documentation>
        </xsd:annotation>
    </xsd:attribute>
    <xsd:attribute name="target" type="cdf:targetType">
        <xsd:annotation>
            <xsd:documentation xml:lang="en">Identifies the target of the hybrid variable being passed from OCIL to OVAL.</xsd:documentation>
        </xsd:annotation>
    </xsd:attribute>
    <xsd:attribute name="datatype" type="cdf:hybridDataEnumType">
        <xsd:annotation>
            <xsd:documentation xml:lang="en">Identifies the type of data being passed from OCIL to OVAL.</xsd:documentation>
        </xsd:annotation>
    </xsd:attribute>
    <xsd:attribute name="element-name" type="xsd:string">
        <xsd:annotation>
            <xsd:documentation xml:lang="en">Identifies the name of the data being passed from OCIL to OVAL, primarily for end user displying purposes in OCIL.</xsd:documentation>
        </xsd:annotation>
    </xsd:attribute>

</xsd:complexType>

    <xsd:simpleType name="hybridDataEnumType">
        <xsd:annotation>
            <xsd:documentation xml:lang="en"> Allowed values to specify which type of data is being passed from OCIL to OVAL for a hybrid check.</xsd:documentation>
        </xsd:annotation>
        <xsd:restriction base="xsd:string">
            <xsd:enumeration value="array">
                <xsd:annotation>
                    <xsd:documentation xml:lang="en">Denotes data being passed is an array of strings</xsd:documentation>
                </xsd:annotation>
            </xsd:enumeration>
            <xsd:enumeration value="single">
                <xsd:annotation>
                    <xsd:documentation xml:lang="en">Denotes data being passed is a single string. </xsd:documentation>
                </xsd:annotation>
            </xsd:enumeration>
        </xsd:restriction>
    </xsd:simpleType>

Example usage:

<xccdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5" selector="">
    <xccdf:check-content-ref name="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:def:21" href="U_MS_SQL_Server_2016_Instance_V3R1_STIG_SCAP_1-3_Benchmark-enhancedV3-oval.xml"/>
    <xccdf:check-content-ref name="ocil:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst.hybrid:questionnaire:21" href="U_MS_SQL_Server_2016_Instance_V3R1_STIG_SCAP_1-3_Benchmark-enhancedV3-ocil.xml"/>
    <xccdf:check-content-hybrid>variable-name="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:var:21" target="dbmsinstance" datatype="array" element-name="user_name"</xccdf:check-content-hybrid>
</xccdf:check>
vanderpol commented 3 weeks ago

@solind, This one is a bit more 'out there', but SCC uses it to process the DISA STIGS's for SQL, and we likely will be using this for some OS checks as well, where the DISA STIG says "make sure that the system setting is configured to match approved system documentation". End user provided data from OCIL is used as an external variable that we then use in a state.

If you want to see it in action, just grab a copy of SCC and view the manual questions for the SQL Instance or SQL Database STIG, this proposal just formalizes our overloaded method of using the check-content field as a delimited list of data.

solind commented 3 weeks ago

@vanderpol This is an interesting (by which I mean terrifying) idea!

What would you say to modifying the XCCDF set-value element so that it could reference any check-content? It would need some kind of a check-import child identifying what it's supposed to retrieve, maybe via XPATH. I'm fuzzy on the details, but I recall implementing check-import, so @maxullman or @A-Biggs could weigh in with those.

vanderpol commented 3 weeks ago

@solind, given that we've been using the equivalent of the proposed schema change for the past year in production level content, I'd personally prefer not having to redesign our implementation, unless there is a 'better' alternate proposal. If you can mock up in more detail what you saying above, my opinion my change.

solind commented 3 weeks ago

Hi @vanderpol , your proposal said:

The specific format in XCCDF is open for discussion/debate, but below is a potential solution.

... and then you explicitly asked me for my opinion. I'm purely a volunteer offering you feedback, I'm not looking to create more work for anyone, least of all myself.

Looking closely at your schema mods and example, I think you meant to write it as follows:

<xccdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5" selector="">
    <xccdf:check-content-ref name="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:def:21" href="U_MS_SQL_Server_2016_Instance_V3R1_STIG_SCAP_1-3_Benchmark-enhancedV3-oval.xml"/>
    <xccdf:check-content-ref name="ocil:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst.hybrid:questionnaire:21" href="U_MS_SQL_Server_2016_Instance_V3R1_STIG_SCAP_1-3_Benchmark-enhancedV3-ocil.xml"/>
    <xccdf:check-content-hybrid variable-name="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:var:21" target="dbmsinstance" datatype="array" element-name="user_name" />
</xccdf:check>

The big change to your original example was to express your check-content-hybrid tag's content as entity attributes, not string content.

But, I must admit, I'm confused about what the above example means. I am guessing that it's supposed to somehow tie together a variable sourced from executed OCIL to a variable value used by the OVAL check. But I don't see how it does that. What's the name of the variable being exported to the OVAL? What's the name of the answer value being imported from the OCIL questionnaire? How does the interpreter know which check is which?

The behavior for multiple check-content-refs is already defined in XCCDF as specifying multiple locations for the same check, in order of preference, only one of which must be evaluated. But this defined behavior doesn't exactly seem to apply here.

My suggestion was merely that you might want to consider modifying an already-defined mechanism for passing values into checks.

vanderpol commented 3 weeks ago

@solind Sorry, I wasn't meaning to ask for your input and then reject it... I was primarily looking to see if our implementation made any sense from a SCAP perspective. When I designed this functionality in SCC a couple years ago, I'll admit that I wasn't thinking this would end up being officially part of SCAP (primarily because SCAP seemed like it was in a coma, and I wasn't sure if any feature release would occur), but after seeing your confusion with the data I provided, I realized there is some magic going on behind the scenes to make it all work. I'll write up exactly what SCC is doing, and we'll see if this can somehow be converted into something ready for XCCDF/SCAP. If we deem that it's really just best for a proprietary implementation, that's fine too. Given that all we have going on with updating OVAL 5.12 and OVAL 6.0, and the very limited timeframe to get XCCDF/SCAP updated, this may not be in scope. I am open to your set-value concepts, I'm just not sure I'm going to be the one designing it right now. If doing so provides what we need, without some of our behind the scenes magic, then I'm all for it.

vanderpol commented 3 weeks ago

Below is a behind the scenes explanation of how the proposed update to XCCDF is used in our implementation. If this update is accepted as part of XCCDF 1.3/SCAP 3.0, the XCCDF documentation may need to have something similar to below in order to adequately explain how it should be implemented.

  1. If both OVAL and OCIL check-content refs exist for the same check, and the overall check system is "OVAL", this is a "hybrid" test, process the OCIL content first: Example:

    <xccdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5" selector="">
    <xccdf:check-content-ref name="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:def:21" href="U_MS_SQL_Server_2016_Instance_V3R1_STIG_SCAP_1-3_Benchmark-enhancedV3-oval.xml"/>
    <xccdf:check-content-ref name="ocil:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst.hybrid:questionnaire:21" href="U_MS_SQL_Server_2016_Instance_V3R1_STIG_SCAP_1-3_Benchmark-enhancedV3-ocil.xml"/>
    <xccdf:check-content-hybrid variable-name="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:var:21" target="dbmsinstance" datatype="array" element-name="user_name" />
    </xccdf:check>
  2. The results from this OCIL test will not directly be returned back to XCCDF, and to prevent any confusion, we setup the test to always return UNKNOWN, we didn't want anyone seeing pass/fail results in OCIL XML when compared to the OVAL and XCCDF results.

    
    <string_question_test_action question_ref="ocil:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst.hybrid:question:21" 
                                id="ocil:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst.hybrid:testaction:21">
      <title>CAT I, V-213930, SV-213930r960768, SRG-APP-000023-DB-000001</title>
    <when_pattern>
        <result>UNKNOWN</result>
        <pattern>^.*$</pattern>
    </when_pattern>
    </string_question_test_action>
Enter the list of database user names authorized and documented to manage SQL Server
The "target", "datatype" and "element-name" are used determine what type of interface to provide to the end user in order to best gather the data.   For example, if you only want a single item returned, you don't want to give the user the ability to enter an array of data etc...  See attached screen shot for an example. 

![hybrid_interface](https://github.com/user-attachments/assets/e8cb7d6f-b2a9-4dd2-a8b5-7048975fda66)

3.  The application should analyze the results of the OCIL string_question, and store the data as an array of strings (or a single string), and associate this data with the variable defined in check-content-hybrid variable-name
4.  Before the OVAL scanning starts, the application should programmatically populate the OVAL external variable using the data from step 3.

5.  The external variable is then used as a state element as the 'requirement'

<independent-def:sql512_state xmlns="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" version="1" comment="If the accounts authorized to manage this SQL Server intance are documented and approved, this is not a finding. " id="oval:navy.navwar.niwcatlantic.scc.ms.sql.server.2016.inst:ste:22">

````` The only real 'magic' here is steps 3 and 4, where the application has to process the OCIL string_question and cache the results, and then populate the OVAL external variable based on that data. I considered using the existing check-export functionality for part of this, but my understanding at the time was that exported Values from XCCDF had to be single elements, such as a single string or a single integer, plus I really wanted to pass long the target, datatype and element-name in order to provide context when asking questions to get the correct data back. Additionally, I felt that giving the application the ability to analyze the text provided by the end user and determine if it seems valid/safe before just blindly accepting the data was wise. This may not be the 'best' from the SCAP view, but felt 'right' from a software developer view. If there is a better way to capture the same pieces of data that makes more sense with the XCCDF spec, I'm open to any suggestion. This worked for us, and was pretty simple to implement.
solind commented 2 weeks ago

OK, I think we can eliminate all the "magic" by coming up with a way to implement this functionality largely using existing constructs. The existing mechanism for setting variable values is through the Profile set-value tag. There is also an existing mechanism to import values from check systems (although they currently only end up showing up in XCCDF TestResults).

Imagine that we come up with a new tag called xccdf:set-value-from-check. It could have an xccdf:check child element, which could support any SCAP check system (OCIL, or OVAL). The check element would be required to contain the following:

  1. A check-import element, with an import-xpath attribute defining how to fetch the value derived from the corresponding check system's result output or an import-name specifying a something readily retrievable from results like the ID of a question or variable.
  2. A check-content-ref element, which identifies the OCIL href and questionnaire ID, or OVAL href and definition ID to run.

Putting this together would signal the interpreter that it needs to run the specified piece of content to retrieve the value of the Value, when the corresponding Profile is selected.

I think it would be a lot simpler to document this method of implementing your requirement.

vanderpol commented 2 weeks ago

@solind thanks for your thoughts on this, sorry for my delayed response, I've been out of the office. Would you be willing to mock up some tiny XCCDF 1.3 content that demonstrates this? Would this hypothetical implementation be able to support setting a list/array of values vs a single value? I'm not an XCCDF expert, but it was my understanding that the current set Value only supported a single value.

solind commented 2 weeks ago

Well, you can always use the SplitFunctionType to break apart a single string value into multiple variable values. There's also the possibility of using the "complex" values in XCCDF 1.3.

I'll try and put together an XML snippet later today to illustrate what I'm proposing.

vanderpol commented 1 week ago

@solind just a reminder to drop an XML snippet out here when you get a chance. Our next SCAP 3.0 meeting is tomorrow, and would like to give Dragos an update as to if we think this feature is going to be feasible for SCAP 3.0 or not.

solind commented 1 week ago

OK, so here's a snippet illustrating how you could use a Profile to set an XCCDF Value from the value of a variable found in an OVAL check.

<xccdf:Profile id="xccdf_net.solin_profile_david_writes_a_snippet">
    <xccdc:set-value-from-check idref="xccdf_net.solin_value_check_derived">
        <xccdf:check system="http://oval.mitre.org/XMLSchema/oval-definitions-5">
            <xccdf:check-import import-name="oval:net.solin:var:123">
            <xccdf:check-content-ref href="ovaldefs.xml" name="oval:net.solin:def:123"/>
        </xccdf:check>
    </xccdc:set-value-from-check>
</xccdf:Profile>
vanderpol commented 1 week ago

@solind thanks, and it's likely me being a bit dense, but could you expand this to show how you'd set that XCCDF value based on the result of an OCIL check, and then use that as a variable in OVAL?

solind commented 1 week ago

@vanderpol sure, in that case we just insert an OCIL check. In this example it would import the value of a variable.

<xccdf:Profile id="xccdf_net.solin_profile_david_writes_a_snippet">
    <xccdc:set-value-from-check idref="xccdf_net.solin_value_check_derived">
        <xccdf:check system="http://scap.nist.gov/schema/ocil/2">
            <xccdf:check-import import-name="ocil:net.solin:variable:123">
            <xccdf:check-content-ref href="questionnaire.xml" name="ocil:some.checklist:questionnaire:1"/>
        </xccdf:check>
    </xccdc:set-value-from-check>
</xccdf:Profile>

The import-name attribute of check-import in XCCDF is not well-specified. I made a best-guess of what I thought would make sense for OVAL and OCIL and SCE so that the import-name could specify something meaningful in the results documents. BUT, I also implemented the optional import-xpath attribute, which runs an XPATH query against the XML results document -- this makes it possible to unambiguously specify what you want to retrieve.

vanderpol commented 1 week ago

Thanks again @solind I'll have to dive into the OCIL spec to see about how I would update the content to have the results end up as variables. Seems doable, just need to put on my OCIL hat, which I have not warn in years.

solind commented 1 week ago

@vanderpol it wouldn't necessarily have to be a variable value. It could be a question answer or artifact or something else, too. The interpreter just has to "know" how to retrieve the value given the check system and associated conventions for the "value-name".

vanderpol commented 2 days ago

@solind, I haven't had much free time to try to prototype this, but I have a couple questions/concerns that maybe you can help me understand this better.

  1. How in your example would the content author designate what the delimiter would be (assuming we are going to split them apart later in OVAL?) If you have ideas on how to make XCCDF Values handle an array of elements I'm all ears.
  2. Any ideas as to how/where we would go about indicating of the data to be returned is desired to be a single value or an array of values?
  3. Any ideas how to pass in the user friendly name for what we are asking for (aka 'username') etc..

I realize my questions 2 and 3 are not 'critical' 'to making this work, but they are pretty key to making it user friendly.

solind commented 1 day ago

Hi @vanderpol, answers below:

  1. The method that doesn't require any new thinking would be to do it all inside the OVAL. If your Value is a string that looks like "a,b,c,d", then you'd export it to an OVAL variable, (we'll call it var:1). Then, another OVAL variable, var:2, would be defined (keeping in mind this isn't precisely valid OVAL):
<local_variable id="var:2">
  <split delimiter=",">
    <variable_component var_ref="var:1"/>
  </split>
</local_variable>

Now, var:2 is your multi-valued variable (i.e., array).

  1. Using the above method, if it's a single value with no delimiters, then the value of var:2 will already be identical to var:1, so no conversion would be necessary.
  2. I'm not quite sure what you mean. If you mean, like, you want to grab the string value of some result element directly, you'd need to use an XPATH. It could be fairly simple (as simple as XPATH gets), like "//registry_item/value" -- this requires, of course, that you've collected something simple like a single registry_item.

Alternatively, you could add an attribute to xccd:check-import that would permit some custom import naming convention, but then you have to define exactly how it works.

vanderpol commented 1 day ago

@solind for 1 above, what I'm asking is how do you tell the OCIL interpreter which delimiter to create when exporting the variable back to XCCDF before we import it into OVAL. I could see where different tools may use different delimiters and being able to specify what to use would be key. Maybe I'm missing something here. The Value is based on what the end user enters, and maybe we you just explain it to the end user to put the data using comma separated delimiters etc... but in our implementation we allowed for CSV, new line etc... and then we cleaned up the data and then output our cleaned variable. In our limited examples commas were always fine, but the data may need some other delimiter.

For 2 above, this is really just me trying to make our application to be smarter in how to display what to ask for. We update the GUI based on if we are expecting 1 result or N results, and we update the GUI to say what we want. Not a showstopper, just a nice to have.

image

If SCC is really going to be the only tool using Hybrid variables and actually implementing all of this it may make more sense for us to just leave it proprietary.

solind commented 1 day ago

@vanderpol Alas, I haven't touched OCIL in a very long time! But, my thinking was that we're dealing with the result format of the specified check system and nothing else, so in this case, OCIL results. If you intend to parse raw user input, the user would have to write an answer that's compatible with whatever parsing you've implemented on the importing side. The job of XCCDF here is just to transport a value obtained from a result to an imported variable value.

We could add an attribute to the RegexCaptureFunctionType that would make it possible to produce multiple values (currently it captures the first instance and nothing more). That would make it possible to implement more robust parsing of imported variable values.

Of course, you can always keep the custom implementation. I'm just trying to suggest a mechanism that is more straightforward (in my opinion, anyway) to standardize.

vanderpol commented 1 day ago

I'll reach out to DISA to see if they have any interest/plans to do any OCIL/OVAL hybrid tests. If they seem at all interested, we'll continue this R&D. I do appreciate your input, and in past conversations with DISA I think their thoughts on this were closer to inline with your thoughts, so we may end up going there. If it's just NIWC doing their own thing, I'm not sure we want to redesign what we are doing, and end up with a less user friendly experience.