mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-19 05:12:41 +01:00
Whitelist allowed editor protocols
Summary: This is the other half of D8548. Specifically, the attack here was to set your own editor link to `javascript\n:...` and then you could XSS yourself. This isn't a hugely damaging attack, but we can be more certain by adding a whitelist here. We already whitelist linkable protocols in remarkup (`uri.allowed-protocols`) in general. Test Plan: Tried to set and use valid/invalid editor URIs. {F130883} {F130884} Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Differential Revision: https://secure.phabricator.com/D8551
This commit is contained in:
parent
ced70f6b32
commit
039b8e43b9
8 changed files with 191 additions and 14 deletions
|
@ -1090,6 +1090,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationFiles' => 'applications/files/application/PhabricatorApplicationFiles.php',
|
||||
'PhabricatorApplicationFlags' => 'applications/flag/application/PhabricatorApplicationFlags.php',
|
||||
'PhabricatorApplicationHarbormaster' => 'applications/harbormaster/application/PhabricatorApplicationHarbormaster.php',
|
||||
'PhabricatorApplicationHelp' => 'applications/help/application/PhabricatorApplicationHelp.php',
|
||||
'PhabricatorApplicationHerald' => 'applications/herald/application/PhabricatorApplicationHerald.php',
|
||||
'PhabricatorApplicationHome' => 'applications/home/application/PhabricatorApplicationHome.php',
|
||||
'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php',
|
||||
|
@ -1129,6 +1130,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationSlowvote' => 'applications/slowvote/application/PhabricatorApplicationSlowvote.php',
|
||||
'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php',
|
||||
'PhabricatorApplicationSubscriptions' => 'applications/subscriptions/application/PhabricatorApplicationSubscriptions.php',
|
||||
'PhabricatorApplicationSupport' => 'applications/support/application/PhabricatorApplicationSupport.php',
|
||||
'PhabricatorApplicationSystem' => 'applications/system/application/PhabricatorApplicationSystem.php',
|
||||
'PhabricatorApplicationTest' => 'applications/base/controller/__tests__/PhabricatorApplicationTest.php',
|
||||
'PhabricatorApplicationTokens' => 'applications/tokens/application/PhabricatorApplicationTokens.php',
|
||||
|
@ -1569,6 +1571,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHash' => 'infrastructure/util/PhabricatorHash.php',
|
||||
'PhabricatorHashTestCase' => 'infrastructure/util/__tests__/PhabricatorHashTestCase.php',
|
||||
'PhabricatorHelpController' => 'applications/help/controller/PhabricatorHelpController.php',
|
||||
'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php',
|
||||
'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php',
|
||||
'PhabricatorHomeController' => 'applications/home/controller/PhabricatorHomeController.php',
|
||||
'PhabricatorHomeMainController' => 'applications/home/controller/PhabricatorHomeMainController.php',
|
||||
|
@ -3751,6 +3754,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationFiles' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationFlags' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationHarbormaster' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationHelp' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationHerald' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationHome' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationLaunchView' => 'AphrontView',
|
||||
|
@ -3788,6 +3792,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationSlowvote' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationStatusView' => 'AphrontView',
|
||||
'PhabricatorApplicationSubscriptions' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationSupport' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationSystem' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationTest' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationTokens' => 'PhabricatorApplication',
|
||||
|
@ -4315,6 +4320,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorHarbormasterConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorHashTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorHelpController' => 'PhabricatorController',
|
||||
'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController',
|
||||
'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController',
|
||||
'PhabricatorHomeController' => 'PhabricatorController',
|
||||
'PhabricatorHomeMainController' => 'PhabricatorHomeController',
|
||||
|
|
|
@ -23,9 +23,6 @@ class AphrontDefaultApplicationConfiguration
|
|||
'' => 'DarkConsoleController',
|
||||
'data/(?P<key>[^/]+)/' => 'DarkConsoleDataController',
|
||||
),
|
||||
'/help/' => array(
|
||||
'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@ final class PhabricatorSecurityConfigOptions
|
|||
}
|
||||
|
||||
public function getOptions() {
|
||||
$support_href = PhabricatorEnv::getDoclink(
|
||||
'article/feedback.html');
|
||||
|
||||
return array(
|
||||
$this->newOption('security.alternate-file-domain', 'string', null)
|
||||
->setSummary(pht("Alternate domain to serve files from."))
|
||||
|
@ -126,6 +129,41 @@ final class PhabricatorSecurityConfigOptions
|
|||
->addExample(
|
||||
'{"http": true, "https": true"}', pht('Valid Setting'))
|
||||
->setLocked(true),
|
||||
$this->newOption(
|
||||
'uri.allowed-editor-protocols',
|
||||
'set',
|
||||
array(
|
||||
'http' => true,
|
||||
'https' => true,
|
||||
|
||||
// This handler is installed by Textmate.
|
||||
'txmt' => true,
|
||||
|
||||
// This handler is for MacVim.
|
||||
'mvim' => true,
|
||||
|
||||
// Unofficial handler for Vim.
|
||||
'vim' => true,
|
||||
|
||||
// Unofficial handler for Sublime.
|
||||
'subl' => true,
|
||||
|
||||
// Unofficial handler for Emacs.
|
||||
'emacs' => true,
|
||||
|
||||
// This isn't a standard handler installed by an application, but
|
||||
// is a reasonable name for a user-installed handler.
|
||||
'editor' => true,
|
||||
))
|
||||
->setSummary(pht('Whitelists editor protocols for "Open in Editor".'))
|
||||
->setDescription(
|
||||
pht(
|
||||
"Users can configure a URI pattern to open files in a text ".
|
||||
"editor. The URI must use a protocol on this whitelist.\n\n".
|
||||
"(If you use an editor which defines a protocol not on this ".
|
||||
"list, [[ %s | let us know ]] and we'll update the defaults.)",
|
||||
$support_href))
|
||||
->setLocked(true),
|
||||
$this->newOption(
|
||||
'celerity.resource-hash',
|
||||
'string',
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorApplicationHelp extends PhabricatorApplication {
|
||||
|
||||
public function canUninstall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isUnlisted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRoutes() {
|
||||
return array(
|
||||
'/help/' => array(
|
||||
'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController',
|
||||
'editorprotocol/' => 'PhabricatorHelpEditorProtocolController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorHelpEditorProtocolController
|
||||
extends PhabricatorHelpController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setMethod('GET')
|
||||
->setSubmitURI('/settings/panel/display/')
|
||||
->setTitle(pht('Unsupported Editor Protocol'))
|
||||
->appendParagraph(
|
||||
pht(
|
||||
'Your configured editor URI uses an unsupported protocol. Change '.
|
||||
'your settings to use a supported protocol, or ask your '.
|
||||
'administrator to add support for the chosen protocol by '.
|
||||
'configuring: %s',
|
||||
phutil_tag('tt', array(), 'uri.allowed-editor-protocols')))
|
||||
->addSubmitButton(pht('Change Settings'))
|
||||
->addCancelButton('/');
|
||||
|
||||
return id(new AphrontDialogResponse())
|
||||
->setDialog($dialog);
|
||||
}
|
||||
|
||||
public static function hasAllowedProtocol($uri) {
|
||||
$uri = new PhutilURI($uri);
|
||||
$editor_protocol = $uri->getProtocol();
|
||||
if (!$editor_protocol) {
|
||||
// The URI must have a protocol.
|
||||
return false;
|
||||
}
|
||||
|
||||
$allowed_key = 'uri.allowed-editor-protocols';
|
||||
$allowed_protocols = PhabricatorEnv::getEnvConfig($allowed_key);
|
||||
if (empty($allowed_protocols[$editor_protocol])) {
|
||||
// The protocol must be on the allowed protocol whitelist.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -441,14 +441,26 @@ final class PhabricatorUser
|
|||
}
|
||||
}
|
||||
|
||||
if ($editor) {
|
||||
return strtr($editor, array(
|
||||
'%%' => '%',
|
||||
'%f' => phutil_escape_uri($path),
|
||||
'%l' => phutil_escape_uri($line),
|
||||
'%r' => phutil_escape_uri($callsign),
|
||||
));
|
||||
if (!strlen($editor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$uri = strtr($editor, array(
|
||||
'%%' => '%',
|
||||
'%f' => phutil_escape_uri($path),
|
||||
'%l' => phutil_escape_uri($line),
|
||||
'%r' => phutil_escape_uri($callsign),
|
||||
));
|
||||
|
||||
// The resulting URI must have an allowed protocol. Otherwise, we'll return
|
||||
// a link to an error page explaining the misconfiguration.
|
||||
|
||||
$ok = PhabricatorHelpEditorProtocolController::hasAllowedProtocol($uri);
|
||||
if (!$ok) {
|
||||
return '/help/editorprotocol/';
|
||||
}
|
||||
|
||||
return (string)$uri;
|
||||
}
|
||||
|
||||
public function getAlternateCSRFString() {
|
||||
|
|
|
@ -26,6 +26,8 @@ final class PhabricatorSettingsPanelDisplayPreferences
|
|||
$pref_monospaced_textareas =
|
||||
PhabricatorUserPreferences::PREFERENCE_MONOSPACED_TEXTAREAS;
|
||||
|
||||
$errors = array();
|
||||
$e_editor = null;
|
||||
if ($request->isFormPost()) {
|
||||
$monospaced = $request->getStr($pref_monospaced);
|
||||
|
||||
|
@ -42,9 +44,35 @@ final class PhabricatorSettingsPanelDisplayPreferences
|
|||
$pref_monospaced_textareas,
|
||||
$request->getStr($pref_monospaced_textareas));
|
||||
|
||||
$preferences->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI('?saved=true'));
|
||||
$editor_pattern = $preferences->getPreference($pref_editor);
|
||||
if (strlen($editor_pattern)) {
|
||||
$ok = PhabricatorHelpEditorProtocolController::hasAllowedProtocol(
|
||||
$editor_pattern);
|
||||
if (!$ok) {
|
||||
$allowed_key = 'uri.allowed-editor-protocols';
|
||||
$allowed_protocols = PhabricatorEnv::getEnvConfig($allowed_key);
|
||||
|
||||
$proto_names = array();
|
||||
foreach (array_keys($allowed_protocols) as $protocol) {
|
||||
$proto_names[] = $protocol.'://';
|
||||
}
|
||||
|
||||
$errors[] = pht(
|
||||
'Editor link has an invalid or missing protocol. You must '.
|
||||
'use a whitelisted editor protocol from this list: %s. To '.
|
||||
'add protocols, update %s.',
|
||||
implode(', ', $proto_names),
|
||||
phutil_tag('tt', array(), $allowed_key));
|
||||
|
||||
$e_editor = pht('Invalid');
|
||||
}
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$preferences->save();
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->getPanelURI('?saved=true'));
|
||||
}
|
||||
}
|
||||
|
||||
$example_string = <<<EXAMPLE
|
||||
|
@ -95,8 +123,8 @@ EXAMPLE;
|
|||
id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Editor Link'))
|
||||
->setName($pref_editor)
|
||||
// How to pht()
|
||||
->setCaption($editor_instructions)
|
||||
->setError($e_editor)
|
||||
->setValue($preferences->getPreference($pref_editor)))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
|
@ -139,6 +167,7 @@ EXAMPLE;
|
|||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Display Preferences'))
|
||||
->setFormErrors($errors)
|
||||
->setFormSaved($request->getStr('saved') === 'true')
|
||||
->setForm($form);
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorApplicationSupport extends PhabricatorApplication {
|
||||
|
||||
public function canUninstall() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isUnlisted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getRoutes() {
|
||||
return array(
|
||||
'/help/' => array(
|
||||
'keyboardshortcut/' => 'PhabricatorHelpKeyboardShortcutController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue