parse-dashboard 9.3.0-alpha.3 → 9.3.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Parse-Dashboard/app.js
CHANGED
|
@@ -87,13 +87,52 @@ module.exports = function(config, options) {
|
|
|
87
87
|
cookieSessionStore: options.cookieSessionStore
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
+
// Headers set by reverse proxies to describe the original client. Their
|
|
91
|
+
// presence means the request was relayed and did not originate on this host.
|
|
92
|
+
// The `x-forwarded-` prefix is matched as a whole because proxies vary in
|
|
93
|
+
// which of them they set, and any single one is enough to reveal a relay.
|
|
94
|
+
const forwardingHeaderPrefix = 'x-forwarded-';
|
|
95
|
+
const forwardingHeaders = ['x-real-ip', 'forwarded'];
|
|
96
|
+
|
|
90
97
|
/**
|
|
91
|
-
* Checks whether
|
|
98
|
+
* Checks whether the connection was opened from this host.
|
|
99
|
+
*
|
|
100
|
+
* This describes the connection, not the client: a reverse proxy running on
|
|
101
|
+
* the same host also connects over loopback, so a true result does not mean
|
|
102
|
+
* the client is local. Use it only to decide whether the connection itself
|
|
103
|
+
* needs encrypting, never to grant access.
|
|
104
|
+
*/
|
|
105
|
+
function isLoopbackPeer(req) {
|
|
106
|
+
// The whole of 127.0.0.0/8 is loopback, not just 127.0.0.1. The address is
|
|
107
|
+
// absent on a socket that has already been destroyed.
|
|
108
|
+
const address = req.socket.remoteAddress;
|
|
109
|
+
return typeof address === 'string' && (
|
|
110
|
+
address.startsWith('127.') ||
|
|
111
|
+
address.startsWith('::ffff:127.') ||
|
|
112
|
+
address === '::1'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Checks whether a request originated on this host.
|
|
118
|
+
*
|
|
119
|
+
* Stricter than `isLoopbackPeer`, because a same-host reverse proxy would
|
|
120
|
+
* otherwise make every request it relays look local. A request counts as
|
|
121
|
+
* local only when nothing indicates it was relayed.
|
|
92
122
|
*/
|
|
93
123
|
function isLocalRequest(req) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
124
|
+
// A configured proxy relays every request, so no request is local.
|
|
125
|
+
if (config.trustProxy) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
// Forwarding headers are never sent by a client on this host.
|
|
129
|
+
const isForwarded = Object.keys(req.headers).some(header =>
|
|
130
|
+
header.startsWith(forwardingHeaderPrefix) || forwardingHeaders.includes(header)
|
|
131
|
+
);
|
|
132
|
+
if (isForwarded) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return isLoopbackPeer(req);
|
|
97
136
|
}
|
|
98
137
|
|
|
99
138
|
/**
|
|
@@ -102,11 +141,15 @@ module.exports = function(config, options) {
|
|
|
102
141
|
* - Requires users to be configured for remote access (unless dev mode is enabled)
|
|
103
142
|
*/
|
|
104
143
|
function enforceRemoteAccessRestrictions(req, res, next) {
|
|
105
|
-
if (!options.dev
|
|
106
|
-
|
|
144
|
+
if (!options.dev) {
|
|
145
|
+
// Keyed on the connection: a loopback connection cannot be observed off
|
|
146
|
+
// this host, so it needs no encryption of its own.
|
|
147
|
+
if (!isLoopbackPeer(req) && !req.secure && !options.allowInsecureHTTP) {
|
|
107
148
|
return res.status(403).json({ error: 'Parse Dashboard can only be remotely accessed via HTTPS' });
|
|
108
149
|
}
|
|
109
|
-
|
|
150
|
+
// Keyed on the client: granting access requires knowing where the
|
|
151
|
+
// request came from, which a relayed request cannot establish.
|
|
152
|
+
if (!isLocalRequest(req) && !users) {
|
|
110
153
|
return res.status(401).json({ error: 'Configure a user to access Parse Dashboard remotely' });
|
|
111
154
|
}
|
|
112
155
|
}
|
|
@@ -135,13 +178,13 @@ module.exports = function(config, options) {
|
|
|
135
178
|
agent: config.agent,
|
|
136
179
|
};
|
|
137
180
|
|
|
138
|
-
if (!options.dev
|
|
139
|
-
if (!req.secure && !options.allowInsecureHTTP) {
|
|
181
|
+
if (!options.dev) {
|
|
182
|
+
if (!isLoopbackPeer(req) && !req.secure && !options.allowInsecureHTTP) {
|
|
140
183
|
//Disallow HTTP requests except on localhost, to prevent the master key from being transmitted in cleartext
|
|
141
184
|
return res.send({ success: false, error: 'Parse Dashboard can only be remotely accessed via HTTPS' });
|
|
142
185
|
}
|
|
143
186
|
|
|
144
|
-
if (!users) {
|
|
187
|
+
if (!isLocalRequest(req) && !users) {
|
|
145
188
|
//Accessing the dashboard over the internet can only be done with username and password
|
|
146
189
|
return res.send({ success: false, error: 'Configure a user to access Parse Dashboard remotely' });
|
|
147
190
|
}
|