Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 2 12 LastLast
Results 1 to 15 of 25
  1. #1
    New Coder
    Join Date
    Aug 2010
    Posts
    89
    Thanks
    3
    Thanked 0 Times in 0 Posts

    How to secure files on my public web server

    I have an application (flex with adobe air) that my customers are going to use to download image files from my server..

    At the moment the url's are stored in my public web root folder. the application navigates to the url and downloads the selected file.

    eg. http://someserver/images/image001.jpg

    What i would like to know is how to prevent my images being accessed by anyone who navigates to the above url, they could easily change the image to image002.jpg...

    What is the best way to serve files to my customers. Would it be better for a php script to handle the download and then pass that file to my application?

  • #2
    Regular Coder Stooshie's Avatar
    Join Date
    Mar 2008
    Location
    Dundee, Scotland
    Posts
    380
    Thanks
    9
    Thanked 39 Times in 39 Posts
    The best thing would be to store the files in a hidden, non-public folder somewhere on your server. Then write a web service in php that takes a request with an image id of some kind, verifies the user, copies the image file to a public folder and renames it to some random name (using a UUID is probably best) and then the web service returns the location of the new image file. You may need some cron job to sweep up images that were created more than, say, 15 minutes previous to the cron sweep.

    If you are not sure about writing web services in php, take a look at nusoap (http://sourceforge.net/projects/nusoap/) It's fairly simple. Also, flex/air can connect to web services fairly simply and most of the as code is auto-generated for you.
    Regards, Stooshie
    O

  • Users who have thanked Stooshie for this post:

    flexillu (01-13-2011)

  • #3
    Codeasaurus Rex
    Join Date
    Jun 2008
    Location
    Redmond, WA
    Posts
    659
    Thanks
    31
    Thanked 100 Times in 94 Posts
    There's a few ways you can do this with images. Options!

    WAY ONE (DENY ACCESS AND STREAM)

    One way is to do something similar to what Sooshie suggests, though instead of copying the file I would advise streaming it.

    First step would be setting up the method. What we're going to do is deny access, through apache, to certain types of files. So what we need is to turn the images you have from something like image.jpg into something like image.denyme.

    Next, we need to make sure that we still know what each file name is and what image we're dealing with so that it can later be downloaded. That's where the database comes in.

    You would want to set your database up having fields such as: ImageID, ImageFileName, ImageFileExtension, ImageOriginalFileName, ImageOriginalFileExtension, ImageFileSize, ImageMIMEType (The MIME Type will be used for sending a PHP header that tells the browser we're downloading a file).

    Next, let's deny access to those files. Create an .htaccess file in the root of your web directory (typically in public_html/ or www/) and include the following code (remember .denyme is the file extension we're using in this example, but that extension can be anything).

    Code:
    <Files ~ "\.denyme$">
    Order allow,deny
    Deny from all
    </Files>
    Lastly, you would implement the PHP to actually stream the file:

    Your code will want to look something similar to this:

    PHP Code:
    <?php

    // ASSUME $result IS A RETURNED ARRAY REPRESENTING YOUR DATABASE
    // QUERTY SELECTING THE FILE THE USER WANTS TO DOWNLOAD

    // Send Content information to tell browser we're downloading a file and of what size the file is
    header"Content-type: " $result['ImageMIMEType'] );
    header"Content-Disposition: attachment; filename=\"" $result['ImageOriginalFileName'] . "." $result['ImageOriginalFileExtension'] . "\"" );
    header"Content-length: " $result['ImageFileSize'] );

    // ALTERNATIVELY, IF YOU DIDN'T STORE ImageFileSize IN THE DATABASE YOU CAN USE:
    //header( "Content-length: " . filesize( "/path/to/images/" . $result['ImageFileName'] . "." . $result['ImageFileExtension'] ) );

    // In case the image is updated we don't want to cache the file
    header"Cache-control: private" );

    $fp fopen"/path/to/images/" $result['ImageFileName'] . "." $result['ImageFileExtension'], "r" );

    // While we haven't reach the end of the file, print 2048 bytes of data from the file
    while( !feof$fp ) ){
        
    $buffer fread$fp2048 );
        echo( 
    $buffer );
    }

    // Once we're done, close the file
    fclose$fp );

    ?>
    WAY TWO (STORE IMAGE DATA IN THE DATABASE)

    Depending on the size of your images, it may be more efficient (or convenient) to store your image data in the database.

    This way your file isn't accessible from the URL, because it doesn't actually exist in file form until you create it.

    First, set up a database so you can upload into it. Create fields, similar to before, ImageID, ImageOriginalFileName, ImageOriginalFileExtension, ImageMimeType, ImageCode.

    * Important: Set the ImageCode database type to "BLOB" *

    Now, we'll need to convert our images into the database. If you're using PhpMyAdmin you can upload into the BLOB element from directly in the "Insert Row" tab of panel.

    If you want to create your own, however, it will look something similar to this:

    PHP Code:
    <?php

    // Uploading our image, let's get to the point where $image represents an image that has been uploaded
    // For more information on this, Google File Uploads in PHP

    $imgCode chunk_splitbase64_encode$image ) );

    $database = new MySQLi"host""username""password""db_name" );

    // You can get the image data from the $image element using something like
    // getimagesize() [http://php.net/manual/en/function.getimagesize.php]
    $database->query"INSERT INTO `myImagesTable` ( `ImageOriginalFileName, `ImageOriginalFileExtension, `ImageCode` ) VALUES ( '" $imageOriginalFileName "', '" $imageOriginalFileExtension "', '" $imageMimeType "', '" $imgCode "' )" );

    ?>
    Now, as for outputting the image, it's easier than streaming this time around (if you want to just display it on a new page, that is). You can still choose to stream the file, if you wish.

    The easiest way is to simply do:

    PHP Code:
    <?php

    // We're assuming again that $result is a result array from a database query selecting the image's row

    header'Content-Type: ' $result['ImageMimeType'] );
    header"Content-Disposition: attachment; filename=\"" $result['ImageOriginalFileName'] . "." $result['ImageOriginalFileExtension'] . "\"" );

    echo( 
    base64_decode$result['ImageCode'] ) );

    ?>
    SIDE NOTE: DYNAMICALLY ZIPPING IN PHP

    If you are storing the images dynamically, you may want to look into generating ZIP files on the file (totally optional, just reduces download size). PHP has a very nifty API for that here: http://php.net/manual/en/book.zip.php.


    I hope this long post helps you! If you have any questions just let me know.
    Unless otherwise stated, any code posted is most likely untested and may contain syntax errors.
    My posts, comments, code, and suggestions reflect only my personal views.
    Web Portfolio and Code Snippets: http://shanechism.com

  • #4
    New Coder
    Join Date
    Aug 2010
    Posts
    89
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Thanks both for your replies.

    ShaneC..The images are now adobe illustrator files..".ai".

    Would your first method still work for these files?

    Also my flex app will be run in adobe air..not in a browser, so how would i send the file back to the app..the same way?
    Last edited by flexillu; 01-09-2011 at 05:14 PM. Reason: Typo

  • #5
    Codeasaurus Rex
    Join Date
    Jun 2008
    Location
    Redmond, WA
    Posts
    659
    Thanks
    31
    Thanked 100 Times in 94 Posts
    Yes, this method will work for any file type. However, having said that, you should not store very large files in your database.

    As for the Adobe Air question, honestly I haven't worked with that platform so I can't tell you if it will work or not. If, however, a direct file download will work then in theory this should work as well - since the downloads operate the same way.
    Unless otherwise stated, any code posted is most likely untested and may contain syntax errors.
    My posts, comments, code, and suggestions reflect only my personal views.
    Web Portfolio and Code Snippets: http://shanechism.com

  • #6
    Super Moderator Inigoesdr's Avatar
    Join Date
    Mar 2007
    Location
    Florida, USA
    Posts
    3,647
    Thanks
    2
    Thanked 406 Times in 398 Posts
    Quote Originally Posted by flexillu View Post
    Also my flex app will be run in adobe air..not in a browser, so how would i send the file back to the app..the same way?
    Yeah, you just need to open a URL request or use the URL as the source in your Image component. Keep in mind that you aren't preventing someone from accessing your images at all; just obfuscating where they are located. All they have to do is open up an HTTP proxy or packet sniffer and they will be able to see where the images are coming from. For that matter if you are only loading them in your AIR app there is no point in obfuscating them at all unless you are going to also require authentication to retrieve the file.

  • #7
    New Coder
    Join Date
    Aug 2010
    Posts
    89
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by Inigoesdr View Post
    Yeah, you just need to open a URL request or use the URL as the source in your Image component. Keep in mind that you aren't preventing someone from accessing your images at all; just obfuscating where they are located. All they have to do is open up an HTTP proxy or packet sniffer and they will be able to see where the images are coming from. For that matter if you are only loading them in your AIR app there is no point in obfuscating them at all unless you are going to also require authentication to retrieve the file.
    The files are of very high value, i understand that if someone really wants to get access to them they will find a way to do so. I am trying to prevent non techies deciding to download more than they are allowed.

    I'm a little confused now i thought Stooshies and ShaneC's method would prevent people finding them on my server and downloading them?

    I do need some kind of authentication for the retrieval of my files..so would this go in my php script? The users are required to log in to access the app, so could i also record who is downloading what?

  • #8
    Super Moderator Inigoesdr's Avatar
    Join Date
    Mar 2007
    Location
    Florida, USA
    Posts
    3,647
    Thanks
    2
    Thanked 406 Times in 398 Posts
    Quote Originally Posted by flexillu View Post
    I'm a little confused now i thought Stooshies and ShaneC's method would prevent people finding them on my server and downloading them?
    Only if you:
    Quote Originally Posted by Stooshie
    hen write a web service in php that takes a request with an image id of some kind, verifies the user
    Quote Originally Posted by flexillu View Post
    I do need some kind of authentication for the retrieval of my files..so would this go in my php script? The users are required to log in to access the app, so could i also record who is downloading what?
    Yes, you would handle the authentication in PHP. If you just want to prevent people from traversing your images directory, turn off indexing so they can't see what files are in it by going to /images/.
    Code:
    # In your .htaccess
    Options -Indexes

  • #9
    New Coder
    Join Date
    Aug 2010
    Posts
    89
    Thanks
    3
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by Inigoesdr View Post
    Yeah, you just need to open a URL request or use the URL as the source in your Image component.
    Can you give me any more details on this part. The files are .ai files.

    If i use the script above to output stream the file...

    what exactly do i have to do in the flex app


    at the moment i use a urlSteam to get the data bytes and write them to a new file and then append .ai onto it. Are you saying that i just need to URL request the php script tat ShanC provided?

  • #10
    Codeasaurus Rex
    Join Date
    Jun 2008
    Location
    Redmond, WA
    Posts
    659
    Thanks
    31
    Thanked 100 Times in 94 Posts
    The method I provided for downloading the files is coupled with the Apache .htaccess change. If you deny access to a certain file type, like I specified in my post, it will prevent users from accessing that file.

    The way you re-enable that access is by creating a PHP script, similar to the one I specified, which allows a user to download the script. Then, on that script, you institute whatever method you would like for authorizing a user to download the requested file.
    Unless otherwise stated, any code posted is most likely untested and may contain syntax errors.
    My posts, comments, code, and suggestions reflect only my personal views.
    Web Portfolio and Code Snippets: http://shanechism.com

  • #11
    Super Moderator Inigoesdr's Avatar
    Join Date
    Mar 2007
    Location
    Florida, USA
    Posts
    3,647
    Thanks
    2
    Thanked 406 Times in 398 Posts
    Quote Originally Posted by flexillu View Post
    Can you give me any more details on this part.
    No, because I have no idea how your application works in terms of displaying the image, authentication, etc. That is really a separate problem you should take to the Flex forum anyway.
    Quote Originally Posted by ShaneC View Post
    The method I provided for downloading the files is coupled with the Apache .htaccess change. If you deny access to a certain file type, like I specified in my post, it will prevent users from accessing that file.
    Changing the extensions of files is silly. Just stick them in a folder and deny access to that folder in the .htaccess:
    Code:
    order deny, allow
    deny from all
    Storing files in the database is also unnecessary and very inefficient.

  • #12
    Codeasaurus Rex
    Join Date
    Jun 2008
    Location
    Redmond, WA
    Posts
    659
    Thanks
    31
    Thanked 100 Times in 94 Posts
    Quote Originally Posted by Inigoesdr View Post
    No, because I have no idea how your application works in terms of displaying the image, authentication, etc. That is really a separate problem you should take to the Flex forum anyway.

    Changing the extensions of files is silly. Just stick them in a folder and deny access to that folder in the .htaccess:
    Code:
    order deny, allow
    deny from all
    Storing files in the database is also unnecessary and very inefficient.
    First and foremost my suggestion was to deny access to the files in some form or fashion, the example I gave is by denying by extension - denying by directory works as well.

    As for storing in the database, that was recommended based on the original request which was storing images, not AI files. Storing images in the database can be significantly more efficient as they can be accessed with O( log n ) efficiency, whereas if it is stored as a file you'll need an O( log n ) lookup for the file name in the database, plus an O( 1 ) access of the file. Obviously, though, if your files are large (which an AI file is likely to be), then putting them in a database isn't the best option.

    As to "changing the extensions of files is silly", I have to respectfully disagree. If you're storing the original filename and extension in the database (which you'll need to stream the file anyway), then your file could be called PurpleGiraffe.awesome - so long as it can be accessed you'll end up streaming it to the user with the original file name and extension.
    Last edited by ShaneC; 01-11-2011 at 07:54 PM.
    Unless otherwise stated, any code posted is most likely untested and may contain syntax errors.
    My posts, comments, code, and suggestions reflect only my personal views.
    Web Portfolio and Code Snippets: http://shanechism.com

  • #13
    Super Moderator Inigoesdr's Avatar
    Join Date
    Mar 2007
    Location
    Florida, USA
    Posts
    3,647
    Thanks
    2
    Thanked 406 Times in 398 Posts
    Quote Originally Posted by ShaneC View Post
    As for storing in the database, that was recommended based on the original request which was storing images, not AI files. Storing images in the database can be significantly more efficient as they can be accessed with O( log n ) efficiency, whereas if it is stored as a file you'll need an O( log n ) lookup for the file name in the database, plus an O( 1 ) access of the file. Obviously, though, if your files are large (which an AI file is likely to be), then putting them in a database isn't the best option.
    Regardless of the size of the file loading it directly from the disk is always going to be faster than querying the database, which also introduces several more potential issues. Most of the time, in my experience, you don't even need a reference to the file in the database unless you are going to make the filenames searchable.
    Quote Originally Posted by ShaneC View Post
    As to "changing the extensions of files is silly", I have to respectfully disagree. If you're storing the original filename and extension in the database (which you'll need to stream the file anyway), then your file could be called PurpleGiraffe.awesome - so long as it can be accessed you'll end up streaming it to the user with the original file name and extension.
    Yeah, you can name it whatever you want, but there is no reason to complicate it like that. Your point of denying access is a good solution, but renaming the files causes more frustration and work on your part when it's not necessary because you can block the whole folder(or place them outside of the document root) and keep your extensions(and sanity).

  • #14
    Codeasaurus Rex
    Join Date
    Jun 2008
    Location
    Redmond, WA
    Posts
    659
    Thanks
    31
    Thanked 100 Times in 94 Posts
    I definitely respect the validity of your arguments, Inigoesdr. I suppose I'm just approaching it from the worst-case-scenario.

    Quote Originally Posted by Inigoesdr View Post
    Regardless of the size of the file loading it directly from the disk is always going to be faster than querying the database, which also introduces several more potential issues. Most of the time, in my experience, you don't even need a reference to the file in the database unless you are going to make the filenames searchable.
    My assumption, based on the original post, is that he's looking to dynamically index the files. That is, make a system by which he can grant someone access to a particular file (or set of files). In this case, a database is your best option. You're already going to need one for the authentication, and extending it to index what files you have will allow you to much more dynamically grant access to file (by adding permission entries).

    Quote Originally Posted by Inigoesdr View Post
    Yeah, you can name it whatever you want, but there is no reason to complicate it like that. Your point of denying access is a good solution, but renaming the files causes more frustration and work on your part when it's not necessary because you can block the whole folder(or place them outside of the document root) and keep your extensions(and sanity).
    In an ideal world then yes, every file uploaded has a unique file name. However when you upload a file with a name that already exists -- well now we have a problem. You'll need to rename the file regardless.

    With the point I already made above, you're already going to have a database for authentication and, to prevent losing the identity of a file which has a duplicate file name, you're going to need to store the file names and their equivalents in the database. So, if you're implementing this type of architecture, and especially if a script is doing the uploading and renaming, the actual name and extension of the file is irrelevant.
    Unless otherwise stated, any code posted is most likely untested and may contain syntax errors.
    My posts, comments, code, and suggestions reflect only my personal views.
    Web Portfolio and Code Snippets: http://shanechism.com

  • #15
    New Coder
    Join Date
    Aug 2010
    Posts
    89
    Thanks
    3
    Thanked 0 Times in 0 Posts
    I thought there was going to be standard way!

    Could you confirm that i have the right idea here?

    OK so i should make a call from my flex app to the phpscript.

    The script will authenticate the user: Any advice on this? (Previosuly the user has logged in) via a different script.

    Get the requested file copy it to a a public directory..or stream it as output. If i stream it..how will i handle that in the air app?

    Get the app to download the copied file from its new temporary public directory..or get the stream. Write it to disk.

    Then i would like to log the download of the file..could i store the user ID and the filename they downloaded in a table?


  •  
    Page 1 of 2 12 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •