62 lines
1.7 KiB
Plaintext
62 lines
1.7 KiB
Plaintext
== How to fix it in Node.js
|
|
|
|
=== Code examples
|
|
|
|
include::../../common/fix/code-rationale.adoc[]
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,javascript,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
const { execSync } = require('child_process')
|
|
|
|
cmd = req.query.cmd
|
|
execSync(cmd) // Noncompliant
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,javascript,diff-id=1,diff-type=compliant]
|
|
----
|
|
const { spawnSync } = require('child_process')
|
|
|
|
const cmdId = parseInt(req.query.cmdId)
|
|
let host = req.query.host
|
|
host = typeof host === "string"? host : "example.org"
|
|
|
|
const allowedCommands = [
|
|
{exe:"/bin/ping", args:["-c","1","--"]},
|
|
{exe:"/bin/host", args:["--"]}
|
|
]
|
|
const cmd = allowedCommands[cmdId]
|
|
spawnSync(cmd.exe, cmd.args.concat(host))
|
|
----
|
|
|
|
=== How does this work?
|
|
|
|
include::../../common/fix/introduction.adoc[]
|
|
|
|
include::../../common/fix/pre-approved-list.adoc[]
|
|
|
|
In the example compliant code, a static list of trusted commands is used. Users are only allowed to
|
|
submit an index in this array in place of a full command name.
|
|
|
|
:sanitizationLib: child_process.spawn
|
|
include::../../common/fix/sanitize-meta-characters.adoc[]
|
|
|
|
In the example compliant code, the `spawn` function from `child_process` is used in place of its less
|
|
secure `exec` counterpart. It accepts command arguments as an array and
|
|
performs a proper escaping of its element before building the command line to
|
|
run.
|
|
|
|
include::../../common/fix/shell_integration.adoc[]
|
|
|
|
The `spawn` function that is used in the example compliant code disables shell integration by default.
|
|
|
|
=== Pitfalls
|
|
|
|
include::../common/pitfalls/loose-typing.adoc[]
|
|
|
|
In the above compliant code example, the ambiguous `concat` function is used.
|
|
However, a type check has been introduced to prevent any unexpected issue.
|