views:

696

answers:

3

When a user signs up in our Struts application, we want to send them an email that includes a link to a different page. The link needs to include a unique identifier in its query string so the destination page can identify the user and react accordingly.

To improve the security of this system, I'd like to first encrypt the query string containing the identifier and second set the link to expire--after it's been used and/or after a few days.

What Java technologies/methods would you suggest I use to do this?

+2  A: 

For the first part have a look at http://stackoverflow.com/questions/599535/generating-private-unique-secure-urls. For the expiration, you simply need to store the unique key creation timestamp in the database and only allow your action to execute when for example now-keyCreatedAt<3 days. Another way is to have a cron or Quartz job periodically delete those rows which evaluate true for "now-keyCreatedAt<3 days".

cherouvim
+4  A: 

I'm going to make some assumptions about your concerns:

  1. A user should not be able to guess another user's URL.
  2. Once used, a URL should not be reusable (avoiding session replay attacks.)
  3. Whether used or not, a URL shouldn't live forever, thus avoiding brute-force probing.

Here's how I'd do it.

  • Keep the user's ID and the expiration timestamp in a table.
  • Concatenate these into a string, then make an SHA-1 hash out of it.
  • Generate a URL using the SHA-1 hash value. Map all such URLs to a servlet that will do the validation.
  • When someone sends you a request for a page with the hash, use it to look up the user and expiration.
  • After the user has done whatever the landing page is supposed to do, mark the row in the database as "used".
  • Run a job every day to purge rows that are either used or past their expiration date.
mtnygard
This is a good approach. I would just choose a random 128-bit identifier, however, rather than hashing. Its simpler and just as secure, if not more so.
erickson
I agree. No need for the hash. If it's random the only way to reverse-engineer the key is via the database table.
banjollity
mtnygard
A: 

I think you can do this in a stateless way, ie without the database table others are suggesting.

  • As mtnygard suggests, make a SHA-1 hash of the URL parameters AND a secret salt string.
  • Add the hash value as a required parameter on the URL.
  • Send the URL in the email.

When the user click on the URL:

  • Verify the integrity of the URL by calculating the hash again, and comparing the calculated value to the one on the URL.

As long as you never divulge your secrete salt string, no one will be able to forge requests to the system. However, unlike the other proposals, this one does not prevent replaying an old URL. That may or may not be desirable, depending on your situation.

Chase Seibert