Closed zharikovpro closed 7 years ago
Bandaid in config/initializers/omniauth.rb:
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# omniauth-steam doesn't check openid.op_endpoint
# Attacker can use it's own fake openid server which always grants auth
# and route auth calls to it with requests like
#
# http://api.localhost:3000/omniauth/steam/callback?auth_origin_url=http%3A%2F%2Fwww.site.com&resource_class=User&_method=post&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=id_res&openid.op_endpoint=https%3A%2F%2Ffakeserver.com%2Fopenid%2Flogin&openid.claimed_id=http%3A%2F%2Fsteamcommunity.com%2Fopenid%2Fid%2F76561198168285384&openid.identity=http%3A%2F%2Fsteamcommunity.com%2Fopenid%2Fid%2F76561198168285384&openid.return_to=http%3A%2F%2Fsite.com%2Fomniauth%2Fsteam%2Fcallback%3Fauth_origin_url%3Dhttp%253A%252F%252Fwww.site.com%26resource_class%3DUser%26_method%3Dpost&openid.response_nonce=2016-10-25T14%3A21%3A45ZtfzZbrgiBUBNDEdvmsmGMb%2FQKWY%3D&openid.assoc_handle=1234567890&openid.signed=signed%2Cop_endpoint%2Cclaimed_id%2Cidentity%2Creturn_to%2Cresponse_nonce%2Cassoc_handle&openid.sig=KVlpWTA8NqBU6oKog1fNkg%2B9Wwc%3D
# (this example contains fakeserver.com instead of steamcommunity.com in openid.op_endpoint param)
#
# also check openid.claimed_id and openid.identity for legitimate value from Steam, as they may have different URLs
class OpenidProtection
def initialize(app)
@app = app
end
def redirect
[303, {'Location' => 'http://site.com/api/v1/auth/steam?auth_origin_url=http://www.site.com', 'Content-Type' => 'text/html'}, ['See Other']]
end
def call(env)
request = Rack::Request.new(env)
openid_endpoint = request.params['openid.op_endpoint']
if openid_endpoint.present?
unless openid_endpoint.start_with?('https://steamcommunity.com/openid')
return redirect
end
end
openid_claimed_id = request.params['openid.claimed_id']
if openid_claimed_id.present?
unless openid_claimed_id.start_with?('http://steamcommunity.com/openid')
return redirect
end
end
openid_identity = request.params['openid.identity']
if openid_identity.present?
unless openid_identity.start_with?('http://steamcommunity.com/openid')
return redirect
end
end
origin = request.params['origin']
if origin.present?
return redirect
end
auth_origin_url = request.params['auth_origin_url']
if auth_origin_url.present?
unless DeviseTokenAuth.redirect_whitelist.include?(auth_origin_url)
return redirect
end
end
@app.call(env)
end
end
Rails.application.config.middleware.use OpenidProtection
Thanks a lot for the report @zharikovpro! Does anyone has an idea of how could we patch this? Should it be patched on omniauth-steam or in the omniauth-openid?
@reu You should be validating claimed identifier
format. As per docs, it should be http://steamcommunity.com/openid/id/<steamid>
.
This is not an issue in omniauth-openid
as the OpenID spec actually allows this.
I just wanted to note that you can retrieve SteamID64 from any SteamID format and/or profile URL (be it custom URL or not).
This plugin acccepts params:
Turned out that attacker can modify op_endpoint and/or other steamcommunity links and route auth request to self-owned openid server which will grant access to any steam id of choice. That way attacker is able to authenticate as any user on site, having it's steam64 id.
Right this vulnerability can be closed using global middleware - to check that openid.op_endpoint must start with https://steamcommunity.com/openid and openid.claimed_id, openid.identity must start with http://steamcommunity.com/openid , otherwise request will fail.