[Engine-devel] Proposal to make REST API more webapp-friendly

Vojtech Szocs vszocs at redhat.com
Wed Apr 17 12:46:35 UTC 2013


Hi Michael, thanks for your feedback.

>>> * cookie parsing/formatting is not trivial
>>>   --> extra complexity imposed on REST clients
>
> i wouldn't call it a cookie blocker, as in most cases (including ours) cookie contains
> restricted amount of records.

I agree, this isn't strictly a blocker issue. It's the other issues (Cross-Site Request Forgery vulnerability, limited cookie access from JavaScript) that make cookies hard to work with.

>>> * cookies are the primary source of Cross-Site Request Forgery
>>> [http://en.wikipedia.org/wiki/Cross-site_request_forgery] attacks
>>>   --> malicious websites/scripts can forge requests to REST API that will
>>>   include the cookie, compromising user session
>
> same true for the authorization header, session being passed via HTTP headers

That's correct. Once set (either via browser-specific popup, or via JavaScript AJAX request) the browser will always include HTTP Authorization header for all requests to given location, AFAIK. The only way to prevent browser from including HTTP Authorization header for all requests to given location, is to simply close the browser window.

Important thing is that HTTP Basic Auth is vulnerable to CSRF mainly because of an easy way to "replay" attacks. This is why I think REST API authentication should be protected against "replay" attacks.

>> We currently return the JSESSIONID also using HTTP headers. We currently return the jsession id also as part of the response HTTP headers, but the client still needs to pass a cookie with the appropriate value in order for the REST session to work. Isn't that enough to cope with this issue?
>
> api, can consume JSESSIONID from the header indeed, but my problem with this approach
> is a persistence of the http headers in browsers.

Persistence of such JSESSIONID information isn't really a problem :) we can use HTML5 web storage API, e.g. session storage, to securely persist such information on client (or we can use a special cookie for this, scoped to WebAdmin path, *not* REST API path). WebAdmin can simply mimic the cookie-handling behavior in browsers, i.e. send JSESSIONID header (instead of cookie) for each REST API request.

>>> HTTP Basic Auth [http://en.wikipedia.org/wiki/Basic_access_authentication]
>>> over (non-secure) HTTP connection means sending user credentials
>>> (username/password/domain) in easy-to-decode cleartext, i.e. the value is
>>> *not* encrypted or hashed in any way. Using secure lower-level protocol
>>> (SSL) fixes the consequence, rather than the root cause of the
>>> confidentiality issue.
>
> same is true for any sensitive date being passed via plain text (including cookies)

That's correct. The solution mentioned in my original email was to hash sensitive data with some sort of private key (password?) to make it harder to sniff sensitive data.

>>> Furthermore, browsers typically remember HTTP Basic Auth information (either
>>> via browser-specific popup, or via XmlHttpRequest) until the browser window
>>> is closed. This means the webapp has no control over HTTP Basic Auth header
>>> after it has been set! This is the reason why it's hard to implement
>>> "logout" functionality in webapps when using HTTP Basic Auth.
>
> right, that is my concern of using headers as well, better solution may be sending
> JSESSION id via URI matrix parameter, e.g /api/vms;sessionid=xxx

Yes, this is possible. But maybe from REST API design perspective, isn't using some (custom) authentication header more clean approach?

>>> I've just read an excellent article at
>>> [http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/]
>>> which describes easy yet secure authentication scheme inspired by Amazon Web
>>> Services REST API authentication
>>> [http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html].
>>> The idea is simple: collect auth information, hash (sign) it with a private
>>> key, and send everything to server. To guard against Replay attacks, just
>>> provide some timestamp to enforce request expiry after some time (say, 5-15
>>> minutes). Easy and simple!
>
> 1. this concept has very same drawbacks as any other content encryption

I assume their goal was to implement easy yet secure-enough authentication scheme for public API (secure from malicious exploit perspective, not necessarily content encryption perspective).

The point was to use private key that's only known to client and server, and nobody else. You hash sensitive data with private key and provide this hash as extra request attribute. The server just does the same thing as client and compares the hash.

> 2. decoding time stamp from request/s will produce fair load for the server as well
> and won't protect the server against DDOS, also it shouldn't as it's not api/webapp
> prerogative.

Timestamp processing depends on implementation efficiency, but yeah you are right, it will increase the processing load in general.

Regarding DDOS, well, this is another story :)

> in general what Vojtech is trying to achieve is passing session via some other
> container than cookie as webapp/browsers can't omit auth. header in runtime,

Exactly.

> what is only justifying my resistance of passing session id via http header,
> i think using matrix parameter (as mentioned above) may give you a decent solution.

The matrix parameter proposal is also OK for me, even though personaly I'm more in favor of using custom HTTP request/response (e.g. "JSESSIONID") header for this purpose.

But it doesn't really matter, for the purpose of transmitting session ID value, anything other than cookie is always better than cookie, from JavaScript perspective.

Vojtech


----- Original Message -----
From: "Michael Pasternak" <mpastern at redhat.com>
To: "Oved Ourfalli" <ovedo at redhat.com>
Cc: "Vojtech Szocs" <vszocs at redhat.com>, "engine-devel" <engine-devel at ovirt.org>, "Juan Hernandez" <jhernand at redhat.com>
Sent: Wednesday, April 17, 2013 11:56:43 AM
Subject: Re: [Engine-devel] Proposal to make REST API more webapp-friendly


Hi Vojtech/Oved,

On 04/17/2013 12:13 PM, Oved Ourfalli wrote:
> 
> 
> ----- Original Message -----
>> From: "Vojtech Szocs" <vszocs at redhat.com>
>> To: "engine-devel" <engine-devel at ovirt.org>
>> Sent: Monday, April 15, 2013 2:04:24 PM
>> Subject: [Engine-devel] Proposal to make REST API more webapp-friendly
>>
>> Hi guys,
>>
>> having worked with Engine REST API from web application (JavaScript)
>> perspective, there are things that could be improved to make REST API more
>> webapp-friendly.
>>
>> First of all, webapps are *not* traditional HTTP clients, i.e. they have
>> *not* full control over HTTP processing. There are some standard conventions
>> and behaviors built into web browsers that any REST API implementation
>> should be aware of.
>>
>> --
>>
>> (1) Don't force clients to use cookies for transmitting authentication
>> information! (or don't use cookies at all)
>>
>> Good explanation can be found at
>> [http://www.berenddeboer.net/rest/cookies.html]. Cookies have many
>> disadvantages:
>>
>> * cookie parsing/formatting is not trivial
>>   --> extra complexity imposed on REST clients

i wouldn't call it a cookie blocker, as in most cases (including ours) cookie contains
restricted amount of records.

>>
>> * in addition to Same-Origin Policy
>> [http://en.wikipedia.org/wiki/Same_origin_policy], cookies can be get/set
>> *only* for the given path
>>   --> JavaScript running at [http://example.com/webapp] *cannot* get/set
>>   cookies from requests at [http://example.com/restapi]
>>
>> * cookies are the primary source of Cross-Site Request Forgery
>> [http://en.wikipedia.org/wiki/Cross-site_request_forgery] attacks
>>   --> malicious websites/scripts can forge requests to REST API that will
>>   include the cookie, compromising user session

same true for the authorization header, session being passed via HTTP headers

>>
>> Alternative: clients could be given the *option* to use regular HTTP header
>> for transmitting authentication information.
>>
>> For example, webapp could read such (sensitive information) header, store it
>> securely via HTML5 Session Storage
>> [http://en.wikipedia.org/wiki/Web_storage] and implement related HTTP
>> processing on its own, e.g. pass this header for all authenticated requests
>> (instead of pushing this responsibility to browser).
>>
> 
> Option #1:
> We currently return the JSESSIONID also using HTTP headers. We currently return the jsession id also as part of the response HTTP headers, but the client still needs to pass a cookie with the appropriate value in order for the REST session to work. Isn't that enough to cope with this issue?

api, can consume JSESSIONID from the header indeed, but my problem with this approach
is a persistence of the http headers in browsers.

> 
> If not, then we might be able to do option #2:
> Today, we keep the engine session ID on the HTTP session attributes.
> So, we can support either passing the cookie with the JSESSIONID (taking the engine session ID from the http session), or passing the engine session ID as HTTP header (assuming we would also return the engine session ID upon first REST request).
> 
> This approach is problematic, as it might work well now, when the only attribute we use is the engine session ID, but in the future that might not be the case.
> If it is important enough (i.e., you can't really work with option #1) , then we can make a decision to save the attributes on the engine session, rather than on the HTTP session.
> So, we would start by supporting them both together, adding new attributes only to the engine session, and in the future deprecating the use of cookies, and only supporting HTTP headers.
> 
> cc-ed Juan and Michael, as they might have some input on that.
> 
> 
>> --
>>
>> (2) Straight-forward HTTP Basic Auth has some drawbacks!
>>
>> HTTP Basic Auth [http://en.wikipedia.org/wiki/Basic_access_authentication]
>> over (non-secure) HTTP connection means sending user credentials
>> (username/password/domain) in easy-to-decode cleartext, i.e. the value is
>> *not* encrypted or hashed in any way. Using secure lower-level protocol
>> (SSL) fixes the consequence, rather than the root cause of the
>> confidentiality issue.

same is true for any sensitive date being passed via plain text (including cookies)

>>
>> Furthermore, browsers typically remember HTTP Basic Auth information (either
>> via browser-specific popup, or via XmlHttpRequest) until the browser window
>> is closed. This means the webapp has no control over HTTP Basic Auth header
>> after it has been set! This is the reason why it's hard to implement
>> "logout" functionality in webapps when using HTTP Basic Auth.

right, that is my concern of using headers as well, better solution may be sending
JSESSION id via URI matrix parameter, e.g /api/vms;sessionid=xxx

>>
>> Last but not least, HTTP Basic Auth is vulnerable to Replay attacks
>> [http://en.wikipedia.org/wiki/Replay_attack]. Someone between client and
>> server can intercept requests and replay them, compromising user session.
>>
>> Alternative: clients could be given the *option* to use more advanced
>> authentication scheme.
>>
>> I've just read an excellent article at
>> [http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/]
>> which describes easy yet secure authentication scheme inspired by Amazon Web
>> Services REST API authentication
>> [http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html].
>> The idea is simple: collect auth information, hash (sign) it with a private
>> key, and send everything to server. To guard against Replay attacks, just
>> provide some timestamp to enforce request expiry after some time (say, 5-15
>> minutes). Easy and simple!

1. this concept has very same drawbacks as any other content encryption
2. decoding time stamp from request/s will produce fair load for the server as well
and won't protect the server against DDOS, also it shouldn't as it's not api/webapp
prerogative.

in general what Vojtech is trying to achieve is passing session via some other
container than cookie as webapp/browsers can't omit auth. header in runtime,
what is only justifying my resistance of passing session id via http header,
i think using matrix parameter (as mentioned above) may give you a decent solution.

>>
>> --
>>
>> (3) Support JSON for resource representations!
>>
>> I think this is pretty much obvious. XML has no real advantages over JSON.
>> JSON, on the other hand, has good support in webapps (JavaScript) and maps
>> directly to common data structures (i.e. string, number, boolean, and so
>> on).
>>
>> From webapp perspective, it's much easier and natural to use JSON than to
>> parse/format XML documents.
>>
>> Alternative: clients could be given the *option* to use JSON, in addition to
>> XML representation.

not sure how it's related, but we plan supporting JSON in future.

>>
>> --
>>
>> Vojtech
>> _______________________________________________
>> Engine-devel mailing list
>> Engine-devel at ovirt.org
>> http://lists.ovirt.org/mailman/listinfo/engine-devel
>>


-- 

Michael Pasternak
RedHat, ENG-Virtualization R&D



More information about the Devel mailing list