๐Ÿ•ต๏ธ Njsscan : ะกะตะผะฐะฝั‚ะธั‡ะตัะบะธะน ะธะฝัั‚ั€ัƒะผะตะฝั‚ SAST, ะบะพั‚ะพั€ั‹ะน ะผะพะถะตั‚ ะฝะฐั…ะพะดะธั‚ัŒ ะฝะตะฑะตะทะพะฟะฐัะฝั‹ะต ะฟะฐั‚ั‚ะตั€ะฝั‹ ะบะพะดะฐ ะฒ ะฟั€ะธะปะพะถะตะฝะธัั… Node.js |

๐Ÿ•ต๏ธ Njsscan : ะกะตะผะฐะฝั‚ะธั‡ะตัะบะธะน ะธะฝัั‚ั€ัƒะผะตะฝั‚ SAST, ะบะพั‚ะพั€ั‹ะน ะผะพะถะตั‚ ะฝะฐั…ะพะดะธั‚ัŒ ะฝะตะฑะตะทะพะฟะฐัะฝั‹ะต ะฟะฐั‚ั‚ะตั€ะฝั‹ ะบะพะดะฐ ะฒ ะฟั€ะธะปะพะถะตะฝะธัั… Node.js

ะžะฑะทะพั€ั‹

Njsscan – ัั‚ะพ ะธะฝัั‚ั€ัƒะผะตะฝั‚ ัั‚ะฐั‚ะธั‡ะตัะบะพะณะพ ั‚ะตัั‚ะธั€ะพะฒะฐะฝะธั ะฟั€ะธะปะพะถะตะฝะธะน (SAST), ะบะพั‚ะพั€ั‹ะน ะผะพะถะตั‚ ะฝะฐะนั‚ะธ ะฝะตะฑะตะทะพะฟะฐัะฝั‹ะต ะฟะฐั‚ั‚ะตั€ะฝั‹ ะบะพะดะฐ ะฒ ะฒะฐัˆะธั… ะฟั€ะธะปะพะถะตะฝะธัั… node.js, ะธัะฟะพะปัŒะทัƒั ะฟั€ะพัั‚ะพะน ัะพะฟะพัั‚ะฐะฒะธั‚ะตะปัŒ ัˆะฐะฑะปะพะฝะพะฒ ะธะท libsast ะธ ะธะฝัั‚ั€ัƒะผะตะฝั‚ ัะตะผะฐะฝั‚ะธั‡ะตัะบะพะณะพ ะฟะพะธัะบะฐ ัˆะฐะฑะปะพะฝะพะฒ ะบะพะดะฐ semgrep, ัƒั‡ะธั‚ั‹ะฒะฐัŽั‰ะธะน ัะธะฝั‚ะฐะบัะธั.

ะฃัั‚ะฐะฝะพะฒะบะฐ

pip install njsscan

ะขั€ะตะฑัƒะตั‚ัั Python 3.6+ ะธ ะฟะพะดะดะตั€ะถะธะฒะฐะตั‚ัั ั‚ะพะปัŒะบะพ Mac ะธ Linux

ะŸะฐั€ะฐะผะตั‚ั€ั‹ ะบะพะผะฐะฝะดะฝะพะน ัั‚ั€ะพะบะธ

$ njsscan
usage: njsscan [-h] [โ€“json] [โ€“sarif] [โ€“sonarqube] [โ€“html] [-o OUTPUT] [-c CONFIG] [โ€“missing-controls] [-w] [-v] [path โ€ฆ]
positional arguments:
path Path can be file(s) or directories with source code
optional arguments:
-h, โ€“help show this help message and exit
โ€“json set output format as JSON
โ€“sarif set output format as SARIF 2.1.0
โ€“sonarqube set output format compatible with SonarQube
โ€“html set output format as HTML
-o OUTPUT, โ€“output OUTPUT
output filename to save the result
-c CONFIG, โ€“config CONFIG
Location to .njsscan config file
โ€“missing-controls enable missing security controls check
-w, โ€“exit-warning non zero exit code on warning
-v, โ€“version show njsscan version

ะŸั€ะธะผะตั€ั‹ ะธัะฟะพะปัŒะทะพะฒะฐะฝะธั

$ njsscan test.js
Pattern Match โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 1
Semantic Grep โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 160
njsscan: v0.1.9 | Ajin Abraham | opensecurity.in
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•คโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ••
โ”‚ RULE ID โ”‚ express_xss โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ OWASP โ”‚ A1: Injection โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ CWE โ”‚ CWE-79: Improper Neutralization of Input During Web Page Generation (โ€˜Cross-site Scriptingโ€™) โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ DESCRIPTION โ”‚ Untrusted User Input in Response will result in Reflected Cross Site Scripting Vulnerability. โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ SEVERITY โ”‚ ERROR โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ FILES โ”‚ โ•’โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•คโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•• โ”‚
โ”‚ โ”‚ โ”‚ File โ”‚ test.js โ”‚ โ”‚
โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚
โ”‚ โ”‚ โ”‚ Match Position โ”‚ 5 โ€“ 46 โ”‚ โ”‚
โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚
โ”‚ โ”‚ โ”‚ Line Number(s) โ”‚ 7: 8 โ”‚ โ”‚
โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚
โ”‚ โ”‚ โ”‚ Match String โ”‚ const { name } = req.query; โ”‚ โ”‚
โ”‚ โ”‚ โ”‚ โ”‚ res.send(โ€˜Hello :โ€™ + name + โ€œโ€) โ”‚ โ”‚
โ”‚ โ”‚ โ•˜โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•งโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•› โ”‚
โ•˜โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•งโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•›

nodejsscan SAST

nodejsscan, ัะพะฑั€ะฐะฝะฝั‹ะน ะฝะฐ ะฑะฐะทะต njsscan, ะฟั€ะตะดะพัั‚ะฐะฒะปัะตั‚ ะฟะพะปะฝะพั†ะตะฝะฝั‹ะน ะฟะพะปัŒะทะพะฒะฐั‚ะตะปัŒัะบะธะน ะธะฝั‚ะตั€ั„ะตะนั ะดะปั ัƒะฟั€ะฐะฒะปะตะฝะธั ัƒัะทะฒะธะผะพัั‚ัะผะธ, ะฐ ั‚ะฐะบะถะต ะดั€ัƒะณะธะต ะฟะพะปะตะทะฝั‹ะต ะธะฝั‚ะตะณั€ะฐั†ะธะธ.

Python API

from njsscan.njsscan import NJSScan
node_source = โ€˜/node_source/true_positives/sqli_node.jsโ€™
scanner = NJSScan([node_source], json=True, check_controls=False)
scanner.scan()
{
โ€˜templatesโ€™: {},
โ€˜nodejsโ€™: {
โ€˜node_sqli_injectionโ€™: {
โ€˜filesโ€™: [{
โ€˜file_pathโ€™: โ€˜/node_source/true_positives/sqli_node.jsโ€™,
โ€˜match_positionโ€™: (1, 24),
โ€˜match_linesโ€™: (4, 11),
โ€˜match_stringโ€™: โ€˜var employeeId = req.foo;\n\nvar sql = โ€œSELECT * FROM trn_employee WHERE employee_id = โ€ + employeeId;\n\n\n\nconnection.query(sql, function (error, results, fields) {\n\n if (error) {\n\n throw error;\n\n }\n\n console.log(results);โ€™
}],
โ€˜metadataโ€™: {
โ€˜owaspโ€™: โ€˜A1: Injectionโ€™,
โ€˜cweโ€™: โ€œCWE-89: Improper Neutralization of Special Elements used in an SQL Command (โ€˜SQL Injectionโ€™)โ€,
โ€˜descriptionโ€™: โ€˜Untrusted input concatinated with raw SQL query can result in SQL Injection.โ€™,
โ€˜severityโ€™: โ€˜ERRORโ€™
}
}
},
โ€˜errorsโ€™: []
}

ะะฐัั‚ั€ะพะนะบะฐ njsscan

ะคะฐะนะป .njsscan ะฒ ะบะพั€ะฝะต ะบะฐั‚ะฐะปะพะณะฐ ะธัั…ะพะดะฝะพะณะพ ะบะพะดะฐ ะฟะพะทะฒะพะปัะตั‚ ะฝะฐัั‚ั€ะพะธั‚ัŒ njsscan.

ะ’ั‹ ั‚ะฐะบะถะต ะผะพะถะตั‚ะต ะธัะฟะพะปัŒะทะพะฒะฐั‚ัŒ ะฟะพะปัŒะทะพะฒะฐั‚ะตะปัŒัะบะธะน ั„ะฐะนะป .njsscan, ะธัะฟะพะปัŒะทัƒั ะฐั€ะณัƒะผะตะฝั‚ –config.

nodejs-extensions:
.js
template-extensions:
.new
.hbs
โ€
ignore-filenames:
skip.js
ignore-paths:
__MACOSX
skip_dir
node_modules
ignore-extensions:
.jsx
ignore-rules:
regex_injection_dos
pug_jade_template
severity-filter:
WARNING
ERROR

ะ˜ะฝั‚ะตะณั€ะฐั†ะธั CI/CD

ะ’ั‹ ะผะพะถะตั‚ะต ะฒะบะปัŽั‡ะธั‚ัŒ njsscan ะฒ ัะฒะพะธ ะฟะฐะนะฟะปะฐะนะฝั‹ CI/CD ะธะปะธ DevSecOps.

Github Action

ะ”ะพะฑะฐะฒัŒั‚ะต ัะปะตะดัƒัŽั‰ะตะต ะฒ ั„ะฐะนะป .github/workflows/njsscan.yml.

name: njsscan
on:
push:
branches: [ master, main ]
pull_request:
branches: [ master, main ]
jobs:
njsscan:
runs-on: ubuntu-latest
name: njsscan check
steps:
โ€“ name: Checkout the code
uses: actions/checkout@v2
โ€“ name: nodejsscan scan
id: njsscan
uses: ajinabraham/njsscan-action@master
with:
args: โ€˜.โ€™

ะ˜ะฝั‚ะตะณั€ะฐั†ะธั ัะบะฐะฝะธั€ะพะฒะฐะฝะธั ะบะพะดะฐ Github

ะ”ะพะฑะฐะฒัŒั‚ะต ัะปะตะดัƒัŽั‰ะตะต ะฒ ั„ะฐะนะป .github/workflows/njsscan_sarif.yml.

name: njsscan sarif
on:
push:
branches: [ master, main ]
pull_request:
branches: [ master, main ]
jobs:
njsscan:
runs-on: ubuntu-latest
name: njsscan code scanning
steps:
โ€“ name: Checkout the code
uses: actions/checkout@v2
โ€“ name: nodejsscan scan
id: njsscan
uses: ajinabraham/njsscan-action@master
with:
args: โ€˜. โ€“sarif โ€“output results.sarif || trueโ€™
โ€“ name: Upload njsscan report
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: results.sarif

Gitlab CI/CD

ะ”ะพะฑะฐะฒัŒั‚ะต ัะปะตะดัƒัŽั‰ะตะต ะฒ ั„ะฐะนะป .gitlab-ci.yml.

stages:
โ€“ test
njsscan:
image: python
before_script:
โ€“ pip3 install โ€“upgrade njsscan
script:
โ€“ njsscan .

Travis CI

ะ”ะพะฑะฐะฒัŒั‚ะต ัะปะตะดัƒัŽั‰ะตะต ะฒ ั„ะฐะนะป .travis.yml.

language: python
install:
โ€“ pip3 install โ€“upgrade njsscan
script:
โ€“ njsscan .

Circle CI

ะ”ะพะฑะฐะฒัŒั‚ะต ัะปะตะดัƒัŽั‰ะตะต ะฒ ั„ะฐะนะป .circleci/config.yaml

version: 2.1
jobs:
njsscan:
docker:
โ€“ image: cimg/python:3.9.6
steps:
โ€“ checkout
โ€“ run:
name: Install njsscan
command: pip install โ€“upgrade njsscan
โ€“ run:
name: njsscan check
command: njsscan .

Docker

ะ“ะพั‚ะพะฒั‹ะน ะพะฑั€ะฐะท ะธะท DockerHub

docker pull opensecurity/njsscan
docker run -v /path-to-source-dir:/src opensecurity/njsscan /src

ะกะพะฑั€ะฐั‚ัŒ ะปะพะบะฐะปัŒะฝะพ:

docker build -t njsscan .
docker run -v /path-to-source-dir:/src njsscan /src
ะกะšะะงะะขะฌ

ัะผ. ั‚ะฐะบะถะต:

 

ะŸะพะถะฐะปัƒะนัั‚ะฐ, ะฝะต ัะฟะฐะผัŒั‚ะต ะธ ะฝะธะบะพะณะพ ะฝะต ะพัะบะพั€ะฑะปัะนั‚ะต. ะญั‚ะพ ะฟะพะปะต ะดะปั ะบะพะผะผะตะฝั‚ะฐั€ะธะตะฒ, ะฐ ะฝะต ัะฟะฐะผะฑะพะบั. ะะตะบะปะฐะผะฝั‹ะต ััั‹ะปะบะธ ะฝะต ะธะฝะดะตะบัะธั€ัƒัŽั‚ัั!
ะ”ะพะฑะฐะฒะธั‚ัŒ ะบะพะผะผะตะฝั‚ะฐั€ะธะน