[pve-devel] [PATCH manager] fix #3389: Skip CSRF token check also for API tokens on file upload

Thomas Lamprecht t.lamprecht at proxmox.com
Thu Apr 22 10:08:56 CEST 2021


On 22.04.21 10:05, Fabian Grünbichler wrote:
> On April 21, 2021 1:59 pm, Lorenz Stechauner wrote:
>> On file upload, the check for CSRF tokens was already skipped
>> when performing user authentication.This now happens for API
>> tokens also.
>>
>> Signed-off-by: Lorenz Stechauner <l.stechauner at proxmox.com>
>> ---
>>  PVE/HTTPServer.pm | 34 +++++++++++++++++-----------------
>>  1 file changed, 17 insertions(+), 17 deletions(-)
>>
>> diff --git a/PVE/HTTPServer.pm b/PVE/HTTPServer.pm
>> index 64976c7c..63b8583e 100755
>> --- a/PVE/HTTPServer.pm
>> +++ b/PVE/HTTPServer.pm
>> @@ -79,8 +79,8 @@ sub auth_handler {
>>  
>>      if ($require_auth) {
>>  	if ($api_token) {
>> +	    # returns tokenid actually
>>  	    $username = PVE::AccessControl::verify_token($api_token);
>> -	    $rpcenv->set_user($username); #actually tokenid in this case
>>  	} else {
>>  	    die "No ticket\n" if !$ticket;
>>  
>> @@ -94,25 +94,25 @@ sub auth_handler {
>>  		die "No ticket\n"
>>  		    if ($rel_uri ne '/access/tfa' || $method ne 'POST');
>>  	    }
>> +	}
>>  
>> -	    $rpcenv->set_user($username);
>> -
>> -	    if ($method eq 'POST' && $rel_uri =~ m|^/nodes/([^/]+)/storage/([^/]+)/upload$|) {
>> -		my ($node, $storeid) = ($1, $2);
>> -		# we disable CSRF checks if $isUpload is set,
>> -		# to improve security we check user upload permission here
>> -		my $perm = { check => ['perm', "/storage/$storeid", ['Datastore.AllocateTemplate']] };
>> -		$rpcenv->check_api2_permissions($perm, $username, {});
>> -		$isUpload = 1;
>> -	    }
>> +	$rpcenv->set_user($username);
>>  
>> -	    # we skip CSRF check for file upload, because it is
>> -	    # difficult to pass CSRF HTTP headers with native html forms,
>> -	    # and it should not be necessary at all.
>> -	    my $euid = $>;
>> -	    PVE::AccessControl::verify_csrf_prevention_token($username, $token)
>> -		if !$isUpload && ($euid != 0) && ($method ne 'GET');
>> +	if ($method eq 'POST' && $rel_uri =~ m|^/nodes/([^/]+)/storage/([^/]+)/upload$|) {
>> +	    my ($node, $storeid) = ($1, $2);
>> +	    # we disable CSRF checks if $isUpload is set,
>> +	    # to improve security we check user upload permission here
>> +	    my $perm = { check => ['perm', "/storage/$storeid", ['Datastore.AllocateTemplate']] };
>> +	    $rpcenv->check_api2_permissions($perm, $username, {});
>> +	    $isUpload = 1;
>>  	}
>> +
>> +	# we skip CSRF check for file upload, because it is
>> +	# difficult to pass CSRF HTTP headers with native html forms,
>> +	# and it should not be necessary at all.
>> +	my $euid = $>;
>> +	PVE::AccessControl::verify_csrf_prevention_token($username, $token)
>> +	    if !$isUpload && ($euid != 0) && ($method ne 'GET');
> 
> this verify_csrf_prevention_token call was never triggered for API 
> tokens before, on purpose - one of the design goals of API tokens was to 
> provide stateless API access without requiring round-trips like our 
> regular, ticket-based sessions do. CSRF-prevention also does not make 
> much sense outside of the browser context (whereas API tokens are for 
> automated access by non-browser clients).
> 
> with this change we'd now suddenly require CSRF tokens for API tokens as 
> well, and IIRC API tokens can't even get one of those (and even if they 

> could, none of the existing clients would know about that and could no 
> longer do any non-GET requests with tokens).
> 
> I think (but I haven't tested it!) that
> - setting $isUpload for the API token case as well
> - leaving the CSRF check limited to regular (non-API-token) authentication
> 
> should give us the desired effect without any side-effects. the actual 
> upload handling is in PVE::APIServer::AnyEvent and just seems to check 
> for $isUpload in the result of auth_handler.
> 

you're right, good catch! @Lorenz, care to send out a patch bringing it
back it shape?






More information about the pve-devel mailing list