Allowing users to upload image files, which are then displayed, can seem extremely simple but has its challenges and security concerns. The main danger is the fact that much of the information available to us at the time of an upload request is supplied by the client/browser, which means all of that information has the potential to be "spoofed" by an unscrupulous hacker.
We can safely upload image files by uploading to a temporary (non-Web-accessible) directory and then moving beneath the Web root once we're certain we have a safe and valid image file.
Allowing users to upload image files, which are then displayed, can seem extremely simple but has its challenges and security concerns. The main danger is the fact that much of the information available to us at the time of an upload request is supplied by the client/browser, which means all of that information has the potential to be "spoofed" by an unscrupulous hacker.
For example, keep in mind that the
accept attribute of the
cffile tag can only validate the MIME type
against that which is supplied by the client/browser. Once again,
this can be spoofed and is therefore not to be trusted! The
following example is still prone to accepting a .cfm file with a
spoofed MIME type of image/gif, for example.
<cffile action="upload" filefield="uploadFile"
destination="#expandPath('images')#" accept="image/gif" />
The following "recipe" is a fairly simple example that demostrates a number of security measures taken upon file upload:
accept attribute in
cffile to limit MIME types accepted from
client; catch potential error thrown.isImageFile() function to ensure the uploaded file
is an image.
<cfset imagesDir = "images" />
<cfset imagesPath = expandPath(imagesDir) />
<cfset uploadPath = getTempDirectory() />
<cfset acceptMimeTypes = "image/gif,image/jpeg,image/png" />
<cfset acceptExtensions = "gif,jpeg,jpg,png" />
<!--- Process file upload, if form submitted --->
<cfif structKeyExists(form, "uploadFile")>
<!--- Catch error if MIME type is not accepted --->
<cftry>
<cffile action="upload"
filefield="uploadFile"
destination="#uploadPath#"
accept="#acceptMimeTypes#"
nameConflict="makeUnique"
result="uploadResult" />
<cfcatch type="any">
<p>ERROR: <cfoutput>#cfcatch.message#<br
/>#cfcatch.detail#</cfoutput></p>
</cfcatch>
</cftry>
<!--- Proceed only if successful upload... --->
<cfif isDefined("uploadResult")>
<!--- Ensure that file is an image --->
<cfif
isImageFile("#uploadPath#/#uploadResult.serverFile#")
AND listFindNoCase(acceptExtensions,
uploadResult.serverFileExt)
AND uploadResult.fileSize LTE 102400
>
<!--- OK to move the file from the temporary
location to the images folder under Web root --->
<cffile action="move"
source="#uploadPath#/#uploadResult.serverFile#"
destination="#imagesPath#" />
<!--- Display success message, stats and image
--->
<cfoutput>
<p>Image uploaded!
(#uploadResult.serverFile#, #numberFormat(
uploadResult.fileSize/1024 )# KB)</p>
<p><img
src="#imagesDir#/#uploadResult.serverFile#" /></p>
</cfoutput>
<!--- File upload not allowed! --->
<cfelse>
<!--- Show error message and delete file from temp
directory --->
<p>ERROR: You may only upload a 100 KB or less
file of type image with one of the following file extensions:
#replace( acceptExtensions, ",", ", ", "all" )#.</p>
<cffile action="delete"
file="#uploadPath#/#uploadResult.serverFile#" />
</cfif>
</cfif>
</cfif>
<!--- Display form to allow user to select an image file to
upload --->
<cfoutput>
<form action="#cgi.script_name#" method="post"
enctype="multipart/form-data">
Select image to upload: <input type="file"
name="uploadFile" />
<input type="submit" value="Upload File" />
</form>
</cfoutput>
For further reading, Pete Freitag has a great post here on tips for safe file uploads.
+