Enforcing The HTTP Request Method In ColdFusion

By admin
Enforcing The HTTP Request Method In

ColdFusion

HTTP GET
PRODUCT

requests should always be safe to execute because they are intended to read the state of the system in an idempotent fashion. Other HTTP methods (verbs)—such as

POST
ORG

and

DELETE
ORG

—which are intended to mutate the state of the system, can be dangerous and should be validated. Meaning, you never want to allow a GET request to invoke a resource that merits a POST method. I wanted to take a quick look at how you can enforce the HTTP request method in

ColdFusion
ORG

.

The easiest way to enforce the HTTP method in

ColdFusion
ORG

is to do so implicitly by relying on the URL and FORM scopes to deliver the different sets of data. By default, the URL scope only contains the data present in the request URL. And, the FORM scope only contains the data present in a form submission.

Which means, if you need to ensure that a request is processed as part of a form submission, check the form scope—and only the form scope—for that data.

To see what I mean, let’s look at a simple

ColdFusion
ORG

page that contains both a <form> element and an <a> element which seeks to impersonate the form:

<cfscript> // In this version, the

SUBMITTED
ORG

value is only observed in the FORM scope, which // means that we can be confident that the request was submitted via an HTTP POST (if // the value is true). param name="form.submitted" type="boolean" default=false; if ( form.submitted ) { // … processing form, mutating the system state… } </cfscript> <cfoutput> <cfif form.submitted> <p> <mark>Thank you for your submission</mark>! </p> </cfif> <!— REAL form submission. —> <form method="post" action="test.cfm"> <input type="hidden" name="submitted" value="true" /> <button type="submit"> Submit Form </button> </form> <!— FAKE (potentially malicious) form submission. —> <p> <a href="test.cfm?submitted=true">Fake Submit</a> </p> </cfoutput>

As you can see, both the <form> and the <a> are attempting to "submit" to the URL, test.cfm?submitted=true ; but, when we go to process the request, we are only looking at the form scope for the submitted flag. As such, we are implicitly testing the HTTP method:

Note that the "Thank you" message is only rendered during a POST request and not during the GET request. By using the appropriate

ColdFusion
PRODUCT

scope, we’ve implicitly validated the request method.

In many of the

ColdFusion
ORG

web frameworks, however, the URL and FORM scopes are combined into a single "request context". So, instead of explicitly referencing the URL and FORM scopes, you rely on a generated scope, such as rc (for "request context").

Since this rc scope is populated by both the URL and FORM scopes, it means that "post" data can easily be provided by a "get" request. What follows is the same

ColdFusion
ORG

code as above, only we’re replacing form. with rc. :

<cfscript> // Mocking out a common framework approach in which the FORM and URL scopes are // combined into a single "request context" scope. rc = structNew() .append( url ) .append( form ) ; // ——————————————————————————- // // ——————————————————————————- // // In this version, the

SUBMITTED
ORG

value is observed in the RC scope, which means that // it can provided either through the URL or the FORM scope. As such, we

CANNOT
PERSON

be // confident about the current HTTP method. param name="rc.submitted"

type="boolean
NORP

" default=false; if ( rc.submitted ) { // … processing form, mutating the system state… } </cfscript> <cfoutput> <cfif rc.submitted> <p> <mark>Thank you for your submission</mark>! </p> </cfif> <!— REAL form submission. —> <form method="post" action="test2.cfm"> <input type="hidden" name="submitted" value="true" /> <button type="submit"> Submit Form </button> </form> <!— FAKE (potentially malicious) form submission. —> <p> <a href="test2.cfm?submitted=true">Fake Submit</a> </p> </cfoutput>

Now that the rc scope is pulling data from both the URL and FORM scopes, both methods can trigger a "form submission":

As you can see, when we switch to the unified rc scope, we no longer get the implicit validation of the HTTP method. Which means, both the GET and POST requests can trigger the "form processing" workflow.

At this point, we have to move from an implicit validation to an explicit validation. Which means, actually asserting that the incoming request is using the expected HTTP method / verb. And, for that, we can look at the CGI scope, which contains the current request method:

<cfscript> // Mocking out a common framework approach in which the FORM and URL scopes are // combined into a single "request context" scope. rc = structNew() .append( url ) .append( form ) ; // ——————————————————————————- // // ——————————————————————————- // // In this version, the

SUBMITTED
ORG

value is observed in the RC scope, which means that // it can provided either through the URL or the FORM scope. As such, we

CANNOT
PERSON

be // confident about the current HTTP method. param name="rc.submitted"

type="boolean
NORP

" default=false; if ( rc.submitted ) { // Since the

SUBMITTED
ORG

value might be coming through via a MALICIOUS GET, we need // to validate / assert that the request method is a

POST
LOC

. Since any non-POST is // considered malicious in this context, we don’t need to "recover gracefully" – // protecting the system is the priority, the user experience (UX) is not. assertHttpMethod( "POST" ); // … processing form, mutating the system state… } // ——————————————————————————- // // ——————————————————————————- // /** * I assert that the current HTTP request is using the given method. If so, this * function quietly returns; if not, an error is thrown in order to protect the system. */ public void function assertHttpMethod( required string method ) { if (

cgi.request_method
NORP

== method ) { return; } throw( type = "Forbidden.

MaliciousRequest
ORG

", method = "

Invalid
WORK_OF_ART

HTTP method used in request.", detail = "Expected method: [

#method#
MONEY

], actual method: [

#cgi.request_method#
MONEY

]." ); } </cfscript> <cfoutput> <cfif rc.submitted> <p> <mark>Thank you for your submission</mark>! </p> </cfif> <!— REAL form submission. —> <form method="post"

action="test3.cfm
NORP

"> <input type="hidden" name="submitted" value="true" /> <button type="submit"> Submit Form </button> </form> <!— FAKE (potentially malicious) form submission. —> <p> <a href="test3.cfm?submitted=true">Fake Submit</a> </p> </cfoutput>

As you can see, this time, inside the form processing block, we examine the

cgi.request_method
NORP

and make sure that it actually contains the HTTP method that we need. And, if it doesn’t, we throw an error and halt the current request processing control flow:

The explicit check is more verbose; but, it’s also more flexible. When we implicitly validate the request via the

URL
ORG

and FORM scopes, we can really only differentiate between the GET and POST methods. However, when we add an explicit HTTP request method check, we can start to differentiate between all the HTTP verbs (including

PUT
ORG

,

PATCH
ORG

,

DELETE
ORG

, OPTIONS , HEAD , etc).

Aside: Throwing an error might seem a bit heavy-handed. But, keep in mind that we’re validating against an unexpected / malicious invocation. Recovering "gracefully" isn’t necessary as this pathway isn’t something a normal user should ever experience.

An Eye on Security

It’s worth quickly discussing why it is (or, can be) dangerous to allow GET routing to invoke state mutation. While

POST
ORG

and

DELETE
ORG

requests typically involve the user explicitly initiating an action, GET requests can be triggered "on the sly" using something like an <img> source. Unvalidated HTTP methods allow a "bad actor" to craft GET requests for an unsuspecting victim:

<img src="/some/malicious/request" />

While this src attribute may not point to a valid image, it won’t matter – the browser will still make the GET request on behalf of the victim. And, if the target server allows this GET request to mutate the system, the "bad actor" will be able to make malicious requests to the system by proxy.

Enforcing the HTTP method isn’t a solve-all; but, it is

one
CARDINAL

part in a multi-prong security effort.

One
CARDINAL

-time use form tokens,

XSRF
ORG

(Cross-Site Request Forgery) tokens,

Content Security Policy
ORG

(

CSP
ORG

), and SameSite cookie settings are all additional mechanics that can be added on top of the HTTP method validation to help create a secure

ColdFusion
ORG

application.

Want to use code from this post? Check out the license.

Enjoyed This Post? ❤️ Share the Love With Your Friends! ❤️ Tweet This Fascinating post by @BenNadel – Enforcing The HTTP Request Method In

ColdFusion https://www.bennadel.com/go/4525

ORG