From 2062070be953edf5d980311f32f5928fd40ddb3a Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Tue, 19 Apr 2016 22:29:04 +0100 Subject: [PATCH] Warn users with secure-http disabled once per hostname they access insecurely to avoid bad URLs going by undetected, fixes #5008 --- src/Composer/Config.php | 21 ++++++++++++++++----- src/Composer/Downloader/HgDownloader.php | 4 ++-- src/Composer/Repository/Vcs/HgDriver.php | 2 +- src/Composer/Util/Git.php | 2 +- src/Composer/Util/RemoteFilesystem.php | 10 +++++----- src/Composer/Util/Svn.php | 2 +- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/Composer/Config.php b/src/Composer/Config.php index 22f3246e2..aaca4e4c9 100644 --- a/src/Composer/Config.php +++ b/src/Composer/Config.php @@ -14,6 +14,7 @@ namespace Composer; use Composer\Config\ConfigSourceInterface; use Composer\Downloader\TransportException; +use Composer\IO\IOInterface; /** * @author Jordi Boggiano @@ -78,6 +79,7 @@ class Config private $configSource; private $authConfigSource; private $useEnvironment; + private $warnedHosts = array(); /** * @param bool $useEnvironment Use COMPOSER_ environment variables to replace config settings @@ -403,19 +405,28 @@ class Config /** * Validates that the passed URL is allowed to be used by current config, or throws an exception. * - * @param string $url + * @param string $url + * @param IOInterface $io */ - public function prohibitUrlByConfig($url) + public function prohibitUrlByConfig($url, IOInterface $io = null) { - // Return right away if check is disabled, or if the URL is malformed or custom (see issue #5173) - if (!$this->get('secure-http') || false === filter_var($url, FILTER_VALIDATE_URL)) { + // Return right away if the URL is malformed or custom (see issue #5173) + if (false === filter_var($url, FILTER_VALIDATE_URL)) { return; } // Extract scheme and throw exception on known insecure protocols $scheme = parse_url($url, PHP_URL_SCHEME); if (in_array($scheme, array('http', 'git', 'ftp', 'svn'))) { - throw new TransportException("Your configuration does not allow connections to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details."); + if ($this->get('secure-http')) { + throw new TransportException("Your configuration does not allow connections to $url. See https://getcomposer.org/doc/06-config.md#secure-http for details."); + } elseif ($io) { + $host = parse_url($url, PHP_URL_HOST); + if (!isset($this->warnedHosts[$host])) { + $io->writeError("Warning: Accessing $host over $scheme which is an insecure protocol."); + } + $this->warnedHosts[$host] = true; + } } } } diff --git a/src/Composer/Downloader/HgDownloader.php b/src/Composer/Downloader/HgDownloader.php index dc1d35464..4222282c0 100644 --- a/src/Composer/Downloader/HgDownloader.php +++ b/src/Composer/Downloader/HgDownloader.php @@ -26,7 +26,7 @@ class HgDownloader extends VcsDownloader public function doDownload(PackageInterface $package, $path, $url) { // Ensure we are allowed to use this URL by config - $this->config->prohibitUrlByConfig($url); + $this->config->prohibitUrlByConfig($url, $this->io); $url = ProcessExecutor::escape($url); $ref = ProcessExecutor::escape($package->getSourceReference()); @@ -47,7 +47,7 @@ class HgDownloader extends VcsDownloader public function doUpdate(PackageInterface $initial, PackageInterface $target, $path, $url) { // Ensure we are allowed to use this URL by config - $this->config->prohibitUrlByConfig($url); + $this->config->prohibitUrlByConfig($url, $this->io); $url = ProcessExecutor::escape($url); $ref = ProcessExecutor::escape($target->getSourceReference()); diff --git a/src/Composer/Repository/Vcs/HgDriver.php b/src/Composer/Repository/Vcs/HgDriver.php index c5432b792..c82c8c4aa 100644 --- a/src/Composer/Repository/Vcs/HgDriver.php +++ b/src/Composer/Repository/Vcs/HgDriver.php @@ -48,7 +48,7 @@ class HgDriver extends VcsDriver } // Ensure we are allowed to use this URL by config - $this->config->prohibitUrlByConfig($this->url); + $this->config->prohibitUrlByConfig($this->url, $this->io); // update the repo if it is a valid hg repository if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) { diff --git a/src/Composer/Util/Git.php b/src/Composer/Util/Git.php index 9c13b2db5..a2b03bbb9 100644 --- a/src/Composer/Util/Git.php +++ b/src/Composer/Util/Git.php @@ -40,7 +40,7 @@ class Git public function runCommand($commandCallable, $url, $cwd, $initialClone = false) { // Ensure we are allowed to use this URL by config - $this->config->prohibitUrlByConfig($url); + $this->config->prohibitUrlByConfig($url, $this->io); if ($initialClone) { $origCwd = $cwd; diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index f28ff460a..87055a15c 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -258,13 +258,13 @@ class RemoteFilesystem $this->io->writeError((substr($origFileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $origFileUrl . $usingProxy, true, IOInterface::DEBUG); unset($origFileUrl, $actualContextOptions); - if ($this->progress && !$isRedirect) { - $this->io->writeError(" Downloading: Connecting...", false); - } - // Check for secure HTTP, but allow insecure Packagist calls to $hashed providers as file integrity is verified with sha256 if ((substr($fileUrl, 0, 23) !== 'http://packagist.org/p/' || (false === strpos($fileUrl, '$') && false === strpos($fileUrl, '%24'))) && $this->config) { - $this->config->prohibitUrlByConfig($fileUrl); + $this->config->prohibitUrlByConfig($fileUrl, $this->io); + } + + if ($this->progress && !$isRedirect) { + $this->io->writeError(" Downloading: Connecting...", false); } $errorMessage = ''; diff --git a/src/Composer/Util/Svn.php b/src/Composer/Util/Svn.php index 1e53e57ae..02b377f7d 100644 --- a/src/Composer/Util/Svn.php +++ b/src/Composer/Util/Svn.php @@ -100,7 +100,7 @@ class Svn public function execute($command, $url, $cwd = null, $path = null, $verbose = false) { // Ensure we are allowed to use this URL by config - $this->config->prohibitUrlByConfig($url); + $this->config->prohibitUrlByConfig($url, $this->io); $svnCommand = $this->getCommand($command, $url, $path); $output = null;