Question:
We usually store the session id in the browser's cockie. But let's say I want to use my API in ios / android mobile applications, and I'm going to store a cookie in the application's memory and then insert it into each request from the application. But how right is this? Are there any tips on this?
Answer:
But how right is this?
There is simply no other approach. You somehow need to identify the user of the API. By any indirect signs, you cannot identify it – several consumers can sit on one IP, there is no User-Agent in principle, and in general it is just a spoofed header and nothing more.
Therefore, you need to pass some identifier with each request that can help you find the user. There are a few subtle points here:
- It should not be the user ID itself (otherwise the whole mechanism breaks through the hijacking of the ID, and nothing can be done with the hijacked user except to kill him)
- This identifier (or the mechanism associated with it) must unambiguously confirm the correctness of the session or be transmitted exclusively over a secure channel (HTTPS), otherwise it can be stolen in exactly the same way and presented as an incorrect user.
- Identifiers should be considered a consumable item in the application: they can always be bang and new ones can be created so that any stolen identifier can be reset immediately after the theft is detected
The common approach is to pass the access token in an arbitrary header ( github , google , amazon s3 ). One way or another, the information for authentication always remains in the headers (it has no place in the query parameters and directly in the request body), so there really isn’t much choice here either. The token is stored on the device, in case of panic, the user deletes the token (using the same access token)
The last paragraph is about confirmation of the correctness of the session, transmitted over an insecure channel.
If there are concerns about the interception of the token during its transfer, it is necessary to somehow sign outgoing requests. To do this, you can use full or lightweight challenge-response authentication, the meaning of which can be reduced to the fact that the server and client ask each other riddles that only they themselves can solve. In the simplest version, the server can issue a token consisting of an identifier and a secret part (encryption key), which is transmitted once to the client when the token is created (the client can also send some secret, but we believe that the server can always be trusted). After that, all messages from the client to the server are either completely encrypted with the received key, or contain in an additional header a signature generated based on the key and the request body, which an attacker cannot fake without stealing the secret key. This, however, does not in itself protect against:
- Replay attacks (eg if the user sends a request to "delete the last entry", then an attacker can generate another hundred such requests and completely clear the user's history). The simplest solution is juggling timestamps (eg don't accept requests older than 5 seconds), but shoots in the leg at the slightest timing issue.
- Physical withdrawal of the key from the client. It is generally believed that this cannot be defended against, and this point is simply ignored.
- Interception of the key at the time of issuing the token (therefore, it is better to get HTTPS after all). With open traffic, you can use the Diffie-Hellman algorithm and analogues, but it will take more time than writing the application itself.
- Key calculation when using an incorrect algorithm (eg if there is no key rotation and if the attacker knows that JSON is always used, then he, knowing that the last character is always
}
or]
, can calculate the key by comparing requests of different lengths). Again, it’s easier to take HTTPS, there are alternative methods, but I won’t tell them so as not to inadvertently miss an important point.
upd. there is a certain standard json web token , I myself have not read it yet.