A while back I was playing around with the OAuth2 spec and discovered a flaw in how Vimeo associates Facebook accounts. Their Facebook connect callback URL was vulnerable to a Cross Site Request Forgery, allowing an attacker to connect their Facebook account with a victim’s Vimeo account.
Background
If you try to connect a Facebook account to your Vimeo account, Vimeo sends you to the following URL:
https://www.facebook.com/v2.1/dialog/oauth?client_id=19884028963&redirect_uri=https%3A%2F%2Fvimeo.com%2Fsettings%2Fapps%3Faction%3Dconnect%26service%3Dfacebook&scope=email,public_profile,publish_actions,user_friends&state=f599e2d1b07d64214116415646a6a653
Once you accept the authorization prompt, Facebook returns an HTTP 302, redirecting you back to Vimeo’s redirect_uri
along with a code
that Vimeo uses to access your Facebook info and associate the accounts.
Along with the code
, Facebook sends back the state
value from the URL above so that Vimeo can verify that the callback request is authentic and originated from the same browser that started the flow.
Vimeo correctly set a state
parameter, but used code similar to the following to verify the state:
def callback
if params[:state] == session[:state]
# associate accounts
else
# error csrf detected!
end
end
But what is session[:state]
when the request is not authentic?
…
Both params[:state]
and session[:state]
will be null
.
Attack Scenario
-
The attacker logs into their own Vimeo account and beings the flow to connect their Facebook account.
-
The attacker accepts all permissions, but uses a tool like NoRedirect to block their browser from making the final redirect back to Vimeo:
https://vimeo.com/settings/apps?action=connect&service=facebook&code=<CODE>&state=<state>#_=_
- The attacker uses this URL, omitting the
state
parameter as part of a CSRF attack on a page that the victim (who is currently logged into Vimeo) is likely to view.
<img src='https://vimeo.com/settings/apps?action=connect&service=facebook&code=<CODE>#_=_' />
- The victim’s Vimeo account is now associated with the attacker’s Facebook account. The attacker can now use their Facebook to login to the victim’s Vimeo account.
Remediation
The callback must ensure that the state
query parameter matches the persisted state
token AND that both values are non-nil.