0

I'm hosting a certain resource on a website and would like to grant permission to download it only to specific users.

However, I'd rather not have an authentication page, but simply prompt for a username and password (that I'll send to users upon previous request) upon the click of a download button.

This link exemplifies perfectly what I'm trying to obtain.

All the documentation I found suggests the above is not possible, or requires to write a routine for login on the website (which I don't care about since authentication should be only for the download):

How can I obtain the effect of the link I posted above?

I think the structure of the client code should look something like this but can't fill in the gaps:

Client (PSEUDO-CODE):

<a class="btn btn-large btn-primary" type="button" onclick="Download_funct()">
    <b>Click to download</b>
</a>

<script>
    function Download_funct() {

        // how to do this thing below is what I'm asking basically.
        username, pass = prompt("Insert Username and Pass");

        authenticated = $.ajax( here is my request to server with username and pass);

        if (authenticated == 1) {
            download;
        } else {
           alert("Wrong User / Pass. If you don't have login credentials send me an email to have them.");
        }
    }
</script>
Community
  • 1
  • 1
Matteo
  • 7,924
  • 24
  • 84
  • 129
  • In my opinion i think i'd be best if the server pushes the file according to the username/pass the user provides. If you have multiple files simple push one more variable with the AJAX request containing the file name – LefterisL Nov 29 '15 at 23:13
  • Create a div with a field for username and password, and hide that. Then show it when the user clicks the download button. Your div can also contain a button with more code etc, providing a link if the credentials are good. But ALL CHECKING should be done server-side! – Herbert Van-Vliet Nov 29 '15 at 23:14
  • @HerbertVan-Vliet - Yeah I agree checking should be server-side, that is why the result of the `ajax` request is the authenticated variable. Is there no way to do it without me hiding a `div` but just using javascript prompt? – Matteo Nov 29 '15 at 23:26
  • Well... we usually use the "username+password" access check so passwords can change. But only those TOGETHER give access. You don't HAVE to use those two just because everyone else does; instead you could go for ONLY the access code - which would mean one field. But if you use a js-prompt the value will show on the screen. – Herbert Van-Vliet Nov 30 '15 at 10:39
  • @HerbertVan-Vliet - I've been following your idea of having a hidden div and showing it to ask for authentication. However I noticed that if a web user is smart enough he could just look at the source code and bypass all my authentication procedure by simply calling the download function directly from the console. Is there a solution to this? – Matteo Nov 30 '15 at 17:01
  • Of course. Send the username and password to a server script. If the script decides it's all good, let the script serve the file. Check http://php.net/manual/en/function.readfile.php – Herbert Van-Vliet Dec 01 '15 at 20:09

2 Answers2

2

The link that you gave probably uses htaccess authentication.

You could place all downloadable files in a separate server directory and as soon as someone wants to access files from there, an authentication dialog would pop up exactly like on the example you gave.

(Edit: This is a server configuration, no javascript programming on the website itself.)

grandchild
  • 1,157
  • 15
  • 20
  • I see, thanks for the response. What if I'm not running `apache`? My server is currently running flask and python. Is there something equivalent to that? – Matteo Nov 29 '15 at 23:28
  • Flask is a framework, not really a webserver. So either you're running the included development webserver in production (not really a good idea, but it might be okay for your case, I don't know enough about it) and you could have a look at this: http://flask.pocoo.org/snippets/8/. Or you should find out what webserver your server is actually running and then google further. If you don't know your webserver, load your page in a browser, hit F12 and have a look at the network tab, in any resources' headers it should tell you what the server says it's running.. – grandchild Nov 30 '15 at 15:37
1

After a day of research I'm able to answer my own question, with all the details and nuances related to it.

Premise:

First of all I should address the confusion I had on the difference between using htaccess or javascript for authentication.

  • .htaccess authentication is server side, based on Apache Web Server.
  • javascript authentication is client side so you cannot use it to prevent the user from accessing the files.

Quoting from .htaccess deny all except allow javascript access as well:

If javascript can access the files, the client can too.

So the short answer to my question is that you cannot obtain the result shown here with client side scripting.

Solution using .htaccess:

The link posted in the question - as @grandchild pointed out - uses .htaccess authentication. From the Apache Tutorial Web Page:

.htaccess files (or "distributed configuration files") provide a way to make configuration changes on a per-directory basis. A file, containing one or more configuration directives, is placed in a particular document directory, and the directives apply to that directory, and all subdirectories thereof.

This means that using an .htaccess configuration file, you can decide (on a directory basis) whether or not to grant clients the permission to access all the files in the directory containing the .htaccess configuration file. Note: you could also use a finer level of detail, but explaining it becomes out of topic.

Below is a code snippet of the .htaccess file to put in the directory on your server that you want to protect from direct access:

AuthUserFile /home/user_name/htaccess/.htpasswd <- path to password file
AuthGroupFile /dev/null
AuthName "This will appear in the prompt to client"
AuthType Basic

<Limit GET>
require valid-user
</Limit>

At the path indicated above you put the following .htpasswd file:

test_user:$a23Tl82g5/yW9$fY84d0PkzV.WNF9w$%d-90

where each line represents a valid username:passwd pair, and the password is generated using the MD5 algorithm. Link to a website you can use to obtain the above.

PHP Solution

The comment from @Herbert Van-Vliet is correct but incomplete:

Create a div with a field for username and password, and hide that. Then show it when the user clicks the download button. Your div can also contain a button with more code etc, providing a link if the credentials are good. But ALL CHECKING should be done server-side!

It's true that you can do what suggested but that will obtain fake security unless you make sure that the resources are not downloadable directly, and this is independent of the authentication procedure.

The correct way of approaching this solution is explained in Block direct access to a file over http but allow php script access.

Which is:

  1. Put the files you want kept to yourself outside of the web root directory.

  2. To still prevent HTTP requests to the files, add a .htaccess file that blocks all communication.

For example:

Order deny,allow
Deny from all
  1. Setup a PHP script (not javascript) that will authenticate the user. Your web server, and therefore your server side language, will still be able to read them because the directory's local permissions (regardless of the .htaccess permissions) allow the web server to read and execute the files.
Community
  • 1
  • 1
Matteo
  • 7,924
  • 24
  • 84
  • 129