Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
bugzilla
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
etersoft
bugzilla
Commits
2f385c10
Commit
2f385c10
authored
Apr 17, 2014
by
Frédéric Buclin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Bug 713926: (CVE-2014-1517) [SECURITY] Login form lacks CSRF protection
r=dkl r=LpSolit a=justdave
parent
88355207
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
141 additions
and
55 deletions
+141
-55
Auth.pm
Bugzilla/Auth.pm
+1
-1
CGI.pm
Bugzilla/Auth/Login/CGI.pm
+37
-4
Cookie.pm
Bugzilla/Auth/Persist/Cookie.pm
+4
-0
CGI.pm
Bugzilla/CGI.pm
+13
-0
Template.pm
Bugzilla/Template.pm
+5
-0
Util.pm
Bugzilla/Util.pm
+14
-2
WebService.pm
Bugzilla/WebService.pm
+13
-13
User.pm
Bugzilla/WebService/User.pm
+23
-31
relogin.cgi
relogin.cgi
+13
-0
login-small.html.tmpl
template/en/default/account/auth/login-small.html.tmpl
+3
-1
login.html.tmpl
template/en/default/account/auth/login.html.tmpl
+3
-1
sudo.html.tmpl
template/en/default/admin/sudo.html.tmpl
+3
-2
user-error.html.tmpl
template/en/default/global/user-error.html.tmpl
+9
-0
No files found.
Bugzilla/Auth.pm
View file @
2f385c10
...
...
@@ -152,7 +152,7 @@ sub _handle_login_result {
if
(
$self
->
{
_info_getter
}
->
{
successful
}
->
requires_persistence
and
!
Bugzilla
->
request_cache
->
{
auth_no_automatic_login
})
{
$self
->
{
_persister
}
->
persist_login
(
$user
);
$
user
->
{
_login_token
}
=
$
self
->
{
_persister
}
->
persist_login
(
$user
);
}
}
elsif
(
$fail_code
==
AUTH_ERROR
)
{
...
...
Bugzilla/Auth/Login/CGI.pm
View file @
2f385c10
...
...
@@ -14,19 +14,52 @@ use Bugzilla::Constants;
use
Bugzilla::WebService::
Constants
;
use
Bugzilla::
Util
;
use
Bugzilla::
Error
;
use
Bugzilla::
Token
;
sub
get_login_info
{
my
(
$self
)
=
@_
;
my
$params
=
Bugzilla
->
input_params
;
my
$cgi
=
Bugzilla
->
cgi
;
my
$login
=
trim
(
delete
$params
->
{
'Bugzilla_login'
});
my
$password
=
delete
$params
->
{
'Bugzilla_password'
};
# The token must match the cookie to authenticate the request.
my
$login_token
=
delete
$params
->
{
'Bugzilla_login_token'
};
my
$login_cookie
=
$cgi
->
cookie
(
'Bugzilla_login_request_cookie'
);
my
$username
=
trim
(
delete
$params
->
{
"Bugzilla_login"
});
my
$password
=
delete
$params
->
{
"Bugzilla_password"
};
my
$valid
=
0
;
# If the web browser accepts cookies, use them.
if
(
$login_token
&&
$login_cookie
)
{
my
(
$time
,
undef
)
=
split
(
/-/
,
$login_token
);
# Regenerate the token based on the information we have.
my
$expected_token
=
issue_hash_token
([
'login_request'
,
$login_cookie
],
$time
);
$valid
=
1
if
$expected_token
eq
$login_token
;
$cgi
->
remove_cookie
(
'Bugzilla_login_request_cookie'
);
}
# WebServices and other local scripts can bypass this check.
# This is safe because we won't store a login cookie in this case.
elsif
(
Bugzilla
->
usage_mode
!=
USAGE_MODE_BROWSER
)
{
$valid
=
1
;
}
# Else falls back to the Referer header and accept local URLs.
# Attachments are served from a separate host (ideally), and so
# an evil attachment cannot abuse this check with a redirect.
elsif
(
my
$referer
=
$cgi
->
referer
)
{
my
$urlbase
=
correct_urlbase
();
$valid
=
1
if
$referer
=~
/^\Q$urlbase\E/
;
}
# If the web browser doesn't accept cookies and the Referer header
# is missing, we have no way to make sure that the authentication
# request comes from the user.
elsif
(
$login
&&
$password
)
{
ThrowUserError
(
'auth_untrusted_request'
,
{
login
=>
$login
});
}
if
(
!
defined
$username
||
!
defined
$passwor
d
)
{
if
(
!
$login
||
!
$password
||
!
$vali
d
)
{
return
{
failure
=>
AUTH_NODATA
};
}
return
{
username
=>
$
username
,
password
=>
$password
};
return
{
username
=>
$
login
,
password
=>
$password
};
}
sub
fail_nodata
{
...
...
Bugzilla/Auth/Persist/Cookie.pm
View file @
2f385c10
...
...
@@ -52,6 +52,10 @@ sub persist_login {
$dbh
->
bz_commit_transaction
();
# We do not want WebServices to generate login cookies.
# All we need is the login token for User.login.
return
$login_cookie
if
i_am_webservice
();
# Prevent JavaScript from accessing login cookies.
my
%
cookieargs
=
(
'-httponly'
=>
1
);
...
...
Bugzilla/CGI.pm
View file @
2f385c10
...
...
@@ -286,6 +286,7 @@ sub close_standby_message {
# Override header so we can add the cookies in
sub
header
{
my
$self
=
shift
;
my
$user
=
Bugzilla
->
user
;
# If there's only one parameter, then it's a Content-Type.
if
(
scalar
(
@_
)
==
1
)
{
...
...
@@ -293,6 +294,18 @@ sub header {
unshift
(
@_
,
'-type'
=>
shift
(
@_
));
}
if
(
!
$user
->
id
&&
$user
->
authorizer
->
can_login
&&
!
$self
->
cookie
(
'Bugzilla_login_request_cookie'
))
{
my
%
args
;
$args
{
'-secure'
}
=
1
if
Bugzilla
->
params
->
{
ssl_redirect
};
$self
->
send_cookie
(
-
name
=>
'Bugzilla_login_request_cookie'
,
-
value
=>
generate_random_password
(),
-
httponly
=>
1
,
%
args
);
}
# Add the cookies in if we have any
if
(
scalar
(
@
{
$self
->
{
Bugzilla_cookie_list
}}))
{
unshift
(
@_
,
'-cookie'
=>
$self
->
{
Bugzilla_cookie_list
});
...
...
Bugzilla/Template.pm
View file @
2f385c10
...
...
@@ -889,6 +889,11 @@ sub create {
# Allow templates to generate a token themselves.
'issue_hash_token'
=>
\&
Bugzilla::Token::
issue_hash_token
,
'get_login_request_token'
=>
sub
{
my
$cookie
=
Bugzilla
->
cgi
->
cookie
(
'Bugzilla_login_request_cookie'
);
return
$cookie
?
issue_hash_token
([
'login_request'
,
$cookie
])
:
''
;
},
# A way for all templates to get at Field data, cached.
'bug_fields'
=>
sub
{
my
$cache
=
Bugzilla
->
request_cache
;
...
...
Bugzilla/Util.pm
View file @
2f385c10
...
...
@@ -13,8 +13,8 @@ use base qw(Exporter);
@
Bugzilla::Util::
EXPORT
=
qw(trick_taint detaint_natural detaint_signed
html_quote url_quote xml_quote
css_class_quote html_light_quote
i_am_cgi
correct_urlbase remote_ip valida
te_ip
do_ssl_redirect_if_required use_attachbase
i_am_cgi
i_am_webservice correct_urlbase remo
te_ip
validate_ip
do_ssl_redirect_if_required use_attachbase
diff_arrays on_main_db say
trim wrap_hard wrap_comment find_wrap_point
format_time validate_date validate_time datetime_from
...
...
@@ -230,6 +230,12 @@ sub i_am_cgi {
return
exists
$ENV
{
'SERVER_SOFTWARE'
}
?
1
:
0
;
}
sub
i_am_webservice
{
my
$usage_mode
=
Bugzilla
->
usage_mode
;
return
$usage_mode
==
USAGE_MODE_XMLRPC
||
$usage_mode
==
USAGE_MODE_JSON
;
}
# This exists as a separate function from Bugzilla::CGI::redirect_to_https
# because we don't want to create a CGI object during XML-RPC calls
# (doing so can mess up XML-RPC).
...
...
@@ -862,6 +868,7 @@ Bugzilla::Util - Generic utility functions for bugzilla
# Functions that tell you about your environment
my $is_cgi = i_am_cgi();
my $is_webservice = i_am_webservice();
my $urlbase = correct_urlbase();
# Data manipulation
...
...
@@ -989,6 +996,11 @@ Tells you whether or not you are being run as a CGI script in a web
server. For example, it would return false if the caller is running
in a command-line script.
=item C<i_am_webservice()>
Tells you whether or not the current usage mode is WebServices related
such as JSONRPC or XMLRPC.
=item C<correct_urlbase()>
Returns either the C<sslbase> or C<urlbase> parameter, depending on the
...
...
Bugzilla/WebService.pm
View file @
2f385c10
...
...
@@ -128,9 +128,7 @@ There are various ways to log in:
=item C<User.login>
You can use L<Bugzilla::WebService::User/login> to log in as a Bugzilla
user. This issues standard HTTP cookies that you must then use in future
calls, so your client must be capable of receiving and transmitting
cookies.
user. This issues a token that you must then use in future calls.
=item C<Bugzilla_login> and C<Bugzilla_password>
...
...
@@ -150,19 +148,21 @@ WebService method to perform a login:
=item C<Bugzilla_restrictlogin> (boolean) - Optional. If true,
then your login will only be valid for your IP address.
=item C<Bugzilla_rememberlogin> (boolean) - Optional. If true,
then the cookie sent back to you with the method response will
not expire.
=back
The C<Bugzilla_restrictlogin> and C<Bugzilla_rememberlogin> options
are only used when you have also specified C<Bugzilla_login> and
C<Bugzilla_password>.
The C<Bugzilla_restrictlogin> option is only used when you have also
specified C<Bugzilla_login> and C<Bugzilla_password>.
=item C<Bugzilla_token>
B<Added in Bugzilla 5.0 and backported to 4.4.3>
You can specify C<Bugzilla_token> as argument to any WebService method,
and you will be logged in as that user if the token is correct. This is
the token returned when calling C<User.login> mentioned above.
Note that Bugzilla will return HTTP cookies along with the method
response when you use these arguments (just like the C<User.login> method
above).
Support for using login cookies for authentication has been dropped
for security reasons.
=back
...
...
Bugzilla/WebService/User.pm
View file @
2f385c10
...
...
@@ -52,7 +52,6 @@ use constant MAPPED_RETURNS => {
sub
login
{
my
(
$self
,
$params
)
=
@_
;
my
$remember
=
$params
->
{
remember
};
# Username and password params are required
foreach
my
$param
(
"login"
,
"password"
)
{
...
...
@@ -60,33 +59,18 @@ sub login {
||
ThrowCodeError
(
'param_required'
,
{
param
=>
$param
});
}
# Convert $remember from a boolean 0/1 value to a CGI-compatible one.
if
(
defined
(
$remember
))
{
$remember
=
$remember
?
'on'
:
''
;
}
else
{
# Use Bugzilla's default if $remember is not supplied.
$remember
=
Bugzilla
->
params
->
{
'rememberlogin'
}
eq
'defaulton'
?
'on'
:
''
;
}
# Make sure the CGI user info class works if necessary.
my
$input_params
=
Bugzilla
->
input_params
;
$input_params
->
{
'Bugzilla_login'
}
=
$params
->
{
login
};
$input_params
->
{
'Bugzilla_password'
}
=
$params
->
{
password
};
$input_params
->
{
'Bugzilla_re
member'
}
=
$remember
;
$input_params
->
{
'Bugzilla_re
strictlogin'
}
=
$params
->
{
restrict_login
}
;
my
$user
=
Bugzilla
->
login
();
my
$result
=
{
id
=>
$self
->
type
(
'int'
,
$user
->
id
)
};
# We will use the stored cookie value combined with the user id
# to create a token that can be used with future requests in the
# query parameters
my
$login_cookie
=
first
{
$_
->
name
eq
'Bugzilla_logincookie'
}
@
{
Bugzilla
->
cgi
->
{
'Bugzilla_cookie_list'
}
};
if
(
$login_cookie
)
{
$result
->
{
'token'
}
=
$user
->
id
.
"-"
.
$login_cookie
->
value
;
if
(
$user
->
{
_login_token
})
{
$result
->
{
'token'
}
=
$user
->
id
.
"-"
.
$user
->
{
_login_token
};
}
return
$result
;
...
...
@@ -440,24 +424,19 @@ etc. This method logs in an user.
=item C<password> (string) - The user's password.
=item C<remember> (bool) B<Optional> - if the cookies returned by the
call to login should expire with the session or not. In order for
this option to have effect the Bugzilla server must be configured to
allow the user to set this option - the Bugzilla parameter
I<rememberlogin> must be set to "defaulton" or
"defaultoff". Addionally, the client application must implement
management of cookies across sessions.
=item C<restrict_login> (bool) B<Optional> - If set to a true value,
the token returned by this method will only be valid from the IP address
which called this method.
=back
=item B<Returns>
On success, a hash containing two items, C<id>, the numeric id of the
user that was logged in, and a C<token> which can be passed in
the parameters as authentication in other calls. A set of http cookies
is also sent with the response. These cookies *or* the token can be sent
along with any future requests to the webservice, for the duration of the
session.
user that was logged in, and a C<token> which can be passed in the parameters
as authentication in other calls. The token can be sent along with any future
requests to the webservice, for the duration of the session, i.e. till
L<User.logout|/logout> is called.
=item B<Errors>
...
...
@@ -483,6 +462,19 @@ A login or password parameter was not provided.
=back
=item B<History>
=over
=item C<remember> was removed in Bugzilla B<4.4> as this method no longer
creates a login cookie.
=item C<restrict_login> was added in Bugzilla B<4.4>.
=item C<token> was added in Bugzilla B<4.4>.
=back
=back
=head2 logout
...
...
relogin.cgi
View file @
2f385c10
...
...
@@ -51,6 +51,19 @@ elsif ($action eq 'prepare-sudo') {
# Keep a temporary record of the user visiting this page
$vars
->
{
'token'
}
=
issue_session_token
(
'sudo_prepared'
);
if
(
$user
->
authorizer
->
can_login
)
{
my
$value
=
generate_random_password
();
my
%
args
;
$args
{
'-secure'
}
=
1
if
Bugzilla
->
params
->
{
ssl_redirect
};
$cgi
->
send_cookie
(
-
name
=>
'Bugzilla_login_request_cookie'
,
-
value
=>
$value
,
-
httponly
=>
1
,
%
args
);
$vars
->
{
'login_request_token'
}
=
issue_hash_token
([
'login_request'
,
$value
]);
}
# Show the sudo page
$vars
->
{
'target_login_default'
}
=
$cgi
->
param
(
'target_login'
);
$vars
->
{
'reason_default'
}
=
$cgi
->
param
(
'reason'
);
...
...
template/en/default/account/auth/login-small.html.tmpl
View file @
2f385c10
...
...
@@ -56,7 +56,9 @@
[%+ "checked" IF Param('rememberlogin') == "defaulton" %]>
<label for="Bugzilla_remember[% qs_suffix %]">Remember</label>
[% END %]
<input type="submit" name="GoAheadAndLogIn" value="Log in"
<input type="hidden" name="Bugzilla_login_token"
value="[% get_login_request_token() FILTER html %]">
<input type="submit" name="GoAheadAndLogIn" value="Log in"
id="log_in[% qs_suffix %]">
<script type="text/javascript">
mini_login_constants = {
...
...
template/en/default/account/auth/login.html.tmpl
View file @
2f385c10
...
...
@@ -68,8 +68,10 @@
[% PROCESS "global/hidden-fields.html.tmpl"
exclude="^Bugzilla_(login|password|restrictlogin)$" %]
<input type="hidden" name="Bugzilla_login_token"
value="[% get_login_request_token() FILTER html %]">
<input type="submit" name="GoAheadAndLogIn" value="Log in" id="log_in">
<p>
(Note: you should make sure cookies are enabled for this site.
Otherwise, you will be required to log in frequently.)
...
...
template/en/default/admin/sudo.html.tmpl
View file @
2f385c10
...
...
@@ -67,9 +67,10 @@
<p>
Finally, enter <label for="Bugzilla_password">your [% terms.Bugzilla %]
password</label>:
<input type="hidden" name="Bugzilla_login" value="
[%- user.login FILTER html %]">
<input type="hidden" name="Bugzilla_login" value="[% user.login FILTER html %]">
<input type="password" id="Bugzilla_password" name="Bugzilla_password" size="20">
<input type="hidden" name="Bugzilla_login_token"
value="[% login_request_token FILTER html %]">
<br>
This is done for two reasons. First of all, it is done to reduce
the chances of someone doing large amounts of damage using your
...
...
template/en/default/global/user-error.html.tmpl
View file @
2f385c10
...
...
@@ -217,6 +217,15 @@
[% Hook.process("auth_failure") %]
[% ELSIF error == "auth_untrusted_request" %]
[% title = "Untrusted Authentication Request" %]
You tried to log in using the <em>[% login FILTER html %]</em> account,
but [% terms.Bugzilla %] is unable to trust your request. Make sure
your web browser accepts cookies and that you haven't been redirected
here from an external web site.
<a href="index.cgi?GoAheadAndLogIn=1">Click here</a> if you really want
to log in.
[% ELSIF error == "attachment_deletion_disabled" %]
[% title = "Attachment Deletion Disabled" %]
Attachment deletion is disabled on this installation.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment