ColdFusion CFFILE to limit text file upload - coldfusion

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.

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 10 CFFILE Accept mimetype not recognised

I'm having problems uploading WMV and MPEG files, 'video/x-ms-wmv' (etc) are on the accept list - I get an error of
The MIME type or the Extension of the uploaded file
application/octet-stream was not accepted by the server
Using Chrome, I check the header and it reads
Content-Disposition: form-data; name="fv_file"; filename="blahblah.wmv"
Content-Type: video/x-ms-wmv
the Client machine also has the WMV registry entry which appears correct.
Server side
Apache is configured to use the OS mime type file: /etc/mime.types.
This file contains entries for wmv and mpeg:
video/x-ms-wmv wmv
video/mpeg mpeg
How does CF10 determine the mimetype? I'm struggling to find out this information.
Does anyone have a solution?
Thanks
edit- Added Code
<cffile action="UPLOAD" filefield="fv_file" destination="#pathtotheserverroot##mediadir#/video/" nameconflict="MAKEUNIQUE" accept="#qry_xxxx.OT_MIMETYPES#" mode="644">
The value of OT_MIMETYPES is
video/mp4,video/mpeg,video/quicktime,video/x-msvideo,video/x-sgi-movie,video/avi,video/vnd.vivo,application/vnd.rn-realmedia,video/vnd.rn-realvideo,audio/vnd.rn-realaudio,audio/x-pn-realaudio,video/x-ms-wmv,audio/mpeg,video/mpg,video/mpe,video/x-ms-asf,video/x-m4v
I did a CFDUMP for completeness
Accept video/mp4,video/mpeg,video/quicktime,video/x-msvideo,video/x-sgi-movie,video/avi,video/vnd.vivo,application/vnd.rn-realmedia,video/vnd.rn-realvideo,audio/vnd.rn-realaudio,audio/x-pn-realaudio,video/x-ms-wmv,audio/mpeg,video/mpg,video/mpe,video/x-ms-asf,video/x-m4v
Detail Only files of type video/mp4,video/mpeg,video/quicktime,video/x-msvideo,video/x-sgi-movie,video/avi,video/vnd.vivo,application/vnd.rn-realmedia,video/vnd.rn-realvideo,audio/vnd.rn-realaudio,audio/x-pn-realaudio,video/x-ms-wmv,audio/mpeg,video/mpg,video/mpe,video/x-ms-asf,video/x-m4v can be uploaded. Verify that you are uploading a file of the appropriate type.
Message The MIME type or the Extension of the uploaded file application/octet-stream was not accepted by the server.
MimeType application/octet-stream
I will have to speculate until I can see your <cffile> code but my guess is that you have not allowed the appropriate mime type under the accept attribute of the <cffile> tag.
Now that you have included your code my assumption has been confirmed: you have not allowed the appropriate mime type under the accept attribute of the <cffile> tag.
See below for further details.
Several changes were made to how the <cffile> tag works in ColdFusion 10. You may or may not be aware that in ColdFusion 10 they added the strict attribute to the tag (documentation reference).
When strict is true, only MIME types or a combination of MIME types and extensions are allowed in the accept attribute. Since strict is true by default, you should specify MIME types for the accept attribute.
When strict is false, either MIME types or extensions or a combination of both can be specified as a value to the accept attribute. For more information, see this blog entry.
Not only was that attribute added, but the default value for the strict attribute is true. So because you have not specified it within your code it is on.
Note: If you receive an error like "The MIME type of the uploaded file (image/jpeg) was not accepted by the server", enter accept="image/jpeg" to accept JPEG files.
Taken from the Adobe documentation here. From the error message that you have posted an attempt was made to upload a file with mime type of "application/octet-stream". You appear to be expecting "video/x-ms-wmv". So you can try to figure out why your browser is attempting to upload the file as "application/octet-stream" or add that mime type to your accept attribute. WARNING: that will also allow other types of files to be uploaded that you probably don't want.
The cffile accept attribute uses the mime type that your browser sends to the server. Read that again... your browser tells cffile what the mime type is. It's very easy to spoof the mime type
Taken from Pete Freitag's page on Tips for Secure File Uploads with ColdFusion. (An older article but still has relevant tips.)
A couple of other references I found that may be helpful:
Adobe forums - cffile MIME types
Learn CF In A Week - File Uploads
How is mime type of an uploaded file determined by browser?
Answer to Why am I getting mime-type of .csv file as “application/octet-stream”?
You may have some odd mime type. If you use a try/catch block around your tag, you can display the full error message.
Example:
<cftry>
<cffile accept="video/x-ms-wmv" action="upload" destination="#ExpandPath('/client-images/')#" filefield="form.UploadFile" nameconflict="makeunique">
<cfcatch type="any">
<cfdump var="#cfcatch#" label="cfcatch">
</cfcatch>
</cftry>
The dump will display the mime type that ColdFusion thinks that was uploaded.
This is for development/analysis only, you wouldn't want to present the dump to regular site visitors.

Cfdocument being served by server despite being in cfsavecontent

It seems that when I use the <cfsavecontent> tag, the output of that is being served by the server (without the variable being outputted), which, to me, kind of defeats the purpose of <cfsavecontent>.
If this is important: my application uses ColdSpring, ModelGlue and Transfer ORM.
Here's my example code in a function:
<cfsavecontent variable="testvar">
<cfinclude template="test.cfm" />
</cfsavecontent>
<cfreturn testvar>
And the template:
<cfdocument format="PDF" pagetype="A4" orientation="portrait" unit="cm">
<cfoutput>
<!--- PDF content here --->
</cfoutput>
</cfdocument>
The PDF content is being parsed by my browser (Google Chrome), while the view hasn't even been loaded in. How can I best prevent this from happening?
Just to clarify: I am not outputting the #testvar# variable yet in this code, though it seems it loads the template in the browser anyways.
To achieve what you're trying to do, should you not simply be using the name attribute of <cfdocument> to put the PDF data into a variable, instead of trying to <cfsavecontent> it?
Disclosure: I've never used <cfdocument> for anything other than proof-of-concept code and testing, but that's what I'm inferring from the docs.
As I also needed to make multiple PDF documents merge, I ended up doing the following. Many thanks to Adam Cameron for providing the solution to my initial issue.
In the template file, I use the <cfdocument> tag with the name attribute to save the PDF in a variable (thanks to Adam Cameron for this)
Then, I store all the PDF documents in an array in their binary format
In my view, I merge the PDF documents together by using <cfpdf>'s merge action, and using a cfloop, to loop over the array, inside it.
Finally, I display the content by using <cfcontent> and using the variable attribute with toBinary(myPdf)
This got me to where I am.
cfinclude will process the test.cfm page, and the way you configured cfdocument will cause "opening" of pdf document in your browser.
You can prevent openning of this file by saving file on the disc:
<cfdocument format="PDF" pagetype="A4" orientation="portrait" unit="cm" filename ="test.pdf" overwrite ="yes">
But this will not prevent execution of cfinclude in the cfcontent tag, it will just prevent opening in the browser.
You can observe cfinclude as request to the server, it will always be executed.
The solution would be to invoke request on test.cfm file which contains cfdocument in the moment that you actually want to generate pdf.
Example: Use javascript on client to invoke report service which will generate and pop out the screen with pdf report.
Hope this helps.

<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.

Coldfusion, using GetHttpRequestData, to Store and Handle Files

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.