Skip to content

Commit

Permalink
Merge pull request #297 from NodeSecure/prepare-major-8
Browse files Browse the repository at this point in the history
Prepare major 8
  • Loading branch information
fraxken authored Aug 16, 2024
2 parents 81e44c5 + 32e71b3 commit 1fb55a9
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 425 deletions.
164 changes: 9 additions & 155 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ The analysis will return: `http` (in try), `crypto`, `util` and `fs`.
> [!TIP]
> There is also a lot of suspicious code example in the `./examples` cases directory. Feel free to try the tool on these files.
## API

- [AstAnalyser](./docs/api/AstAnalyser.md)
- [EntryFilesAnalyser](./docs/api/EntryFilesAnalyser.md)

## Warnings

This section describes how use `warnings` export.
Expand Down Expand Up @@ -118,7 +123,7 @@ import * as i18n from "@nodesecure/i18n";
console.log(i18n.getTokenSync(jsxray.warnings["parsing-error"].i18n));
```

## Warnings Legends
### Legends

This section describe all the possible warnings returned by JSXRay. Click on the warning **name** for additional information and examples.

Expand All @@ -131,161 +136,10 @@ This section describe all the possible warnings returned by JSXRay. Click on the
| [encoded-literal](./docs/encoded-literal.md) || An encoded literal has been detected (it can be an hexa value, unicode sequence or a base64 string) |
| [short-identifiers](./docs/short-identifiers.md) || This mean that all identifiers has an average length below 1.5. |
| [suspicious-literal](./docs/suspicious-literal.md) || A suspicious literal has been found in the source code. |
| [suspicious-file](./docs/suspicious-file.md) | ✔️ | A suspicious file with more than ten encoded-literal in it |
| [suspicious-file](./docs/suspicious-file.md) | | A suspicious file with more than ten encoded-literal in it |
| [obfuscated-code](./docs/obfuscated-code.md) | ✔️ | There's a very high probability that the code is obfuscated. |
| [weak-crypto](./docs/weak-crypto.md) | ✔️ | The code probably contains a weak crypto algorithm (md5, sha1...) |
| [shady-link](./docs/shady-link.md) | ✔️ | The code contains shady/unsafe link |

## Custom Probes

You can also create custom probes to detect specific pattern in the code you are analyzing.

A probe is a pair of two functions (`validateNode` and `main`) that will be called on each node of the AST. It will return a warning if the pattern is detected.
Below a basic probe that detect a string assignation to `danger`:

```ts
export const customProbes = [
{
name: "customProbeUnsafeDanger",
validateNode: (node, sourceFile) => [
node.type === "VariableDeclaration" && node.declarations[0].init.value === "danger"
],
main: (node, options) => {
const { sourceFile, data: calleeName } = options;
if (node.declarations[0].init.value === "danger") {
sourceFile.addWarning("unsafe-danger", calleeName, node.loc);

return ProbeSignals.Skip;
}

return null;
}
}
];
```

You can pass an array of probes to the `runASTAnalysis/runASTAnalysisOnFile` functions as `options`, or directly to the `AstAnalyser` constructor.

| Name | Type | Description | Default Value |
|------------------|----------------------------------|-----------------------------------------------------------------------|-----------------|
| `customParser` | `SourceParser \| undefined` | An optional custom parser to be used for parsing the source code. | `JsSourceParser` |
| `customProbes` | `Probe[] \| undefined` | An array of custom probes to be used during AST analysis. | `[]` |
| `skipDefaultProbes` | `boolean \| undefined` | If `true`, default probes will be skipped and only custom probes will be used. | `false` |


Here using the example probe upper:

```ts
import { AstAnalyser } from "@nodesecure/js-x-ray";

// add your customProbes here (see example above)

const scanner = new AstAnalyser({
customProbes,
skipDefaultProbes: true
});

const result = scanner.analyse("const danger = 'danger';");

console.log(result);
```

Result:

```sh
✗ node example.js
{
idsLengthAvg: 0,
stringScore: 0,
warnings: [ { kind: 'unsafe-danger', location: [Array], source: 'JS-X-Ray' } ],
dependencies: Map(0) {},
isOneLineRequire: false
}
```
Congrats, you have created your first custom probe! 🎉
> [!TIP]
> Check the types in [index.d.ts](index.d.ts) and [types/api.d.ts](types/api.d.ts) for more details about the `options`
## API
- [AstAnalyser](./docs/api/AstAnalyser.md)
- [EntryFilesAnalyser](./docs/api/EntryFilesAnalyser.md)
Legacy APIs waiting to be deprecated;
<details>
<summary>runASTAnalysis(str: string, options?: RuntimeOptions & AstAnalyserOptions): Report</summary>
```ts
interface RuntimeOptions {
module?: boolean;
removeHTMLComments?: boolean;
isMinified?: boolean;
initialize?: (sourceFile: SourceFile) => void;
finalize?: (sourceFile: SourceFile) => void;
}
```
```ts
interface AstAnalyserOptions {
customParser?: SourceParser;
customProbes?: Probe[];
skipDefaultProbes?: boolean;
}
```
The method take a first argument which is the code you want to analyse. It will return a Report Object:
```ts
interface Report {
dependencies: ASTDeps;
warnings: Warning[];
idsLengthAvg: number;
stringScore: number;
isOneLineRequire: boolean;
}
```
</details>
<details>
<summary>runASTAnalysisOnFile(pathToFile: string, options?: RuntimeFileOptions & AstAnalyserOptions): Promise< ReportOnFile ></summary>
```ts
interface RuntimeFileOptions {
module?: boolean;
removeHTMLComments?: boolean;
packageName?: string;
initialize?: (sourceFile: SourceFile) => void;
finalize?: (sourceFile: SourceFile) => void;
}
```
```ts
interface AstAnalyserOptions {
customParser?: SourceParser;
customProbes?: Probe[];
skipDefaultProbes?: boolean;
}
```
Run the SAST scanner on a given JavaScript file.
```ts
export type ReportOnFile = {
ok: true,
warnings: Warning[];
dependencies: ASTDeps;
isMinified: boolean;
} | {
ok: false,
warnings: Warning[];
}
```
</details>
| [weak-crypto](./docs/weak-crypto.md) || The code probably contains a weak crypto algorithm (md5, sha1...) |
| [shady-link](./docs/shady-link.md) || The code contains shady/unsafe link |

## Workspaces

Expand Down
93 changes: 89 additions & 4 deletions docs/api/AstAnalyser.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,30 @@ declare class AstAnalyser {
constructor(options?: AstAnalyserOptions);
analyse: (str: string, options?: RuntimeOptions) => Report;
analyseFile(pathToFile: string, options?: RuntimeFileOptions): Promise<ReportOnFile>;
analyseFileSync(pathToFile: string, options?: RuntimeFileOptions): ReportOnFile;
}
```

The `analyseFile` method is a superset of `analyse` with the ability to read the file on the local filesystem with additional features like detecting if the file is ESM or CJS.
The `analyseFile` and `analyseFileSync` methods is a superset of `analyse` with the ability to read the file on the local filesystem with additional features like detecting if the file is ESM/CJS (using the extension).

```ts
interface RuntimeOptions {
/**
* @default true
*/
module?: boolean;
/**
* @default false
*/
removeHTMLComments?: boolean;
/**
* @default false
*/
isMinified?: boolean;
initialize?: (sourceFile: SourceFile) => void;
finalize?: (sourceFile: SourceFile) => void;
}

interface Report {
dependencies: Map<string, Dependency>;
warnings: Warning[];
Expand All @@ -65,9 +83,7 @@ type ReportOnFile = {
}
```
## Examples
### `initialize`/`finalize` Hooks
### Hooks
The `analyse` method allows for the integration of two hooks: `initialize` and `finalize`.
These hooks are triggered before and after the analysis process, respectively.
Expand All @@ -90,3 +106,72 @@ scanner.analyse("const foo = 'bar';", {
}
});
```

## Custom Probes

You can also create custom probes to detect specific pattern in the code you are analyzing.

A probe is a pair of two functions (`validateNode` and `main`) that will be called on each node of the AST. It will return a warning if the pattern is detected.

Below a basic probe that detect a string assignation to `danger`:

```ts
export const customProbes = [
{
name: "customProbeUnsafeDanger",
validateNode: (node, sourceFile) => [
node.type === "VariableDeclaration" && node.declarations[0].init.value === "danger"
],
main: (node, options) => {
const { sourceFile, data: calleeName } = options;
if (node.declarations[0].init.value === "danger") {
sourceFile.addWarning("unsafe-danger", calleeName, node.loc);

return ProbeSignals.Skip;
}

return null;
}
}
];
```

You can pass an array of probes to the `AstAnalyser` constructor.

| Name | Type | Description | Default Value |
|---|---|---|---|
| **customParser** | `SourceParser \| undefined` | An optional custom parser to be used for parsing the source code. | `JsSourceParser` |
| **customProbes** | `Probe[] \| undefined` | An array of custom probes to be used during AST analysis. | `[]` |
| **skipDefaultProbes** | `boolean \| undefined` | If **true**, default probes will be skipped and only custom probes will be used. | `false` |

Here using the example probe upper:

```ts
import { AstAnalyser } from "@nodesecure/js-x-ray";

// add your customProbes here (see example above)

const scanner = new AstAnalyser({
customProbes,
skipDefaultProbes: true
});

const result = scanner.analyse("const danger = 'danger';");

console.log(result);
```

Result:

```sh
✗ node example.js
{
idsLengthAvg: 0,
stringScore: 0,
warnings: [ { kind: 'unsafe-danger', location: [Array], source: 'JS-X-Ray' } ],
dependencies: Map(0) {},
isOneLineRequire: false
}
```
Congrats, you have created your first custom probe! 🎉
4 changes: 2 additions & 2 deletions docs/shady-link.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Shady link
| Code | Severity | i18n | Experimental |
| --- | --- | --- | :-: |
| shady-link | `Warning` | `sast_warnings.shady_link` | ✔️ |
| shady-link | `Warning` | `sast_warnings.shady_link` | |

## Introduction

Expand Down Expand Up @@ -36,4 +36,4 @@ const IPv6URL = "http://2444:1130:80:2aa8:c313:150d:b8cf:c321/script";

> [!IMPORTANT]\
> Credit goes to the [guarddog](https://github.dev/DataDog/guarddog) team.\
> Credit goes to the [ietf.org](https://www.ietf.org/rfc/rfc3986.txt).
> Credit goes to the [ietf.org](https://www.ietf.org/rfc/rfc3986.txt).
2 changes: 1 addition & 1 deletion docs/suspicious-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Code | Severity | i18n | Experimental |
| --- | --- | --- | :-: |
| suspicious-file | `Critical` | `sast_warnings.suspicious_file` | ✔️ |
| suspicious-file | `Critical` | `sast_warnings.suspicious_file` | |

## Introduction

Expand Down
2 changes: 1 addition & 1 deletion docs/weak-crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

| Code | Severity | i18n | Experimental |
| --- | --- | --- | :-: |
| weak-crypto | `Information` | `sast_warnings.weak_crypto` | ✔️ |
| weak-crypto | `Information` | `sast_warnings.weak_crypto` | |

## Introduction

Expand Down
4 changes: 0 additions & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import {

SourceParser,
JsSourceParser,
runASTAnalysis,
runASTAnalysisOnFile,
Report,
ReportOnFile,
RuntimeFileOptions,
Expand All @@ -34,8 +32,6 @@ export {
EntryFilesAnalyserOptions,
JsSourceParser,
SourceParser,
runASTAnalysis,
runASTAnalysisOnFile,
Report,
ReportOnFile,
RuntimeFileOptions,
Expand Down
Loading

0 comments on commit 1fb55a9

Please sign in to comment.