Coldfusion, using GetHttpRequestData, to Store and Handle Files - coldfusion

I have a JQUERY file upload plug-in which allows users to upload files to the Coldfusion server. The plugin submits the files to the server in a way that requires me to use GetHttpRequestData() for the files contents. Here's what I have so far in terms of handling the file data:
<cfparam name="URL.qqfile" type="string">
<cfset x = GetHttpRequestData()>
<cffile action="write" output="#x.content#" file="c:\temp\#URL.qqfile#">
This works, which is nice, but I can't seem to take this to the next step.
What I want to happen next is:
A. Determine the file's extension.
B. If it is an accepted ext defined by my app, (JPG,PNG,PDF, DOC, DOCX, etc...) upload it to the correct directory on the server. Then delete the temp file above
C. Use CFIMAGE to make a thumbnail if the file uploaded was an Image
How can I take the above through steps A-C with the GetHttpRequestData problem?
Thanks

A few tips:
Have a look at the result structure of GetHttpRequestData() via <cfdump>.
Pull out the necessary headers by accessing this struct. The Content-Type header usually contains the stuff you want to know. You can use the List functions (i.e. ListLen(), ListFirst(), ListLast(), ListRest() with appropriate delimiter chars) to easily parse the string.
Always use StructKeyExists() to safeguard against missing struct parts. Never take for granted anything that "typically" seems to be in this struct.
Don't blindly trust file extensions or the Content-Type header. Also look into the first few bytes of the uploaded file and compare them against a white list to confirm the file type.
Have a look at <cffile action="upload">.
Optionally, perfom a drive space test to assess if the uploaded data does not clog the server, or enforce limits in another way that suits you.
Read through the documentation of <cfimage>. It can't be that hard to use it to make thumbnails.

Related

How does one determine the filetype on an AWS S3 hosted file without the extension?

As an example, I'm currently uploading items directly to an S3 bucket using a form. While I was testing, I didn't specify any expected filenames or extensions.
I uploaded a .png which produced this direct link:
https://s3-us-west-2.amazonaws.com/easyhighlighting2/2015-07-271438019663927upload94788
When I place this inside an img tag, it displays on a web page properly.
My question is, without an extension, how would my browser know what type of file it's loading? Inside the bucket, the file's metadata isn't even filled out.
Is there any way to get that file extension, programmatically?
I'm ready to try any clientside methods available; my server-side language is ColdFusion which is somewhat limiting, but I'm open to suggestions for that as well.
Okay, so after some more extensive digging, I found a method of retrieving the file's type that was only added since CF10 was released; that would explain the lack of documentation.
The answer lies in the FileGetMimeType function.
<cfset someVar = "https://s3-us-west-2.amazonaws.com/easyhighlighting2/2015-07-271438019663927upload94788">
<cfset FileType = FileGetMimeType(someVar)>
<cfoutput>#FileType#</cfoutput>
This code would output image/png - which is correct and has worked for every filetype I have tested thus far.
I'm surprised this kind of question hasn't popped up before, but this appears to be the best answer, at least for users of CFML.
Edit:
ColdFusion accomplishes this by either reading the contents of a file, or by trusting its extension. An implicit attribute, 'strict', is used in this function. If true, it reads the file's contents. If false, it uses the provided extension.
True is the default.
Link:
https://wikidocs.adobe.com/wiki/display/coldfusionen/FileGetMimeType
Check the Content-Type HTTP response header returned by Amazon S3.
For example, curl -I https://s3.amazonaws.com/path/to/file fetches only the headers.

ColdFusion CFFILE to limit text file upload

I'm want to use CFFILE upload to detect only .txt file. I've tried to use file.clientfileext to detect the extension. When TXT is detected, I'm showing a pop up error message to users and delete the file. But I was told I should not even allow user's file to reach our server.
Then I use CFFILE accept attribute to only accept text/plain. This should do it but unfortunately on my test when I tried uploading non text file I got ColdFusion error:
The MIME type of the uploaded file application/pdf was not accepted by
the server. Only files of type text/plain can be uploaded. Verify
that you are uploading a file of the appropriate type.
I tried to use cftry and cfcatch but I still get the same error, this mainly due to the MIME Type that I don't know when the file is being uploaded by the browser.
I also found the same question in this forum and tried the suggested answer, it did not work, still got the same error message (see below)
I also found another posting in this forum that do not suggest the use of CF "accept" attribute. This link is provided for a further detail explanation: http://www.petefreitag.com/item/701.cfm
So my question is, since I'm still using CF8, I actually don't have many options to prevent my users from uploading other than .txt file securely?
If I can't use the accept attribute of the CFFILE, can I at least secure my file upload functionality by doing the following? but is doing it this way safe enough?
Upload the file to a temp folder that is not under the root dir
verify the file extension
change the file name even if the extension is detected to be a .txt
move the file to the destination file under the root dir
Even if I do these steps, I have to allowed the file to reach our server, the order is to NOT allow the file to reach our server.
Below is the answer/suggestion from previous question. But it doesn't work when I tested it:
<CFTRY>
<cflock name="write_lock" type="Exclusive" timeout="120">
<cffile action="upload" filefield="filepath" destination="#DestDir#"
nameconflict="Overwrite" attributes="Archive">
</cflock>
<CFCATCH>
<cfif FindNoCase("not accepted", cfcatch.Message)>
<script>
$(function(){
alert("Only the following file types are allowed: .jpg, .gif, .bmp,
.png.");
});
</script>
<cfabort />
<cfelse>
<!--- looks like non-MIME error, handle separately --->
<cfdump var="#cfcatch#" abort />
</cfif>
</CFCATCH>
</CFTRY>
I think your steps are reasonable if you don't like using the Accept attribute for validation. FYI you can set accept to .txt instead of the MIME types. The MIME type was determined by the client so it's safer to check the extension anyway.
The exception thrown by cffile failing attribute validation may not have a type, so the code you posted tried to detect it with FindNoCase() by looking at the exception's message. You can dump the exception out and find out why the FindNoCase() failed to catch the exception.
Make sure you treat whatever uploaded as something potentially malicious and do not process them (e.g. cfinclude them). Forcing the file extension to be .txt should be safe enough, but I'll let other security experts charm in.
You can use the below code:
<cffile action="upload" filefield="BidDoc"
destination="C:\upload\"
nameconflict="makeunique"
accept="text/plain">
The other mime types which you may use are:
application/pdf
application/msword
application/vnd.ms-excel
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
As discussed in this answer, there really is no 100% fool-proof way.
If you don't want to trust the "accept" attribute, I would suggest allowing the user to upload the file and then checking the mime type of the uploaded file using the cffile.contentType property. Check against whatever mime types you wish to allow/restrict and reject with the appropriate message. You may also choose to employ a check of the file extension as an added layer of error checking.
It must be noted that like file extensions, mime types can not be 100% trusted to be accurate as they can be edited by the user. But using a combination of checks you can be reasonably that most files uploaded are of the correct type.
Coldfusion will not prevent a file from being uploaded to a server. You can set a maximum file size but this is processed during the upload. The cffile tag kicks in after the file is uploaded. Furthermore it is rather difficult to really determine if a file is a text file or a jpg, exe, rar etc file. The following q & a may help:
Determining binary/text file type in Java?
In my opinion it is best to follow the tips given by pete freitag and use a java class to determine the file type. Then you can delete all non text files.

How do I CFINCLUDE without creating a cached template in /WEB-INF/cfclasses/?

Are there any solution or alternative ColdFusion tag to include static text file without creating template cache under /WEB-INF/cfclasses ?
The problem is I have dynamic pages growing over the time.
Each page need to include one single static file.
e.g.
<cfinclude template="mapping/static_1.txt> for page 1
<cfinclude template="mapping/static_2.txt> for page 2
<cfinclude template="mapping/static_3.txt> for page 3
....etc.
Since the number of pages are growing to 2000 pages, it cause the server down as the system generate 2000 cache tempaltes which exceed the server limit.
I can ask hosting support to extend the limitation but that will not be the long a term solution for dynamic pages that growing over the time.
Obviously, there is no calculation required as the file to include is static text (.txt) which contain static HTML tags (no script involve).
Is there any alternative tag apart from <cfinclude > that will just
show the file content without binary calculation and cache creation?
Or is there any solution to prevent server from caching .txt file?
Sorry for question that may simple but I'm new to CF here.
Your pointer would be really appreciate.
Cheers
Chanon
my hosting support do not recommend disable caches all together.
Anyway, I came out with a simple solution using <cffile> instead of <cfinclude>.
When using <cffile> server will not execute each lines and create cache. Instead, it just grab the whole chuck of file and put it in variable.
Why use CFINCLUDE if those are static HTML files? Use FileRead() for example (or longer version with FileOpen/FileReadLine/FileIsEOF) - or even CFFILE with action="read".
<cfset variables.content = FileRead("mapping/static_1.txt")>
<cfoutput>
#variables.content#
</cfoutput>
There's no point using CFINCLUDE if there's no CFML/CFScript to process.
You don't need to cache any compiled class files at all: there's a setting in CFAdmin to switch this caching off (on the Cache page: "Save Class Files"). Those cached files are only really a benefit at server start-up time: it saves files being re-compiled when they're first accessed. This overhead is neglible, really. It used to be considerable back in the days of CFMX6 & 7, but not so much since then.
There is - as far as I know - no way to pick & choose which files have their compiled classes saved. It's all or nothing.
What one could do, I suppose, is to switch the setting on, compile all the apps "main" files so their classes are saved, then switch the setting off. One would need to repeat this process whenever one adds new files to the application though. Still: that's not such a hardship.
But I see no benefit in having these files saved at all, these days.

<cffileupload> and Database Insert of File Name

I am having a problem with the cffileupload tag and then inserting the names of the files uploaded into the database. It seems like there are no hooks back from the CF Action page that would say if it was successful, if the file was renamed, what the new filename is, and
Basically, I want a user to be able to upload mulitple files (up to 10) without a timeout and storing the name of the files in the database.
Any suggestions would be welcome! I've dug around on the interweb, and there doesn't seem to be any elegant solutions.
After the file is processed by <cffile action="upload">, there's a huge amount of information available via the variable specified in "result". This includes the original filename, the file size, and an indicator of success. Adobe's docs on cffile has the details. Your best bet is to create a temporary file, push the upload to there via cffile, evaluate success or failure, then push it into the database. Something like:
<cfset TemporaryFile = GetTempFile(GetTempDirectory(), "myAppTemp") />
<cffile action="upload" destination="#TemporaryFile#"
fileField="filefield" result="FileResults" />
Then you can access your file via the TemporaryFile variable, and the filename via FileResults.clientFile. FileResults.fileWasSaved should indicate success or failure of the upload and subsequent save to disk.

Is there a way to make cffile.oldFileSize return a correct value?

When working with cffile in ColdFusion, after an upload of a file to a webserver, the cffile structure is created that is supposed to have a value in it called "oldFileSize". Every time I do an upload and examine that value, it has the new file's size, not the overwritten file's size. Is there some setting somewhere to correct that or is this a bug in cffile in cf8?
Clarification: If you use the cffile command to upload a file to a server, it will attempt to store that file in the location you tell it in the command. If the destination already has a file there with the same name and path, then one of the options in your cffile command can bet to overwrite any existing file. If you do that, a structure is returned called cffile with an attribute called "oldFileSize". The documentation states that oldFileSize should be the size of the file that was overwritten. Instead, it's returning the size of the file being uploaded.
If the oldfilesize attribute is not returning correctly, I would use nameconflict=unique to preserve the old file. Then, you can use cfdirectory to check the old filesize, and cffile action="delete" and action="rename" to replace the old file, so that you have essentially overwritten the old file, only manually.
A bit of work, but if you need the information....
Ben Doom is correct about the work-around to the problem, but if you're not seeing the documented behavior, that's a bug and you should report it! Currently, there is no public bug tracker you can submit to (although there is a push for one and we should probably see it soon-ish), so the defacto standard is to post it as a comment on the documentation page.
Adobe staff does read and respond to comments and they will likely either respond that it will be fixed, or acknowledge that it is a bug but indicate there is no plan to fix it at this time. Either way, the responsible thing to do is to report the bug.
What overwritten file? It seems you are talking about two files when you only refer to one.