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

Suspicious request blocking - Express Path Parameters #4769

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

CarlesDD
Copy link
Contributor

@CarlesDD CarlesDD commented Oct 11, 2024

What does this PR do?

Subscribe to express process_param in order to report express path parameters to the WAF and block malicious incoming requests.

Motivation

To extend suspicious request blocking feature, blocking malicious payloads coming in express path parameters.

Plugin Checklist

  • Unit tests.

Additional Notes

Based on @simon-id previous work #3666

System Test PR

APPSEC-8367

Copy link

github-actions bot commented Oct 11, 2024

Overall package size

Self size: 7.48 MB
Deduped: 63.25 MB
No deduping: 63.53 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | @datadog/native-appsec | 8.1.1 | 18.67 MB | 18.68 MB | | @datadog/native-iast-taint-tracking | 3.1.0 | 12.27 MB | 12.28 MB | | @datadog/pprof | 5.3.0 | 9.85 MB | 10.22 MB | | protobufjs | 7.2.5 | 2.77 MB | 5.16 MB | | @datadog/native-iast-rewriter | 2.5.0 | 2.51 MB | 2.59 MB | | @opentelemetry/core | 1.14.0 | 872.87 kB | 1.47 MB | | @datadog/native-metrics | 2.0.0 | 898.77 kB | 1.3 MB | | @opentelemetry/api | 1.8.0 | 1.21 MB | 1.21 MB | | jsonpath-plus | 9.0.0 | 580.4 kB | 1.03 MB | | import-in-the-middle | 1.11.2 | 112.74 kB | 826.22 kB | | msgpack-lite | 0.1.26 | 201.16 kB | 281.59 kB | | opentracing | 0.14.7 | 194.81 kB | 194.81 kB | | pprof-format | 2.1.0 | 111.69 kB | 111.69 kB | | @datadog/sketches-js | 2.1.0 | 109.9 kB | 109.9 kB | | semver | 7.6.3 | 95.82 kB | 95.82 kB | | lodash.sortby | 4.7.0 | 75.76 kB | 75.76 kB | | lru-cache | 7.14.0 | 74.95 kB | 74.95 kB | | ignore | 5.3.1 | 51.46 kB | 51.46 kB | | int64-buffer | 0.1.10 | 49.18 kB | 49.18 kB | | shell-quote | 1.8.1 | 44.96 kB | 44.96 kB | | istanbul-lib-coverage | 3.2.0 | 29.34 kB | 29.34 kB | | rfdc | 1.3.1 | 25.21 kB | 25.21 kB | | tlhunter-sorted-set | 0.1.0 | 24.94 kB | 24.94 kB | | limiter | 1.1.5 | 23.17 kB | 23.17 kB | | dc-polyfill | 0.1.4 | 23.1 kB | 23.1 kB | | retry | 0.13.1 | 18.85 kB | 18.85 kB | | jest-docblock | 29.7.0 | 8.99 kB | 12.76 kB | | crypto-randomuuid | 1.0.0 | 11.18 kB | 11.18 kB | | koalas | 1.0.2 | 6.47 kB | 6.47 kB | | path-to-regexp | 0.1.10 | 6.38 kB | 6.38 kB | | module-details-from-path | 1.0.3 | 4.47 kB | 4.47 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdyt about splitting this file into supsicious-request-blocking.express.plugin.spec.js and api-security.express.plugin.spec.js ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this file is getting longer and longer... We could separate this in two files, but should we also split the src/appsec/index.js in different files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean packages/dd-trace/test/appsec/index.spec.js? If so, I'd not go with it, since it contains unit test for src/appsec/index.js so, to me, it makes sense to mirror the filenames.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I am not talking about test file, I am talking about appsec/index.js source file.
But anyway, a refactor shouldn't be part of this PR. So not to implement here.

Copy link

codecov bot commented Oct 11, 2024

Codecov Report

Attention: Patch coverage is 0% with 11 lines in your changes missing coverage. Please review.

Project coverage is 70.15%. Comparing base (7f93d36) to head (2b5543c).
Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
packages/dd-trace/src/appsec/index.js 0.00% 7 Missing ⚠️
packages/datadog-instrumentations/src/express.js 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4769      +/-   ##
==========================================
+ Coverage   69.19%   70.15%   +0.96%     
==========================================
  Files           1      307     +306     
  Lines         198    12992   +12794     
  Branches       33        0      -33     
==========================================
+ Hits          137     9115    +8978     
- Misses         61     3877    +3816     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@pr-commenter
Copy link

pr-commenter bot commented Oct 11, 2024

Benchmarks

Benchmark execution time: 2024-10-14 14:07:53

Comparing candidate commit c545063 in PR branch ccapell/path-params-blocking with baseline commit f62cbfa in branch master.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 260 metrics, 6 unstable metrics.

@CarlesDD CarlesDD marked this pull request as ready for review October 11, 2024 07:26
@CarlesDD CarlesDD requested review from a team as code owners October 11, 2024 07:26
@CarlesDD CarlesDD mentioned this pull request Oct 11, 2024
6 tasks
@@ -106,7 +106,17 @@ const wrapProcessParamsMethod = (requestPositionInArguments) => {
return (original) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make wrapProcessParamsMethod a non arrow function, and add names to the functions under that ? it's easier to reason about with actual function names.
Usually it goes like
wrapProcessParams()
-> wrappedProcessParams()
-> -> processParamsCallback()
or something like that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -6,6 +6,7 @@ const remoteConfig = require('./remote_config')
const {
bodyParser,
cookieParser,
expressProcessParams,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we try to keep consistency of order between channel.js, appsec/index.js require, subscribe, handler, and unsubscribe ? just so it's not all over the place and it's easier to find a specific one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const rootSpan = web.root(req)
if (!rootSpan) return

if (!params || typeof params !== 'object' || !Object.keys(params).length) return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the only place where we have Object.keys check ? why is that

Copy link
Contributor Author

@CarlesDD CarlesDD Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the other site - TaintTrackingPlugin- , the key length check is done (indirectly) later on, in the subscriber handler (taintObject method).

Here, this is done to avoid an unnecessary call to the WAF.

expect(e.response.status).to.be.equals(403)
expect(e.response.data).to.be.deep.equal(JSON.parse(json))
expect(requestBody).not.to.be.called
assert.equal(e.response.status, 403)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😮 you replaced all the expect by assert in this file, thanks for it :-D

Copy link
Collaborator

@uurien uurien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor comments, related with test spacing, optional to fix. But I like when our tests have this spacing:

it('test', () => {
  code.preparing.the.test()

  execute.the.test()

  assert(thistest).hasEmptyLinesAfterPreparationAndAfterExecution()
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants