From 335fb23a0f555b79c6ddf81cfdb6ff6afca6e4ae Mon Sep 17 00:00:00 2001 From: mendhak Date: Thu, 19 Mar 2026 23:12:17 +0000 Subject: [PATCH 1/4] Add cookie parser to echo the value of cookies in the response. Also works for signed cookies. To sign a cookie, generate a value using SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); function sign(val, secret){ return val + '.' + crypto .createHmac('sha256', secret) .update(val) .digest('base64') .replace(/=+$/, ''); }; console.log(sign('my-value','mysecretkey123'));") Then send it in the header like so curl -s http://localhost:8080/ -H "Cookie: mysigned=s:${SIGNED_COOKIE}" Issue #93 --- index.js | 4 ++++ package-lock.json | 20 ++++++++++++++++++ package.json | 1 + tests.sh | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/index.js b/index.js index f408286..5876532 100644 --- a/index.js +++ b/index.js @@ -4,6 +4,7 @@ const http = require('http') const https = require('https') const morgan = require('morgan'); const express = require('express') +const cookieParser = require('cookie-parser'); const concat = require('concat-stream'); const { promisify } = require('util'); const promBundle = require("express-prom-bundle"); @@ -39,6 +40,8 @@ if(PROMETHEUS_ENABLED === 'true') { app.use(metricsMiddleware); } +app.use(cookieParser(process.env.COOKIE_SECRET || 'examplekey')); + if(process.env.DISABLE_REQUEST_LOGS !== 'true'){ app.use(morgan('combined')); } @@ -76,6 +79,7 @@ app.all('*', (req, res) => { ips: req.ips, protocol: req.protocol, query: req.query, + signedCookies: req.signedCookies, subdomains: req.subdomains, xhr: req.xhr, os: { diff --git a/package-lock.json b/package-lock.json index e36edc8..36b0fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "BSD-3-Clause", "dependencies": { "concat-stream": "^2.0.0", + "cookie-parser": "^1.4.6", "express": "^4.22.0", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", @@ -280,6 +281,25 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, "node_modules/cookie-signature": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", diff --git a/package.json b/package.json index 69547ec..2fd41c2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ }, "dependencies": { "concat-stream": "^2.0.0", + "cookie-parser": "^1.4.6", "express": "^4.22.0", "express-prom-bundle": "^8.0.0", "jsonwebtoken": "^9.0.0", diff --git a/tests.sh b/tests.sh index f78844a..73cca7f 100755 --- a/tests.sh +++ b/tests.sh @@ -653,6 +653,60 @@ message " Stop containers " docker stop http-echo-tests sleep 5 +message " Start container with signed cookies support " +# Set cookie secret for signing/verifying cookies +docker run -d --rm -e COOKIE_SECRET=mysecretkey123 \ + --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +sleep 5 + +SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); + +function sign(val, secret){ + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/=+$/, ''); +}; + +console.log(sign('my-value','mysecretkey123'));") + + +RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: mysigned=s:${SIGNED_COOKIE}") +if [ $(echo $RESPONSE | jq -r '.signedCookies.mysigned') == 'my-value' ] +then + passed "Signed cookie test passed." +else + failed "Signed cookie test failed." + echo $RESPONSE | jq + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + + +message " Check that regular cookies are returned in response " +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing +sleep 5 + + +RESPONSE=$(curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux") +if [ $(echo $RESPONSE | jq -r '.cookies.foo') == 'bar' ] && \ + [ $(echo $RESPONSE | jq -r '.cookies.baz') == 'qux' ] +then + passed "Cookies returned in response test passed." +else + failed "Cookies returned in response test failed." + echo $RESPONSE | jq + exit 1 +fi + +message " Stop containers " +docker stop http-echo-tests +sleep 5 + popd rm -rf testarea message "DONE" From 67da5eb9bd277aff2fcec87e4a61a36a2a3e7d73 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 07:25:17 +0000 Subject: [PATCH 2/4] Update the sarif actions --- .github/workflows/build.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a89eebf..5037958 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,10 @@ jobs: # The type of runner that the job will run on runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it @@ -76,7 +80,7 @@ jobs: - name: Scan the image id: scan - uses: anchore/scan-action@v3 + uses: anchore/scan-action@v7 with: image: "mendhak/http-https-echo:testing" output-format: sarif @@ -84,6 +88,6 @@ jobs: fail-build: false - name: upload Anchore scan SARIF report - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: ${{ steps.scan.outputs.sarif }} From ba1c32982dc541455e7ba86289d36499c4d9decf Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 07:51:41 +0000 Subject: [PATCH 3/4] How to send a signed cookie --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index e716926..2e720a1 100644 --- a/README.md +++ b/README.md @@ -301,6 +301,47 @@ You can use the `MAX_HEADER_SIZE` environment variable to set a maximum header s docker run -d --rm -e MAX_HEADER_SIZE=1000 -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 ``` +## Cookies and Signed Cookies + +Make a request with a `Cookie` header and the response will include the cookies: + +```bash +docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +``` + +Then make a request with a cookie header: + +```bash +curl -s http://localhost:8080/ -H "Cookie: foo=bar; baz=qux" +``` + +To enable signed cookie support, set the `COOKIE_SECRET` environment variable. Signed cookies appear in the `signedCookies` section of the response: + +```bash +docker run -d --rm -e COOKIE_SECRET=mysecretkey123 --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:39 +``` + +Now you need to generate a signed cookie, and send it in the header. Here's a convenience node snippet: + +```bash + +SIGNED_COOKIE=$(node -e "var crypto = require('crypto'); + +function sign(val, secret){ + return val + '.' + crypto + .createHmac('sha256', secret) + .update(val) + .digest('base64') + .replace(/=+$/, ''); +}; + +console.log(sign('my-value','mysecretkey123'));") + +curl -s http://localhost:8080/ -H "Cookie: mysigned=s:$SIGNED_COOKIE" | jq '.signedCookies' +``` + +Notice the `s:` prefix in the cookie value, that is important. + ## Prometheus Metrics From 4f118c005be9847c59608d0c9c6264fa1dc1fde9 Mon Sep 17 00:00:00 2001 From: mendhak Date: Fri, 20 Mar 2026 07:53:12 +0000 Subject: [PATCH 4/4] Changelog for v40 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f494b79..d86685f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## Version `40` - 2026-03-20 +* Echo back cookies and signed cookies + ## Version `39` - 2026-01-09 * Renamed privkey.pem to testpk.pem so Trivy doesn't flag a false positive by [willyguggenheim](https://github.com/mendhak/docker-http-https-echo/pull/89) * Updated dependencies in package.json