mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: add protection mechanism to request lib so that network requests to reserved IP ranges throw an error
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
"wrong-parameter-type": "A value of type %3 was expected for property `%1`, but %2 was received instead",
|
"wrong-parameter-type": "A value of type %3 was expected for property `%1`, but %2 was received instead",
|
||||||
"required-parameters-missing": "Required parameters were missing from this API call: %1",
|
"required-parameters-missing": "Required parameters were missing from this API call: %1",
|
||||||
|
|
||||||
|
"reserved-ip-address": "Network requests to reserved IP ranges are not allowed.",
|
||||||
|
|
||||||
"not-logged-in": "You don't seem to be logged in.",
|
"not-logged-in": "You don't seem to be logged in.",
|
||||||
"account-locked": "Your account has been locked temporarily",
|
"account-locked": "Your account has been locked temporarily",
|
||||||
"search-requires-login": "Searching requires an account - please login or register.",
|
"search-requires-login": "Searching requires an account - please login or register.",
|
||||||
|
|||||||
@@ -1,10 +1,18 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const dns = require('dns').promises;
|
||||||
|
|
||||||
const nconf = require('nconf');
|
const nconf = require('nconf');
|
||||||
|
const ipaddr = require('ipaddr.js');
|
||||||
const { CookieJar } = require('tough-cookie');
|
const { CookieJar } = require('tough-cookie');
|
||||||
const fetchCookie = require('fetch-cookie').default;
|
const fetchCookie = require('fetch-cookie').default;
|
||||||
const { version } = require('../package.json');
|
const { version } = require('../package.json');
|
||||||
|
|
||||||
|
const ttl = require('./cache/ttl');
|
||||||
|
const checkCache = ttl({
|
||||||
|
ttl: 1000 * 60 * 60, // 1 hour
|
||||||
|
});
|
||||||
|
|
||||||
exports.jar = function () {
|
exports.jar = function () {
|
||||||
return new CookieJar();
|
return new CookieJar();
|
||||||
};
|
};
|
||||||
@@ -13,6 +21,11 @@ const userAgent = `NodeBB/${version.split('.').shift()}.x (${nconf.get('url')})`
|
|||||||
|
|
||||||
// Initialize fetch - somewhat hacky, but it's required for globalDispatcher to be available
|
// Initialize fetch - somewhat hacky, but it's required for globalDispatcher to be available
|
||||||
async function call(url, method, { body, timeout, jar, ...config } = {}) {
|
async function call(url, method, { body, timeout, jar, ...config } = {}) {
|
||||||
|
const ok = await check(url);
|
||||||
|
if (!ok) {
|
||||||
|
throw new Error('[[error:reserved-ip-address]]');
|
||||||
|
}
|
||||||
|
|
||||||
let fetchImpl = fetch;
|
let fetchImpl = fetch;
|
||||||
if (jar) {
|
if (jar) {
|
||||||
fetchImpl = fetchCookie(fetch, jar);
|
fetchImpl = fetchCookie(fetch, jar);
|
||||||
@@ -75,6 +88,40 @@ async function call(url, method, { body, timeout, jar, ...config } = {}) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks url to ensure it is not in reserved IP range (private, etc.)
|
||||||
|
async function check(url) {
|
||||||
|
const cached = checkCache.get(url);
|
||||||
|
if (cached) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
const addresses = new Set();
|
||||||
|
if (ipaddr.isValid(url)) {
|
||||||
|
addresses.add(url);
|
||||||
|
} else {
|
||||||
|
const { host } = new URL(url);
|
||||||
|
const [v4, v6] = await Promise.all([
|
||||||
|
dns.resolve4(host),
|
||||||
|
dns.resolve6(host),
|
||||||
|
]);
|
||||||
|
v4.forEach((ip) => {
|
||||||
|
addresses.add(ip);
|
||||||
|
});
|
||||||
|
v6.forEach((ip) => {
|
||||||
|
addresses.add(ip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every IP address that the host resolves to should be a unicast address
|
||||||
|
const ok = Array.from(addresses).every((ip) => {
|
||||||
|
const parsed = ipaddr.parse(ip);
|
||||||
|
return parsed.range() === 'unicast';
|
||||||
|
});
|
||||||
|
|
||||||
|
checkCache.set(url, ok);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const { body, response } = await request.get('someurl?foo=1&baz=2')
|
const { body, response } = await request.get('someurl?foo=1&baz=2')
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user