policy: add WDAC integration on Windows #50644
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Last year, I spoke with @bmeck @mhdawson and @RafaelGSS about extending the chain of trust of node policy files into the OS. Work has been done on the OS side to better support language interpreters with code integrity, and now we're ready to integrate this work with NodeJS.
This is intended to be a draft PR to demonstrate what the proposed changes are and to facilitate discussion around OS code integrity integration on Windows. I will submit an issue so we can discuss this in further detail during the next security wg meeting.
Changes
Added an alternate option to --policy-integrity so the integrity of the policy can be rooted in the OS.
The alternative option is --policy-signature which is a path to a PKCS7 detached signature of the policy file.
The policy signature is verified using the OS CI policy system. On Windows, this uses WDAC.
On *nix this is stubbed out.
Added a query to WDAC to see if a policy file and signature are mandatory for Node to run.
Windows Code Integrity (WDAC)
Official WDAC docs
WDAC is Window's code integrity enforcement system. Using WDAC, system administrators can define policy rules that dictate which executables can be run on a system where WDAC is enabled. One of the criteria they can define is a set of valid signing keys. EXEs and DLLs have signatures embedded into them (in headers and other "unused" blocks within the file) which are validated when loaded. Since interpreted languages don't use the standard EXE and DLL loading entry points, and the code which they interpret can be various file types, enforcement by the OS is difficult. There needs to be some cooperation between the OS and the language runtime.
Node policies seem like a natural point we can integrate with WDAC. In the current form, however, a Node policy manifest can be altered on disk. This can be mitigated with the --policy-integrity option. However, this can be bypassed if an attacker can modify the command parameters. We're proposing linking the chain of trust into something the OS trusts, rather (or in addition to) a command line parameter. To do this, the manifest is signed with a PKCS7 detached signature. This adds another layer of security, since now a trusted signing key would need to be compromised to use NodeJS on a locked-down system.
This can be done with signtool with
signtool sign /p7 .\ /p7co 1.2.840.113549.1.7.2 /p7ce Pkcs7DetachedSignedData /fd sha256 /f key.pfx node_policy.json
Or OpenSSL with
openssl smime -sign -binary -in policy.json -signer signer.pem -inkey signer.key -outform DER -out policy.json.p7s
This signature can then be passed in along with a Node policy.
node.exe --experimental-policy policy.json --policy-signature policy.json.p7s app.js
If the OS is configured to enforce code integrity for Node, Node will not execute unless both a policy and its signature are provided and pass WDAC's verification. From that point, integrity enforcement is delegated to Node's manifest/policy subsystem.
Some questions that I have: