Generating Private, Unique, Secure URLs

2020-05-18 03:34发布

问题:

I'd like to generate a secure one-click-access type of url similar to the examples below. I'll be using PHP but that is irrelevant as I'm just looking to understand the underlying concept. Some answers suggest using a GUID, but I don't think that will give me an absolutely unique, secure URL like below.

#    Google Calendar
3qq6jlu04ptlhmb9fencsu5t2k
#    Private
3qq6jlu04ptlhmb9fencsu5t2k
#    Private 'token'
163a0afe7fkb1ba2acd04c11ef0eefe8
#    LogMeIn
#    1024 bit - 128 Character URL
72oxuj0fzefqo3fu04xjtvmd0adj2948rfh7g5by4forkwcy7t651z7hcb6kjjgqkxmvmfqpyrcfy15z1fto8ewcxstjc6avicag7d5qnoimsm19kb9kgi9i7v6z01d5

I'm leaning toward that 128 character, 1024 bit style, as it seems very secure. I guess I could make four MD5 hashes and merge them, but is that really effective?

I have two specific intentions for a url such as this, but I'm sure there are others who may find this useful.

1) Instant log in shortcut/icon for users

2) Single-use url (Password recovery links)

回答1:

Update:

For something like a single use URL, I'd go with the GUID-esque appoach that has been suggested. Make sure to have a short lifespan on the link.

For a instant log-in, there is no really secure way to have a single URL.

Yes you can generate a URL which is going to be damn near impossible to guess, but that doesn't give you super security. If you want to remember users, why not use an encrypted authentication cookie?

The example you give, Google Calendar doesn't log you in via the URL alone, you have to be authenticated first before the URL means anything.

E.g. clicking on google calendar from my gmail gives me:

https://www.google.com/calendar/render?tab=mc&gsessionid=-LTeHrnKoeAbDcVaN68NHA

That doesn't help you access my account unless you've first authenticated as me.

Old post:

You can generate a GUID in PHP using com_create _guid and use that.

On linux I think you can use uuid_create, or this code from here:

<?php
 function guid(){
 if (function_exists('com_create_guid')){
       return com_create_guid();
   }else{
       mt_srand((double)microtime()*10000);//optional for php 4.2.0 and up.
       $charid = strtoupper(md5(uniqid(rand(), true)));
       $hyphen = chr(45);// "-"
       $uuid = chr(123)// "{"
               .substr($charid, 0, 8).$hyphen
               .substr($charid, 8, 4).$hyphen
               .substr($charid,12, 4).$hyphen
               .substr($charid,16, 4).$hyphen
               .substr($charid,20,12)
               .chr(125);// "}"
       return $uuid;
   }
}
echo guid();
?>


回答2:

Try uniqid - and perhaps combine with an md5 hash, as given in the examples:

// no prefix
// works only in PHP 5 and later versions
$token = md5(uniqid());

// better, difficult to guess
$better_token = md5(uniqid(rand(), true));

I must note however that no urls generated in this way (whatever the hash algorithm) will be 'secure', simply very difficult to guess.



回答3:

Just generate a GUID. It is important though that is isn't an old-style sequential GUID though.

However it appears that php doesn't have its own GUID generating function. The com_create_guid function suggested in another answer appears to only be available in php when running on Windows.

There is a user suggested alternative for com_create_guid for non-Windows on the manual page for it:

function guid(){
    if (function_exists('com_create_guid')){
        return com_create_guid();
    }else{
        mt_srand((double)microtime()*10000);//optional for php 4.2.0 and up.
        $charid = strtoupper(md5(uniqid(rand(), true)));
        $hyphen = chr(45);// "-"
        $uuid = chr(123)// "{"
                .substr($charid, 0, 8).$hyphen
                .substr($charid, 8, 4).$hyphen
                .substr($charid,12, 4).$hyphen
                .substr($charid,16, 4).$hyphen
                .substr($charid,20,12)
                .chr(125);// "}"
        return $uuid;
    }
}

But I have to admit I'd be reluctant to use it for anything important in case there was an non obvious problem lurking in it that my non-cryptographically trained mind didn't spot.



回答4:

The id has to be impossible to guess, GUIDs are unique but are not that hard to guess.

You need a good random number generator, every cryptography/encryption library has at least one, I don't know PHP so I can't give you the function name.

Then you have to decide how long your random number will be, you should choose a length so big that anyone guessing a number will get an unassigned number - either:

  1. Estimate the number of unique URLs you will have to generate, calculate how many bits you need to represent them all and then double the number of bits (at least).

  2. Or, take the largest number your users will accept

Now you have a "secure" number you can just convert it to decimal, hex or base64 and use that string.



回答5:

If you want to ensure that the URL is both unique and can only be used a limited number of times:

  • Keep a small database with fields like: RandomKey, InternalURL, Counter, TimeStamp

  • Create a random number out of a large enough pool.
    Non Sequential GUIDs should be sufficient

  • Save it in your database as the RandomKey, along with the actual internal URL or resource code needed by your system to handle that URL and a time stamp.

  • When the user clicks or enters a URL, check it against that database: if the TimeStamp is too old or the Counter is too high, take appropriate action (for instance if you want this URL to be accessible for a limited time or a certain number of times).
    Otherwise, just treat the request using the InternalURL and send its result back to the user.

  • When the URL has been used or has reached its maximum use counter, then just delete it from the database so it can not be used any further.

This is great to give you one-time URLs that are practically impossible to guess.

Of course, you must also implement some security checks to limit the rate at which people can try to access an invalid URL.



回答6:

I would avoid this for:

1) Instant log in shortcut/icon for users

because these URLs can be cached/logged on proxies, weblogs, browser cache, bookmarks, emails etc.



回答7:

To trim additional curly braces

$guid = strtolower(trim(com_create_guid(), "{}")); (PHP 5 or later)



标签: php security url