diff --git a/htdocs/admin/system/security.php b/htdocs/admin/system/security.php
index e972581beaa..5214808985d 100644
--- a/htdocs/admin/system/security.php
+++ b/htdocs/admin/system/security.php
@@ -277,7 +277,7 @@ if ($conf->global->MAIN_SECURITY_HASH_ALGO != 'password_hash') {
print '
';
-print 'MAIN_SECURITY_ANTI_SSRF_SERVER_IP = '.(empty($conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP) ? ''.$langs->trans("Undefined").'' : $conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP)."
";
+print 'MAIN_SECURITY_ANTI_SSRF_SERVER_IP = '.(empty($conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP) ? ''.$langs->trans("Undefined").' ('.$langs->trans("Example").': static-ips-of-server - '.$langs->trans("Note").': common loopback ip like 127.*.*.*, [::1] are already added)' : $conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP)."
";
print '
';
print 'MAIN_ALLOW_SVG_FILES_AS_IMAGES = '.(empty($conf->global->MAIN_ALLOW_SVG_FILES_AS_IMAGES) ? '0 ('.$langs->trans("Recommanded").': 0)' : $conf->global->MAIN_ALLOW_SVG_FILES_AS_IMAGES)."
";
diff --git a/htdocs/core/lib/geturl.lib.php b/htdocs/core/lib/geturl.lib.php
index 9feddb6f7f5..f87e7b7b4cd 100644
--- a/htdocs/core/lib/geturl.lib.php
+++ b/htdocs/core/lib/geturl.lib.php
@@ -24,7 +24,9 @@
/**
* Function to get a content from an URL (use proxy if proxy defined).
* Support Dolibarr setup for timeout and proxy.
- * Enhancement of CURL to add an anti SSRF protection.
+ * Enhancement of CURL to add an anti SSRF protection:
+ * - you can set MAIN_SECURITY_ANTI_SSRF_SERVER_IP to set static ip of server
+ * - common local lookup ips like 127.*.*.* are automatically added
*
* @param string $url URL to call.
* @param string $postorget 'POST', 'GET', 'HEAD', 'PUT', 'PUTALREADYFORMATED', 'POSTALREADYFORMATED', 'DELETE'
@@ -199,12 +201,13 @@ function getURLContent($url, $postorget = 'GET', $param = '', $followlocation =
}
}
if ($localurl == 1) { // Only local url allowed (dangerous, may allow to get metadata on server or make internal port scanning)
+ // Deny ips NOT like 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 0.0.0.0/8, 169.254.0.0/16, 127.0.0.0/8 et 240.0.0.0/4, ::1/128, ::/128, ::ffff:0:0/96, fe80::/10...
if (filter_var($iptocheck, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$info['http_code'] = 400;
$info['content'] = 'Error bad hostname '.$iptocheck.'. Must be a local URL.';
break;
}
- if (!empty($conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP) && !in_array($iptocheck, explode(',', '127.0.0.1,::1,'.$conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP))) {
+ if (!empty($conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP) && !in_array($iptocheck, explode(',', $conf->global->MAIN_SECURITY_ANTI_SSRF_SERVER_IP))) {
$info['http_code'] = 400;
$info['content'] = 'Error bad hostname IP (IP is not a local IP defined into list MAIN_SECURITY_SERVER_IP). Must be a local URL in allowed list.';
break;
diff --git a/test/phpunit/SecurityTest.php b/test/phpunit/SecurityTest.php
index 944d4f4cbe5..f889a6c542b 100644
--- a/test/phpunit/SecurityTest.php
+++ b/test/phpunit/SecurityTest.php
@@ -703,17 +703,22 @@ class SecurityTest extends PHPUnit\Framework\TestCase
$url = 'http://127.0.0.1';
$tmp = getURLContent($url, 'GET', '', 0, array(), array('http', 'https'), 0); // Only external URL
print __METHOD__." url=".$url."\n";
- $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because localtest.me is not an external URL
+ $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because 127.0.0.1 is not an external URL
+
+ $url = 'http://127.0.2.1';
+ $tmp = getURLContent($url, 'GET', '', 0, array(), array('http', 'https'), 0); // Only external URL
+ print __METHOD__." url=".$url."\n";
+ $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because 127.0.2.1 is not an external URL
$url = 'https://169.254.0.1';
$tmp = getURLContent($url, 'GET', '', 0, array(), array('http', 'https'), 0); // Only external URL
print __METHOD__." url=".$url."\n";
- $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because localtest.me is not an external URL
+ $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because 169.254.0.1 is not an external URL
$url = 'http://[::1]';
$tmp = getURLContent($url, 'GET', '', 0, array(), array('http', 'https'), 0); // Only external URL
print __METHOD__." url=".$url."\n";
- $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because localtest.me is not an external URL
+ $this->assertEquals(400, $tmp['http_code'], 'GET url to '.$url.' that is a local URL'); // Test we receive an error because [::1] is not an external URL
/*$url = 'localtest.me';
$tmp = getURLContent($url, 'GET', '', 0, array(), array('http', 'https'), 0); // Only external URL