We have a situation where a user's identity can be verified as follows: the network provider knows the identity of the user and injects secure headers into the HTTP request, which our servers can use to authenticate the user.
We're writing client-server applications and want to use this mechanism to automatically authenticate the user. We can't use HTTPS end-to-end for the authentication request because obviously the network couldn't inject headers in that case.
EDIT: roughly equivalent setup:
(client <-VPN-> HTTP proxy) <-internet-> our server
Assume the VPN (bold section) is secure and the user is authenticated within in the VPN.
The client generates a HTTP request. A proxy within the network knows the client's identity and generates a token which is automatically added to the headers in the proxied HTTP request. All of this happens in a secure domain and cannot therefore be compromised. (Unfortunately we can't change anything in the VPN setup, such as have the proxy make a HTTPS request instead.)
Our server can query back to the network (securely) to determine the identity of the client who initiated the request.
Assumptions:
- This HTTP requirement is a given and can't be changed.
- An attacker can't fool the identity verification process by presenting fake headers.
- An attacker might be able to otherwise intercept/compromise the HTTP request/response.
- Server is stateless (so no storing one-time keys server-side).
- Storing a private key in the client application is not an option as it could be compromised
- The HTTP request/response will be used auto-authenticate the user, but all other interactions before (if necessary) and afterward will be over HTTPS.
Here's what we've tried so far:
- Client fetches a public key
PK
from server over HTTPS - Client generates a symmetric key
SK
- Client encrypts
SK
usingPK
, and sends this to server over HTTP - Server verifies user's identity and generates authentication token
AT
- Server encrypts
AT
usingSK
->E(AT,SK)
- Server signs
E(AT,SK)
using its private key and sends to client - Client uses
PK
to verify signature - Client uses
SK
to decryptE(AT,SK)
givingAT
- Client uses
AT
to authenticate all subsequent HTTPS traffic.
(And we should probably use separate key pairs for encryption and signing, but let's ignore that for now).
As far as I can see, this is secure against eavesdroppers (as they won't have SK
) but if a malicious attacker can modify the HTTP request, there is nothing stopping them from generating their own symmetric key instead of SK
, encrypting it with PK
, replacing the request payload with that and the server will have no idea that it's not talking to the real client. The server will then happily encrypt a valid AT
and send it back to the attacker who can then proceed with impunity.
Is there a way to shore up this hole? Is it even possible to do this with a stateless server?
EDIT: if the server can detect tampering and abort the authentication process, that would be sufficient. "This is not possible because X" is also a valid answer, if it can be demonstrated.