Jump to content

Recommended Posts

I have an application where the user can upload and download files.  To do either, the user needs to be logged on with their username credentials.  For downloads, I include a link such as the following, and use PHP to first authenticate and then use either PHP's readfile() or Apache's X-Sendfile to download.

<a target="_blank" href="index.php?task=dispDoc&id=516789792">myfile.xlsx</a>

Now, I have a certain page where I display the user's deleted documents.  The documents are not really deleted, but just have deleted status as stored in the database.  For these, I could easily include a link such as the following, and make displayDeletedDoc do what needs to be done.

<a target="_blank" href="index.php?task=dispDeletedDoc&id=516789792">myfile.xlsx</a>

The problem with approach is I don't want them to be able to be downloaded from anywhere but this single page.  Any recommendations?

Link to comment
https://forums.phpfreaks.com/topic/295230-single-use-file-download-links/
Share on other sites

On your download page check for the $_SERVER['HTTP_REFERER'] and see if it matches your site and the deleted documents page name, otherwise redirect them. The referer is spoofable though, so anyone that is smart enough to try it could potentially download the file from elsewhere.

 

Another idea that came to mind, generate random ids in the users session data that maps to the real id, regenerate those ID's on every page refresh. That way they would need the latest ID's, the modified referer and could only grab it once since the other ID's would be regenerated again. This could cause headaches for legitimate people.

Edited by iarp

Page is displayed in one window, user opens another page in another window, and then clicks link on first page?

That's one possibility that would cause issues if you're constantly re-generating the random ID's. There are plenty of other ways someone might end up with an invalid ID without realizing why (or even being the cause).

 

For example if someone were downloading using a download manager, there may be two requests for the file: One by the browser which is aborted when it determines the content to be a download, and another later by the download manager.

 

If the browser or an extension uses pre-fetching, it may start requesting other pages on your site in the background in order to speed up the user's browsing experience (chrome will do this if you ask it to). Each of these requests would re-generate the ID's and result in invalid links.

 

The least troublesome method is to generate the IDs as needed, and time-limit them rather than usage-limit them. You could generate the tokens when creating the link, or when they initially request the download, either way. For example:

 

Create the initial link with the actual database ID or something else that doesn't change. Link to some intermediate file rather than directly to the download link

<a target="_blank" href="retrieveFile.php?id=516789792">myfile.xlsx</a>
In retrieveFile.php generate the random token and store it in the session along with the initial request time and file ID. Redirect to another file with the token.

$token = generateRandomToken();
$_SESSION['downloadTokens'][$token] = array(
   'initiated' => time()
   , 'id' => $_GET['id']
);

header('Location: download.php?token='.$token);
Verify the token and download the file.

define('GRACE_TIME', 3600); //Token is valid for an hour, adjust as desired.

$details = isset($_SESSION['downloadTokens'][$_GET['token']])?$_SESSION['downloadTokens'][$_GET['token']]:null;
if (!$details || time()-$details['initiated'] > GRACE_TIME){
    header('HTTP/1.0 404 Not Found');
    header('Status: 404');
    echo 'Token not valid.';
    exit;
}

//download the file.

For example if someone were downloading using a download manager, there may be two requests for the file: One by the browser which is aborted when it determines the content to be a download, and another later by the download manager.

 

If the browser or an extension uses pre-fetching, it may start requesting other pages on your site in the background in order to speed up the user's browsing experience (chrome will do this if you ask it to). Each of these requests would re-generate the ID's and result in invalid links.

 

I didn't even contemplate those scenarios.  Thank you for pointing them out.  I haven't yet reviewed your solution in detail, however, the concept makes sense.  I will spend some time and post addition questions if needed.

 

On a side note, I see how you assigned "_blank"  as the target attribute for the download file link.  I've been pondering doing so for a while, and recently updated my code to do so.  I, however, experienced some negative results when the links were presented in a JavaScript generated dialog, and reverted to not doing so.  The only reason I bring it up is that I will post a more on-target new thread on this subject and hope to get your advise (however, if you have some immediate advice, please don't hesitate to voice it!).

 

Thanks again

Edited by NotionCommotion

On a side note, I see how you assigned "_blank"  as the target attribute for the download file link.

I just copy/pasted your link from the original post and edited the href value.

 

I generally do not add a target to any of my links. For items I think should be in a popup I'll just give them a class="popup" or similar and have a bit of jQuery that attaches to it and opens it into a new window. Otherwise it's up to the end-user to open it in a new tab/window if they want too using their browser.

Thanks Kicken.  You saved me a new post!

I read (http://www.searchenginejournal.com/when-not-to-use-target_blank-link-attribute/19924/) how when downloading pdf/etc files, the target could improve the ux.
 

The cases when the attribute can (and is encouraged to) be used are the following:

to link to a PDF document mostly because when it’s first followed there’s often a delay while the browser loads up the plugin and PDF (and thus you can let the visitor read more information on the current page while the document loads).


Caused issues for some circumstances, so not sure it was good advise and don't plan on following.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.