diff --git a/spec/Middlewares.spec.js b/spec/Middlewares.spec.js
index 2c380152ba..cc4383d8f4 100644
--- a/spec/Middlewares.spec.js
+++ b/spec/Middlewares.spec.js
@@ -158,78 +158,6 @@ describe('middlewares', () => {
});
});
- it('should not succeed if the connection.remoteAddress does not belong to masterKeyIps list', () => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1', 'ip2'],
- });
- fakeReq.connection = { remoteAddress: 'ip3' };
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- middlewares.handleParseHeaders(fakeReq, fakeRes);
- expect(fakeRes.status).toHaveBeenCalledWith(403);
- });
-
- it('should succeed if the connection.remoteAddress does belong to masterKeyIps list', done => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1', 'ip2'],
- });
- fakeReq.connection = { remoteAddress: 'ip1' };
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
- expect(fakeRes.status).not.toHaveBeenCalled();
- done();
- });
- });
-
- it('should not succeed if the socket.remoteAddress does not belong to masterKeyIps list', () => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1', 'ip2'],
- });
- fakeReq.socket = { remoteAddress: 'ip3' };
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- middlewares.handleParseHeaders(fakeReq, fakeRes);
- expect(fakeRes.status).toHaveBeenCalledWith(403);
- });
-
- it('should succeed if the socket.remoteAddress does belong to masterKeyIps list', done => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1', 'ip2'],
- });
- fakeReq.socket = { remoteAddress: 'ip1' };
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
- expect(fakeRes.status).not.toHaveBeenCalled();
- done();
- });
- });
-
- it('should not succeed if the connection.socket.remoteAddress does not belong to masterKeyIps list', () => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1', 'ip2'],
- });
- fakeReq.connection = { socket: { remoteAddress: 'ip3' } };
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- middlewares.handleParseHeaders(fakeReq, fakeRes);
- expect(fakeRes.status).toHaveBeenCalledWith(403);
- });
-
- it('should succeed if the connection.socket.remoteAddress does belong to masterKeyIps list', done => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1', 'ip2'],
- });
- fakeReq.connection = { socket: { remoteAddress: 'ip1' } };
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
- expect(fakeRes.status).not.toHaveBeenCalled();
- done();
- });
- });
-
it('should allow any ip to use masterKey if masterKeyIps is empty', done => {
AppCache.put(fakeReq.body._ApplicationId, {
masterKey: 'masterKey',
@@ -243,52 +171,9 @@ describe('middlewares', () => {
});
});
- it('should succeed if xff header does belong to masterKeyIps', done => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1'],
- });
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- fakeReq.headers['x-forwarded-for'] = 'ip1, ip2, ip3';
- middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
- expect(fakeRes.status).not.toHaveBeenCalled();
- done();
- });
- });
-
- it('should succeed if xff header with one ip does belong to masterKeyIps', done => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1'],
- });
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- fakeReq.headers['x-forwarded-for'] = 'ip1';
- middlewares.handleParseHeaders(fakeReq, fakeRes, () => {
- expect(fakeRes.status).not.toHaveBeenCalled();
- done();
- });
- });
-
- it('should not succeed if xff header does not belong to masterKeyIps', () => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip4'],
- });
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- fakeReq.headers['x-forwarded-for'] = 'ip1, ip2, ip3';
- middlewares.handleParseHeaders(fakeReq, fakeRes);
- expect(fakeRes.status).toHaveBeenCalledWith(403);
- });
-
- it('should not succeed if xff header is empty and masterKeyIps is set', () => {
- AppCache.put(fakeReq.body._ApplicationId, {
- masterKey: 'masterKey',
- masterKeyIps: ['ip1'],
- });
- fakeReq.headers['x-parse-master-key'] = 'masterKey';
- fakeReq.headers['x-forwarded-for'] = '';
- middlewares.handleParseHeaders(fakeReq, fakeRes);
- expect(fakeRes.status).toHaveBeenCalledWith(403);
+ it('can set trust proxy', async () => {
+ const server = await reconfigureServer({ trustProxy: 1 });
+ expect(server.app.parent.settings['trust proxy']).toBe(1);
});
it('should properly expose the headers', () => {
diff --git a/src/Options/Definitions.js b/src/Options/Definitions.js
index d8e3f841dd..35ab883719 100644
--- a/src/Options/Definitions.js
+++ b/src/Options/Definitions.js
@@ -477,6 +477,13 @@ module.exports.ParseServerOptions = {
help: 'Starts the liveQuery server',
action: parsers.booleanParser,
},
+ trustProxy: {
+ env: 'PARSE_SERVER_TRUST_PROXY',
+ help:
+ 'The trust proxy settings. It is important to understand the exact setup of the reverse proxy, since this setting will trust values provided in the Parse Server API request. See the express trust proxy settings documentation. Defaults to `false`.',
+ action: parsers.objectParser,
+ default: [],
+ },
userSensitiveFields: {
env: 'PARSE_SERVER_USER_SENSITIVE_FIELDS',
help:
diff --git a/src/Options/docs.js b/src/Options/docs.js
index cbd06ecd25..ffb86e91bd 100644
--- a/src/Options/docs.js
+++ b/src/Options/docs.js
@@ -88,6 +88,7 @@
* @property {Number} sessionLength Session duration, in seconds, defaults to 1 year
* @property {Boolean} silent Disables console output
* @property {Boolean} startLiveQueryServer Starts the liveQuery server
+ * @property {Any} trustProxy The trust proxy settings. It is important to understand the exact setup of the reverse proxy, since this setting will trust values provided in the Parse Server API request. See the express trust proxy settings documentation. Defaults to `false`.
* @property {String[]} userSensitiveFields Personally identifiable information fields in the user table the should be removed for non-authorized users. Deprecated @see protectedFields
* @property {Boolean} verbose Set the logging to verbose
* @property {Boolean} verifyUserEmails Set to `true` to require users to verify their email address to complete the sign-up process.
Default is `false`.
diff --git a/src/Options/index.js b/src/Options/index.js
index 2592e1e441..ea505c7414 100644
--- a/src/Options/index.js
+++ b/src/Options/index.js
@@ -238,6 +238,9 @@ export interface ParseServerOptions {
cluster: ?NumberOrBoolean;
/* middleware for express server, can be string or function */
middleware: ?((() => void) | string);
+ /* The trust proxy settings. It is important to understand the exact setup of the reverse proxy, since this setting will trust values provided in the Parse Server API request. See the express trust proxy settings documentation. Defaults to `false`.
+ :DEFAULT: false */
+ trustProxy: ?any;
/* Starts the liveQuery server */
startLiveQueryServer: ?boolean;
/* Live query server configuration options (will start the liveQuery server) */
diff --git a/src/ParseServer.js b/src/ParseServer.js
index df20020d6d..9be0059d9c 100644
--- a/src/ParseServer.js
+++ b/src/ParseServer.js
@@ -304,6 +304,9 @@ class ParseServer {
options
);
}
+ if (options.trustProxy) {
+ app.set('trust proxy', options.trustProxy);
+ }
/* istanbul ignore next */
if (!process.env.TESTING) {
configureListeners(this);
diff --git a/src/middlewares.js b/src/middlewares.js
index 37acf46821..8a5084a7e7 100644
--- a/src/middlewares.js
+++ b/src/middlewares.js
@@ -280,22 +280,7 @@ export function handleParseHeaders(req, res, next) {
}
function getClientIp(req) {
- if (req.headers['x-forwarded-for']) {
- // try to get from x-forwared-for if it set (behind reverse proxy)
- return req.headers['x-forwarded-for'].split(',')[0];
- } else if (req.connection && req.connection.remoteAddress) {
- // no proxy, try getting from connection.remoteAddress
- return req.connection.remoteAddress;
- } else if (req.socket) {
- // try to get it from req.socket
- return req.socket.remoteAddress;
- } else if (req.connection && req.connection.socket) {
- // try to get it form the connection.socket
- return req.connection.socket.remoteAddress;
- } else {
- // if non above, fallback.
- return req.ip;
- }
+ return req.ip;
}
function httpAuth(req) {