Skip to content

Instantly share code, notes, and snippets.

@bennadel
Created October 24, 2023 12:47
Enforcing The HTTP Request Method In ColdFusion
<cfscript>
// In this version, the SUBMITTED 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>
<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 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 be
// confident about the current HTTP method.
param name="rc.submitted" type="boolean" 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>
<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 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 be
// confident about the current HTTP method.
param name="rc.submitted" type="boolean" default=false;
if ( rc.submitted ) {
// Since the SUBMITTED value might be coming through via a MALICIOUS GET, we need
// to validate / assert that the request method is a POST. 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 == method ) {
return;
}
throw(
type = "Forbidden.MaliciousRequest",
method = "Invalid HTTP method used in request.",
detail = "Expected method: [#method#], actual method: [#cgi.request_method#]."
);
}
</cfscript>
<cfoutput>
<cfif rc.submitted>
<p>
<mark>Thank you for your submission</mark>!
</p>
</cfif>
<!--- REAL form submission. --->
<form method="post" action="test3.cfm">
<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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment