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

policy: add WDAC integration on Windows #50644

Closed
wants to merge 1 commit into from

Conversation

rdw-msft
Copy link

@rdw-msft rdw-msft commented Nov 9, 2023

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:

  • I couldn't find where in the Node project calls to OS functions are located, so I put them alongside the other win32 methods in UV. Please let me know if there's a better place
  • I have tested this on Windows with a couple VMs on different OS versions. However, I don't know what the best course of action is for adding unit tests, since this is an OS integration feature. I'm open to any suggestions you have.

Added an alternative 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 WLDP.
On *nix this is stubbed out.

Additionally, added a check to query the policy system to see if a
policy file and signature are mandatory for node to run.
@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/security-wg

@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Nov 9, 2023
@rdw-msft
Copy link
Author

Early feedback from @RafaelGSS is to move code out of libuv and provide examples of the threat and how this mitigates it.

I will be doing this as soon as possible, but I will be on vacation soon and likely will not push any changes until after the new year.

Does anyone have any suggestions on the most appropriate place move the code within the node project?

@rdw-msft rdw-msft closed this Feb 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants