openvibers/openvibe.chat Commits
nginx: every Chat location that sets its own proxy_set_header (Connection "" for upstream keepalive) repeats Host and the client address: /auth/me, /auth/, /api/ and / had lost the server-level ones, so REST requests reached Chat as 127.0.0.1 (per-IP limits and bans saw one address); the test fails a location without them
Changes
@@@ -113,10 +113,17 @@ server {# The session probe: the shared navbar asks it on every page view, so it cannot share the sign-in# budget below (10 a minute): a visitor reading quickly was answered 503 and looked signed out# (found by the browser check, OpenVibe.Host scripts/browser-check.js).++ # These locations set Connection "" (keepalive to the upstream), and any proxy_set_header in a++ # location replaces every server-level one, so the client address and Host are repeated in each.location = /auth/me {limit_req zone=ovchat_api burst=30 nodelay;limit_req_status 429;proxy_set_header Connection "";++ proxy_set_header Host $host;++ proxy_set_header X-Real-IP $remote_addr;++ proxy_set_header X-Forwarded-For $remote_addr;++ proxy_set_header CF-Connecting-IP $remote_addr;++ proxy_set_header X-Forwarded-Proto $scheme;proxy_pass http://127.0.0.1:4400;}@@@ -124,6 +131,11 @@ server {limit_req zone=ovchat_auth burst=10 nodelay;limit_req_status 429;proxy_set_header Connection "";++ proxy_set_header Host $host;++ proxy_set_header X-Real-IP $remote_addr;++ proxy_set_header X-Forwarded-For $remote_addr;++ proxy_set_header CF-Connecting-IP $remote_addr;++ proxy_set_header X-Forwarded-Proto $scheme;proxy_pass http://127.0.0.1:4400;}@@@ -131,12 +143,22 @@ server {limit_req zone=ovchat_api burst=40 nodelay;client_max_body_size 10m;proxy_set_header Connection "";++ proxy_set_header Host $host;++ proxy_set_header X-Real-IP $remote_addr;++ proxy_set_header X-Forwarded-For $remote_addr;++ proxy_set_header CF-Connecting-IP $remote_addr;++ proxy_set_header X-Forwarded-Proto $scheme;proxy_pass http://127.0.0.1:4400;}location / {limit_req zone=ovchat_write burst=20 nodelay;proxy_set_header Connection "";++ proxy_set_header Host $host;++ proxy_set_header X-Real-IP $remote_addr;++ proxy_set_header X-Forwarded-For $remote_addr;++ proxy_set_header CF-Connecting-IP $remote_addr;++ proxy_set_header X-Forwarded-Proto $scheme;proxy_pass http://127.0.0.1:4400;}}@@@ -17,4 +17,15 @@ assert.match(auth, /limit_req zone=ovchat_auth burst=10 nodelay;/);for (const b of [probe, auth]) assert.match(b, /limit_req_status 429;/);const upstream = (b) => (b.match(/proxy_pass (\S+);/) || [])[1];assert.ok(upstream(probe) && upstream(probe) === upstream(auth), 'the same upstream');++// Any location that sets its own proxy_set_header loses the server-level ones, so each must carry the++// client address and Host itself (a location without them sent every REST request as 127.0.0.1).++{++ const conf = require('fs').readFileSync(require('path').join(__dirname, '..', 'deploy', 'nginx', 'openvibe.chat.conf'), 'utf8');++ const blocks = conf.split(/\n location /).slice(1);++ for (const b of blocks) {++ const body = b.slice(0, b.indexOf('\n }'));++ if (!/proxy_set_header/.test(body) || !/proxy_pass/.test(body)) continue;++ for (const h of ['Host $host', 'X-Real-IP $remote_addr', 'CF-Connecting-IP $remote_addr']) require('assert').ok(body.includes(`proxy_set_header ${h}`), `location ${b.split(' ')[0]} ${b.split(' ')[1] || ''}: proxy_set_header ${h}`);++ }++}console.log('nginx auth limit: /auth/me on the API zone, 429 when limited');
@@ -113,10 +113,17 @@ server {
@@ -113,10 +113,17 @@ server {
# The session probe: the shared navbar asks it on every page view, so it cannot share the sign-in
# The session probe: the shared navbar asks it on every page view, so it cannot share the sign-in
# budget below (10 a minute): a visitor reading quickly was answered 503 and looked signed out
# budget below (10 a minute): a visitor reading quickly was answered 503 and looked signed out
# (found by the browser check, OpenVibe.Host scripts/browser-check.js).
# (found by the browser check, OpenVibe.Host scripts/browser-check.js).
+ # These locations set Connection "" (keepalive to the upstream), and any proxy_set_header in a
+ # location replaces every server-level one, so the client address and Host are repeated in each.
location = /auth/me {
location = /auth/me {
limit_req zone=ovchat_api burst=30 nodelay;
limit_req zone=ovchat_api burst=30 nodelay;
limit_req_status 429;
limit_req_status 429;
proxy_set_header Connection "";
proxy_set_header Connection "";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header CF-Connecting-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
proxy_pass http://127.0.0.1:4400;
}
}
@@ -124,6 +131,11 @@ server {
@@ -124,6 +131,11 @@ server {
limit_req zone=ovchat_auth burst=10 nodelay;
limit_req zone=ovchat_auth burst=10 nodelay;
limit_req_status 429;
limit_req_status 429;
proxy_set_header Connection "";
proxy_set_header Connection "";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header CF-Connecting-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
proxy_pass http://127.0.0.1:4400;
}
}
@@ -131,12 +143,22 @@ server {
@@ -131,12 +143,22 @@ server {
limit_req zone=ovchat_api burst=40 nodelay;
limit_req zone=ovchat_api burst=40 nodelay;
client_max_body_size 10m;
client_max_body_size 10m;
proxy_set_header Connection "";
proxy_set_header Connection "";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header CF-Connecting-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
proxy_pass http://127.0.0.1:4400;
}
}
location / {
location / {
limit_req zone=ovchat_write burst=20 nodelay;
limit_req zone=ovchat_write burst=20 nodelay;
proxy_set_header Connection "";
proxy_set_header Connection "";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header CF-Connecting-IP $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:4400;
proxy_pass http://127.0.0.1:4400;
}
}
}
}
@@ -17,4 +17,15 @@ assert.match(auth, /limit_req zone=ovchat_auth burst=10 nodelay;/);
@@ -17,4 +17,15 @@ assert.match(auth, /limit_req zone=ovchat_auth burst=10 nodelay;/);
for (const b of [probe, auth]) assert.match(b, /limit_req_status 429;/);
for (const b of [probe, auth]) assert.match(b, /limit_req_status 429;/);
const upstream = (b) => (b.match(/proxy_pass (\S+);/) || [])[1];
const upstream = (b) => (b.match(/proxy_pass (\S+);/) || [])[1];
assert.ok(upstream(probe) && upstream(probe) === upstream(auth), 'the same upstream');
assert.ok(upstream(probe) && upstream(probe) === upstream(auth), 'the same upstream');
+// Any location that sets its own proxy_set_header loses the server-level ones, so each must carry the
+// client address and Host itself (a location without them sent every REST request as 127.0.0.1).
+{
+ const conf = require('fs').readFileSync(require('path').join(__dirname, '..', 'deploy', 'nginx', 'openvibe.chat.conf'), 'utf8');
+ const blocks = conf.split(/\n location /).slice(1);
+ for (const b of blocks) {
+ const body = b.slice(0, b.indexOf('\n }'));
+ if (!/proxy_set_header/.test(body) || !/proxy_pass/.test(body)) continue;
+ for (const h of ['Host $host', 'X-Real-IP $remote_addr', 'CF-Connecting-IP $remote_addr']) require('assert').ok(body.includes(`proxy_set_header ${h}`), `location ${b.split(' ')[0]} ${b.split(' ')[1] || ''}: proxy_set_header ${h}`);
+ }
+}
console.log('nginx auth limit: /auth/me on the API zone, 429 when limited');
console.log('nginx auth limit: /auth/me on the API zone, 429 when limited');