File Create Time in ColdFusion / CFML

Today I needed to get the time that a file was created from within some CFML code. I had first thought that cfdirectory or directoryList would return this, but it only returns the date the a file was modified, not the date that it was created. My next thought was that getFileInfo must return this, but again it only returns the date that the file was last modified. Even java.io.File only returns the last modified date, not the date the file was created. The Solution The solution is to use Java's NIO (Native IO) file API, and more specifically the java.nio.file.attribute.BasicFileAttributes implementation. Here's a function that will return the date a file was created, modified, and the date the file was last accessed. function getFileAttributes(path) { var filePath = createObject("java", "java.nio.file.Paths").get(arguments.path, []); var basicAttribs = createObject("java", "java.nio.file.attribute.BasicFileAttributes"); var fileAttribs = createObject("java", "java.nio.file.Files").readAttributes(filePath, basicAttribs.getClass(), []); return { "creationTime": fileAttribs.creationTime().toString(), "lastModifiedTime": fileAttribs.lastModifiedTime().toString(), "lastAccessTime": fileAttribs.lastAccessTime().toString() }; } Note that some linux file system implementations don't actually keep track of the last access time (or atime as they call it), so you might get the last modified date there instead.

From: Pete Freitag's Homepage

Speaking at ColdFusion Summit Online Next Week

I will be giving my talk Taming the Top 25 Most Dangerous Software Weaknesses (for ColdFusion Developers) next Tuesday, December 6th 2022 at 1pm US Eastern Time. You will need to register with Adobe to join, it's free. Adobe is repeating many of the talks from the in person ColdFusion Summit that took place in October, if you weren't able to make it - this is a great way to see the presentations. Finally, if you are interested in the topic of ColdFusion Security, there are still a few seats left in my ColdFusion Security Training Class taking place on December 13th and 14th.

From: Pete Freitag's Homepage

OpenSSL and ColdFusion / Lucee / Tomcat

I've had a several people asking me about the openssl vulnerabilities that were patched this week: CVE-2022-3602 and CVE-2022-3786 aka Spooky SSL. ColdFusion / Lucee and OpenSSL As far as I know both ColdFusion and Lucee do not use openssl for any of its crypto operations by default. Both ColdFusion and Lucee use the Java Cryptographic Extension (JCE) layer which provides an api to access crypto algorithm implementations. Adobe ColdFusion Enterprise is using RSA BSafe CryptoJ provider, which has FIPS compliant implementations of many crypto algorithms. The standard version, and Lucee would likely just use the default provider that ships with java. Adobe's Product Support Manager mentioned on the CFML slack on November 4, 2022 that Adobe ColdFusion is not impacted: Hi All, Just want to update everyone that CF is not impacted by OpenSSL vulnerability. Tomcat and OpenSSL Tomcat - which ships with ColdFusion, can actually use openssl libraries to provide a SSL / TLS / HTTPS connector for the tomcat web server. This feature is called Tomcat Native. So if you have Tomcat configured with SSL/TLS you should check and see if it is using Tomcat Native with the OpenSSL Library. You would see something like this in your catalina.out file: 01-Nov-2022 10:22:42.105 INFO [main] org.apache.catalina.core.AprLifecycleListener.initializeSSL OpenSSL successfully initialized [OpenSSL 3.0.4-dev 3 May 2022] If you find that you are using OpenSSL version 3, you need to upgrade to the most recently patched version of OpenSSL 3. From the OpenSSL Security Advisory: OpenSSL 3.0 users should upgrade to OpenSSL 3.0.7. OpenSSL 1.1.1 and 1.0.2 are not affected by this issue. Or you can also remove the Tomcat Native AprLifecycleListener from your server.xml file: <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> It appears that you can alternatively set UseOpenSSL="false" on the <Listener> tag of the AprLifecycleListener. After making one of the above changes, double check your tomcat logs and make sure OpenSSL 3 is no longer output on server startup. IIS and OpenSSL IIS uses MSCAPI to perform crypto operations, so you should be ok at the web server level if you are using IIS. Apache or nginx and OpenSSL Most linux based web servers such as Apache or nginx would be using OpenSSL, however there is a good chance that your server is not using Openssl 3 yet. You can check the version of openssl installed by running: openssl version Check the list of software affected / unaffected Here is a handy list of software that has been marked as vulnerable or not vulnerable to this issue. Disclaimer: The content (and links) on this page are provided as is, without warranty of any kind. Use at your own risk. You should consult with your software vendors to ensure that you are properly protected.

From: Pete Freitag's Homepage

ColdFusion Security Training Class December 2022

Early bird registration is open for my ColdFusion Security Training deep dive class in December. If you've ever attended one of my conference sessions on ColdFusion Security at Adobe ColdFusion Summit or Into The Box (or even cf.Objective() or CFUnited :-) you know that it is hard cover a wide variety of issues in a one hour session. It is an online class that takes place over Zoom on Tuesday December 13, 2022 and Wednesday December 14 from 11am-2pm each day. I find that two three hour chunks each day is a good amount of time to get hands on and in depth, but not so long that your brain is completely toasted. It also leaves some time for you to get some of your typical work done on those days if you are so inclined. Here's an outline of the topics that will be covered in the course: Remote Code Execution Path Traversals & File Path Vulnerabilities File Upload Vulnerabilities Cross Site Scripting Cross Site Request Forgery Session Hijacking Cookie Security Password Storage Authentication Authorization Content Security Policy SQL Injection Timing Attacks Scope Injection LDAP Injection XML Security Issues Core Security Principals Proactive Coding Guidelines OWASP Top 10 Security Tools: OWASP Zap, Fixinator And more! The course covers a wide range of vulnerabilities that CFML web developers should be aware of. For each vulnerability the students will learn about it, attempt to exploit it, and last but certainly not least learn how to fix or mitigate the vulnerability. I would love to have you attend, so please sign up while seats are still available and before the price increases on December 1st.

From: Pete Freitag's Homepage

How Long Has Your ColdFusion Server Been Running?

Someone asked on the CFML slack recently how can you find out how long your ColdFusion (or Lucee) server has been running via code. How long has the server been running? createObject("java", "java.lang.management.ManagementFactory").getRuntimeMXBean().getUptime() This approach uses Java's Management Factory Runtime Bean to get the number of milliseconds since the server started. What date / time did the server start? The Runtime Bean in Java, also has a getStartTime() function that returns the time the jvm was started as a timestamp. start_time = createObject("java", "java.lang.management.ManagementFactory").getRuntimeMXBean().getStartTime(); java_date = createObject("java", "java.util.Date").init(start_time); writeOutput(dateTimeFormat(java_date, "long")); Here's a trycf snippet for both examples. Finally someone pointed out that on licensed ColdFusion server you can actually use the variable coldfusion.server.expiration to get the time that the server started. Charlie Arehart has a blog entry all about that approach. The blog entry was from 2006, but it apparently still works! That approach might not work in all cases or on Lucee however, but it really simpler than the approach I have here.

From: Pete Freitag's Homepage

Adding CloudFlare Turnstile CAPTCHAs to CFML Sites

CloudFlare recently released a new CAPTCHA service called Turnstile, which aims to provide a better user experience for CAPTCHA's. At the worst case the user will have to click a checkbox, rather than train a machine learning model solving a puzzle. You don't need to use CloudFlare's CDN / dynamic proxy services on your site to use this service, and it is free to use. Client Side Implementation There are a few different ways to implement the front end side, but at a minimum you would just add these two lines to an existing form: <div class="cf-turnstile" data-sitekey="YOUR-SITE-KEY"></div> <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script> Make sure you replace YOUR-SITE-KEY with Site Key that CloudFlare provides to you. The JavaScript will automatically insert a hidden input field inside the div named cf-turnstile-response. When the captcha is solved it will also automatically fill value of the hidden field with the captcha response code: <input type="hidden" name="cf-turnstile-response" value="automatically filled and generated"> Server Side Implementation Now your job on the server side is to verify that the value passed in cf-turnstile-response is legit. On the form action page you will need to make a HTTP request to cloudflare with your secret key and the cf-turnstile-response value. Here's a ColdFusion / CFML function I've implemented that takes care of it all: function verifyTurnstileResponse(secret, response, remoteip="") { try { var httpResult = ""; cfhttp(url="https://challenges.cloudflare.com/turnstile/v0/siteverify", method="POST", result="httpResult", timeout=5) { cfhttpparam(name="secret", value=arguments.secret, type="formfield"); cfhttpparam(name="response", value=arguments.response, type="formfield"); if (len(arguments.remoteip)) { cfhttpparam(name="remoteip", value=arguments.remoteip, type="formfield"); } } if (isJSON(httpResult.fileContent)) { return deserializeJSON(httpResult.fileContent); } else { return { "success": false, "error-codes":["response-was-not-json"], "http-result": httpResult}; } } catch (any err) { return { "success": false, "error-codes":["exception"], "exception": err}; } } The function should always return a struct with the boolean key "success", if the HTTP request fails for any reason it will return with a success value of false. Here's how you might use it... var turnstile = verifyTurnstileResponse(secret=server.system.environment.TURNSTILE_SECRET, response=form["cf-turnstile-response"]); if (turnstile.success) { //do it } else { //log / display error } The remoteip argument is optional, so I left it out in my example. I didn't want to default it to cgi.remote_addr because in some proxied environments that wouldn't be the correct IP. I'll probably turn this code into a ColdBox module at some point as well.

From: Pete Freitag's Homepage

ColdFusion Summit 2022 Slides

I'm back from another excellent CFSummit. So many great presentations and conversations. This I gave a presentation on the 25 Most Dangerous Software Weaknesses and how they relate to ColdFusion. My company Foundeo Inc. once again sponsored the event. It was nice to be able to present live, instead of over zoom! You can find the slides here, and the code samples are on github in my CFML Security Training repository. If you missed it, or you were there but want to go deeper into many of the issues we discussed I will be hosting a ColdFusion Developer Security Training Class on December 13-14, 2022.

From: Pete Freitag's Homepage

Ways to suppress a finding in Fixinator

Code is complex, so any static application security testing (SAST) tool will find things that may not be an actual security issue. Fixinator has a few different ways we can deal with this problem. For example, let's suppose you have a variable application.maxstories=10 set in Application.cfc, and you use that variable in a different file like this: <cfquery name="news"> SELECT headline, story FROM news ORDER BY date_published DESC LIMIT #application.maxstories# </cfquery> Assuming that application.maxstories is always defined, this query isn't vulnerable to SQL injection because you can't change the value of application.maxstories unless you can change the application source code. Quick aside: If the application.maxstories variable is defined conditionally, then it is a different story. The value of the variable in the query could be manipulated via something I call scope injection via url.application.maxstories for example. But that depends on application.maxstores being undefined. Suppressing a single finding with Fixinator If you are using Fixinator then we have a few different ways to suppress this finding. We can add a comment as such: <cfquery name="news"> SELECT headline, story FROM news ORDER BY date_published DESC <!--- ignore:sqlinjection because application.maxstories is always defined ---> LIMIT #application.maxstories# </cfquery> When Fixinator finds an issue, it will check to see if there is a comment with the pattern ignore:scanner-type directly above or on the same line as the issue. You can optionally add a reason to the comment, which I always like to do. However if this were my code, I would rather just do this: LIMIT #int(application.maxstories)# Fixinator understands that wrapping a variable with int() is a safe solution. I prefer that approach over a comment. Suppressing a type of finding over many files with Fixinator Fixinator has a setting called ignorePatterns that can be defined in a .fixinator.json file. For the above example, we might use something like this: { "ignorePatterns": { "sqlinjection": ["application.maxstories"] } } That will tell fixinator to ignore any SQL Injection finding where the variable contains application.maxstories, pretty handy way to keep your fixinator report free of any false positives. Here's another example... let's assume we fixed XSS issues in our app before the encodeForHTML was builtin to CF by creating our own function called xssEncoder. Perhaps our own function originally called ESAPI directly via java, but now is just an alias to encodeForHTML. This abstraction isn't a bad thing, it even allows us to switch to a different encoder in the future if a better one comes along. We can tell Fixinator about it like this: { "ignorePatterns": { "sqlinjection": ["application.maxstories"], "xss": ["xssEncoder("] } } Of course you have to be careful about what you ignore, but I think it is an important feature to have. Without a good way to manage false positives you are either giving developers pointless work just to please the scanner, or the reports are full of false positives and end up being ignored. Neither lead to better security.

From: Pete Freitag's Homepage

Simple Parallel Execution in ColdFusion or Lucee

A really handy feature of the arrayEach() function is the parallel argument. It has been supported in Lucee since 4.5, but ColdFusion 2021 now supports it as well. What does the arrayEach function do? Quite simply it loops over each element of an array and invokes a function for each element of the array, here's a simple example: fruit = ["Apples", "Oranges"]; arrayEach(fruit, function(item) { writeOutput("I like #item#"); }); It would output (run on trycf): I like Apples I like Oranges Make it parallel Recently on the cfml slack the question was asked: Anybody have a good examples of using the parallel features or multi-threading <cfhttp> requests? Yes, you can do this with the parallel argument of array each quite easily: requests = [ {"url"="https://httpbin.org/ip"}, {"url"="https://httpbin.org/uuid"}, {"url"="https://httpbin.org/uuid"}, {"url"="https://httpbin.org/uuid"}, {"url"="https://httpbin.org/uuid"} ]; maxThreads = 5; parallel = true; tick = getTickCount(); arrayEach(requests, function(value, index) { var httpResult=""; cfhttp(url=value.url, result="httpResult"); value.result = httpResult.fileContent; }, parallel, maxThreads); writeOutput("Took: #getTickCount()-tick# with parallel: #parallel#, maxThreads: #maxThreads#"); writeDump(requests); You can run the example on trycf and see that when parallel = true; it runs in about 180ms, when you set parallel = false; it takes 750ms. Pretty simple way to get a big speed boost for that use case, and much easier than using cfthread. Things to look out for One thing you do need to be careful of when you start multithreading is synchronization issues. In my example I am updating the array element struct, but if I were modifying the array itself, or another shared variable within my closure function, I would need to use cflock. For the same reasons, if you create any variables within your closure function, make sure they are var scoped or you will run into some strange issues. Without the var scope, the variable will be in the variables scope and shared among all the iterations.

From: Pete Freitag's Homepage

Creating a ColdFusion UUID in MySQL

The uuid() function in MySQL returns a 36 character hex string, formatted as: aa479ea9-1d9d-11ed-ba03-564760fe47b7 ColdFusion's createUUID() function returns a 35 character hex string formatted as: AA479EA9-1D9D-11ED-BA03564760FE47B7 Both store the same amount of data (16 bytes), the only difference is that there is an extra dash in the MySQL uuid() function result. Here's some SQL I came up with to create a UUID using ColdFusion's formatting in raw SQL: SELECT upper(concat(left(uuid(), 23), right(uuid(), 12))) It is not an ideal solution because I am actually calling uuid() twice, but it is sufficient for my use case. You could probably use a regex to remove the extra dash and avoid calling uuid twice if you wanted to try and optimize it. Feel free to post a comment if you can come up with a better way to do it. Now suppose you want to convert the CFML uuid back to a MySQL uuid, you can do so like this: SELECT lower(concat(left(some_id, 23), '-', right(some_id, 12))) FROM table

From: Pete Freitag's Homepage

Better CFML Code with CI

I gave a presentation for the Adobe ColdFusion Developer Week Conference today titled: Better CFML Code with CI. You can find the slides for my talk here, and the video here. Here is a link to the code samples.

From: Pete Freitag's Homepage