diff options
author | Dylan William Hardison <dylan@hardison.net> | 2018-02-16 17:17:55 +0100 |
---|---|---|
committer | David Lawrence <dkl@mozilla.com> | 2018-02-16 17:17:55 +0100 |
commit | d010759a987a18ee44a515e5d1cc266f154e01a8 (patch) | |
tree | fb1fba41a9755e76c83c79c9bdd522d387d6977f | |
parent | c345cbc05311d8ecc51752c59b102d0323bcfb6c (diff) | |
download | bugzilla-d010759a987a18ee44a515e5d1cc266f154e01a8.tar.gz bugzilla-d010759a987a18ee44a515e5d1cc266f154e01a8.tar.xz |
Bug 1433400 (CVE-2018-5123) Prevent cross-site image requests from leaking contents of certain fields due to regex search
-rw-r--r-- | Bugzilla/CGI.pm | 65 | ||||
-rwxr-xr-x | attachment.cgi | 1 |
2 files changed, 66 insertions, 0 deletions
diff --git a/Bugzilla/CGI.pm b/Bugzilla/CGI.pm index 40262187b..651c31bad 100644 --- a/Bugzilla/CGI.pm +++ b/Bugzilla/CGI.pm @@ -428,6 +428,69 @@ sub close_standby_message { } } +our $ALLOW_UNSAFE_RESPONSE = 0; +# responding to text/plain or text/html is safe +# responding to any request with a referer header is safe +# some things need to have unsafe responses (attachment.cgi) +# everything else should get a 403. +sub _prevent_unsafe_response { + my ($self, $headers) = @_; + state $safe_content_type_re = qr{ + ^ (*COMMIT) # COMMIT makes the regex faster + # by preventing back-tracking. see also perldoc pelre. + # application/x-javascript, xml, atom+xml, rdf+xml, xml-dtd, and json + (?: application/ (?: x(?: -javascript | ml (?: -dtd )? ) + | (?: atom | rdf) \+ xml + | json ) + # text/csv, text/calendar, text/plain, and text/html + | text/ (?: c (?: alendar | sv ) + | plain + | html ) + # used for HTTP push responses + | multipart/x-mixed-replace) + }sx; + state $safe_referer_re = do { + # Note that urlbase must end with a /. + # It almost certainly does, but let's be extra careful. + my $urlbase = Bugzilla->localconfig->{urlbase}; + $urlbase =~ s{/$}{}; + qr{ + # Begins with literal urlbase + ^ (*COMMIT) + \Q$urlbase\E + # followed by a slash or end of string + (?: / + | $ ) + }sx + }; + + return if $ALLOW_UNSAFE_RESPONSE; + + if (Bugzilla->usage_mode == USAGE_MODE_BROWSER) { + # Safe content types are ones that arn't images. + # For now let's assume plain text and html are not valid images. + my $content_type = $headers->{'-type'} // $headers->{'-content_type'} // 'text/html'; + my $is_safe_content_type = $content_type =~ $safe_content_type_re; + + # Safe referers are ones that begin with the urlbase. + my $referer = $self->referer; + my $is_safe_referer = $referer && $referer =~ $safe_referer_re; + + if (!$is_safe_referer && !$is_safe_content_type) { + print $self->SUPER::header(-type => 'text/html', -status => '403 Forbidden'); + if ($content_type ne 'text/html') { + print "Untrusted Referer Header\n"; + if ($ENV{MOD_PERL}) { + my $r = $self->r; + $r->rflush; + $r->status(200); + } + } + exit; + } + } +} + # Override header so we can add the cookies in sub header { my $self = shift; @@ -443,6 +506,8 @@ sub header { %headers = @_; } + $self->_prevent_unsafe_response(\%headers); + if ($self->{'_content_disp'}) { $headers{'-content_disposition'} = $self->{'_content_disp'}; } diff --git a/attachment.cgi b/attachment.cgi index d1523d248..d1b260407 100755 --- a/attachment.cgi +++ b/attachment.cgi @@ -41,6 +41,7 @@ use File::Basename qw(basename); local our $cgi = Bugzilla->cgi; local our $template = Bugzilla->template; local our $vars = {}; +local $Bugzilla::CGI::ALLOW_UNSAFE_RESPONSE = 1; ################################################################################ # Main Body Execution |