1

I need to implement a number of web pages for resetting an API access key:

  • user must be logged in first
  • user gets to "confirmation" page that has a "confirmation" link with a time token inserted
  • user follows a "confirmation" link
  • server gets the token from the followed link and decides whether it's fresh enough (say at most five minutes fresh is considered good)
  • if the token is fresh enough the server resets the API access key, otherwise it refuses to do so and asks the user to go back and obtain a link with a new token

This is intended to prevent users from accidentally reusing the link and resetting API keys unintentionally.

So the problem is the time token. The easiest way it to just get server local time and insert it into the hyperlink. Time represented as number of "ticks" (similar to Unix time) is just fine. This discloses the server local time to the user because the user needs to have a hyperlink before he can follow it.

Maybe it's no good to disclose local time to the user - maybe it facilitates some clever attacks against the server.

Does disclosing server time introduce any extra security risks?

Anders
  • 64,406
  • 24
  • 178
  • 215
sharptooth
  • 2,161
  • 1
  • 19
  • 22
  • Does this link is saved somewhere to check if it exists ? Or if I type myself an URL that match to the format it will work ? – Walfrat Nov 18 '16 at 09:02
  • @Walfrat Sure it will work, you just have to pass proper cookie values with the request (which is what any browser does). – sharptooth Nov 18 '16 at 09:24
  • You say 'similar' to Unix time; _actual_ Unix time, and C time (which is broader than Unix), and Java time, is UTC (perhaps excepting leapseconds) not local. – dave_thompson_085 Nov 19 '16 at 05:12

5 Answers5

1

I cannot see how disclosing the server localtime could help in attacks. I assume that most production server use synchronization so their UTC time is accurate and is the same on any server.

More for me the notion of localtime in only local to one environment: different processes on the same server could use different local times. At most it could help an attacker to locate where the server could be on the planet. But even this information has a limited value because in some large organization the servers and applications internally run on UTC time to allow easy backups between servers on different continents.

Serge Ballesta
  • 25,636
  • 4
  • 42
  • 84
0

Note : I assume here that resetting the password is an operation that can be done without being logged on the site.

If I type myself an URL that match to the format it will work ? Sure it will work, you just have to pass proper cookie values with the request (which is what any browser does).

You have a problem, this means that if myself I use this to check how your format your URL, and then I change my id to match to another user, and update the time part to be in the 5mn windows I'm likely able to reset everyone's password.

How to handle this ? Consider the following format <userID>|<time> that we encode in 64 bit to be sure to noat have trouble with browsers.

This format is really simple to crack, however it is not hard to improve the security :

  1. each time you generate a token, save it in database
  2. each time you check a token, check if it exits in database, if it has not expired, accept the request.
  3. Add a little scheduler that will delete every token that last for more than 5mn.

If you want to increase even more : use a different user when you write data (insert/delete) in the table of the tokens and remove insert/update/delete write to the main user who handle the rest of the application. So if you have somewhere a SQL injection flaw, as long it's localized using the other user account, he won't be able to touch that table.

Walfrat
  • 406
  • 2
  • 12
  • I phrased my question such that you focused on the secret reset, that's mostly my fault. The question is about showing the time token only. I rephrased the question. – sharptooth Nov 18 '16 at 09:41
  • @sharptooth well when it's about security, everything as to be taken into account, I don't see any risk of showing server's time as long you protect the "token" generated by the server however I'm no security expert. – Walfrat Nov 18 '16 at 09:43
  • There's no other token rather than the current time in the scheme I describe. The time is there only to prevent the user from rerunning the request accidentally. – sharptooth Nov 18 '16 at 09:46
  • Then as I said, what prevent me from modifying a request and use another user id ? As I stated, using the time without considering the rest is not a security risk. But how you use it now, you definitively seems to have a big flaw that I can exploit easily. – Walfrat Nov 18 '16 at 09:48
  • You cannot use another user id because the user id is deduced from encrypted "forms authentication" cookie which is sent with every request. Until you have someone else's cookie you cannot impersonate as them. – sharptooth Nov 18 '16 at 11:05
  • @sharptooth ok, I have though of a classic email to reset password which don't imply cookie. – Walfrat Nov 18 '16 at 11:58
0

I seem to be interpreting the question with a few nuances. I'll list them as I understand them:

  • The focus is only on the time token. Is there a security risk? - Shooting from the hip, I'd say ensure there are no patterns in tokens. If I'm the attacker and the token is a combination of a few static pieces (or predictable randomness) and the time token, I'd be able to predict the tokens. Burp, for example, lets me sample a bunch of tokens and predict new ones.
  • The focus is on synchronization with the server - leave out the time token altogether. Store the entire token on the server side when generating, and then check against this when the user submits this token for freshness, validity etc (along the lines of Walfrat's answer)

Personally, I always believe the bad guy is always two steps ahead of me. I try to give as little information about my application ecosystem as possible.

katrix
  • 533
  • 2
  • 13
0

I don't see a problem with the attacker being able to tell your server's clock's time from your use of timestamps in reset URLs, because if:

  1. Your server is reasonably synchronized to official time (as it should!);
  2. The attacker can observe some of your server's actions or interact with it;
  3. The attacker has some knowledge about how your server works (which you should pessimistically assume);

...then I would assume the attacker can guess what events happened on your server and reasonably estimate at what time they did.

What I'd give some more thought to is whether an attacker can profitably forge reset URLs. As you describe your system, such a forgery would be all but trivial. So I'd give some thought to what attacks this might enable—e.g., an attacker might be able to send a forged emails to your users with valid API reset links. Maybe not the biggest problem in the world, though.


In any case, if forgeries are a problem one solution would be to incorporate a message authentication code into the API key reset URLs. The most popular is HMAC; you'd do something like this:

  1. Each server that generates reset URLs and responds to the requests generates a random secret key. Ideally an ephemeral one—one that lives only in memory and never is saved to disk.
    • Alternative: if the client API key is a cryptographically generated shared secret, use a MAC key derived from it. A suitable derivation function would be HMAC(api_key, "URL authentication subkey"), where the string "URL authentication subkey" is an "information string" describing the use of the derived key—the literal string "URL authentication subkey" is a good choice.
  2. When you generate a password reset URL, you compute a MAC with that secret key over a delimited string that contains these fields:
    • URL protocol, hostname and path;
    • Username, timestamp and any other URL parameters.
  3. Put the MAC result into the URL as an additional parameter.
  4. In the handler that responds to the reset URLS, recompute the MAC using the secret key and the request URL, and verify that it matches the MAC that the client sent. Make sure to compare the MAC values with constant-time equality comparison!

Note that this sort of URL authenticity check has nothing to do with timestamps in particular, so it is something that you could conceivably want to use generically to prevent other attacks.

Luis Casillas
  • 10,181
  • 2
  • 27
  • 42
0

There has been (and probably still are) some people who wrote code to generate a random token using time as the seed of their random generator. That is where knowing the time of your server can allow a hacker to guess such a token. (i.e. the token is based on a specific time and thus a hacker can "guess" the token by testing with the tokens that the function would generate between the time you accessed the server and the time you received a response, it's certainly pretty limited and thus possible to get the token.)

However, the process that you are describing is not worked on that way at all.

  1. Create a random token (for example, use OpenSSL RAND_bytes() or an equivalent, just do not use a timestamp in any way to do that part).
  2. Save that token and the date when it is generated in your database.
  3. Send an email to your user with the URL and the token.
  4. When the user accesses your server again, check that the token exists in the database and then use the date there and make sure now < date + 5min..
  5. Delete the token, so it cannot be reused more than once.

This means your database will be filled up with tokens that no one ever used unless you also add a CRON process that scans it and deletes old entries. In SQL it would be something like this (check your SQL docs to make sure):

DELETE FROM tokens WHERE date < NOW() + '5min.'

In what you described, you would put the timestamp along the token which means that when it comes back, I can put any timestamp I'd like and that means I can make the token last as long as I want. This is called tainted data. In security, you have to think of data sent to your by the client as always tempered with...

Alexis Wilke
  • 862
  • 5
  • 19