This OWASP document suggests that API keys for REST APIs should be passed as a POST parameter or a cookie. Not a GET parameter, because they can appear in the server logs.
Elsewhere they suggest that the right HTTP verb be used. Writes already have to be a POST request, so maybe read-only calls should still be a GET request (it makes the intent clearer).
As a GET or a POST parameter, the API key will still need to be accessible to client-side JS (assuming that's what your frontend app is written in). It may therefore be vulnerable to XSS.
A cookie can have the HttpOnly flag set so that on any modern browser it will not be accessible to client-side JS (and therefore safer against XSS). It will still be passed back to the server with each request. To set such a cookie, the frontend and backend probably need to be within the same domain.
In CRM_Utils_REST (as of 4.4 at least), the api_key is retrieved from $_REQUEST, which includes $_GET and $_POST. It used to include $_COOKIE (which would enable cookies to be used for the API key), but that is no longer the default in PHP due to other security concerns.
Is there any accepted best practice for treatment of CiviCRM REST API keys at the client side?