diff --git a/CHANGELOG.md b/CHANGELOG.md index f12ef06..6a407f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 3.8.0 (2023-12-22) +Added: + - Added option `ignoreXForwardedHost` to ignore any `X-Forwarded-Host` headers, which can be used to block SSRF attacks + ## 3.7.0 (2023-05-22) Added: - Add Google-InspectionTool to the recognized user agents diff --git a/README.md b/README.md index 951d341..6102db9 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,26 @@ Option to forward headers from request to prerender. app.use(require('prerender-node').set('forwardHeaders', true)); ``` +### ignoreXForwardedHost + +Option to ignore `X-Forwarded-Host` header. Can be used to block SSRF attacks. + +**Important:** this header is used to preserve the original host header for servers that sit behind a load balancer or internal reverse proxy. If your server does not need this header then it's probably safe to enable this option. Check your environment before enabling this option and make sure to test it first. + +The url that Prerender will get and return the (possibly cached) contents of is created by taking the first available of the following: +- The `host` option, as set with `app.use(require('prerender-node').set('host', 'example.com'));` +- The `X-Forwarded-Host` header, if `ignoreXForwardedHost` is **NOT** set to `true` +- The Host header +Finally the originally requested url path is added to the end. + +The Prerender.io servers will connect to any url you specify at the end of the prerender service URL. This means that if someone visits `https://mysite.com`, and the request is modified with the path `/some/path` and the header `x-forwarded-host` set to `example.com`, Prerender will connect to `https://example.com/some/path`. (You actually don't need to intercept any request, you can just run the whole request directly, e.g. by using Postman.) + +If you set `ignoreXForwardedHost` to `true`, the `X-Forwarded-Host` header will be ignored, effectively blocking these SSRF attacks. + +```js +app.use(require('prerender-node').set('ignoreXForwardedHost', true)); +``` + ### prerenderServerRequestOptions Option to add options to the request sent to the prerender server. diff --git a/index.js b/index.js index d3ad541..98dc96e 100644 --- a/index.js +++ b/index.js @@ -271,7 +271,10 @@ prerender.buildApiUrl = function(req) { if (this.protocol) { protocol = this.protocol; } - var fullUrl = protocol + "://" + (this.host || req.headers['x-forwarded-host'] || req.headers['host']) + req.url; + + // if set, ignore X-Forwarded-Host header to block SSRF attacks + const xforwardedHost = this.ignoreXForwardedHost !== true && req.headers['x-forwarded-host']; + const fullUrl = `${protocol}://${this.host || xforwardedHost || req.headers.host}${req.url}`; return prerenderUrl + forwardSlash + fullUrl; }; diff --git a/package-lock.json b/package-lock.json index 4ae1d49..fa31582 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "prerender-node", - "version": "3.7.0", + "version": "3.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index f8a2708..a92f2cb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prerender-node", - "version": "3.7.0", + "version": "3.8.0", "description": "express middleware for serving prerendered javascript-rendered pages for SEO", "author": "Todd Hooper", "license": "MIT",