BoxLang 🚀 A New JVM Dynamic Language Learn More...
A module that protects you against CSRF attacks by generating unique FORM/client tokens and providing your ColdBox application with new functions for verifying these tokens.
Even though every CFML engine offers these functions natively, we have expanded them and have made them more flexible and more secure than the native CFML functions.
cbauth
login and logout operationscbStorages
to store your tokens in CacheBox, which can be easily distributed and clusteredkeys
rc
or headersApache License, Version 2.0.
Use CommandBox to install
box install cbcsrf
You can then continue to configure the module in your config/Coldbox.cfc
.
Below are the settings you can use for this module. Remember you must create the cbcsrf
struct in your ColdBox.cfc
under the moduleSettings
structure:
moduleSettings = {
cbcsrf : {
// By default we load up an interceptor that verifies all non-GET incoming requests against the token validations
enableAutoVerifier : false,
// A list of events to exclude from csrf verification, regex allowed: e.g. stripe\..*
verifyExcludes : [
],
// By default, all csrf tokens have a life-span of 30 minutes. After 30 minutes, they expire and we aut-generate new ones.
// If you do not want expiring tokens, then set this value to 0
rotationTimeout : 30,
// Enable the /cbcsrf/generate endpoint to generate cbcsrf tokens for secured users.
enableEndpoint : false,
// The WireBox mapping to use for the CacheStorage
cacheStorage = "CacheStorage@cbstorages",
// Enable/Disable the cbAuth login/logout listener in order to rotate keys
enableAuthTokenRotator : false
}
};
This module also relies on the cbstorages module which also requires a structure in moduleSettings
. Find the updated documentation here: https://github.com/coldbox-modules/cbstorages#settings
This module will add the following UDFs into any framework files:
csrfToken()
: To generate a token, using the default
or a custom keycsrfVerify()
: Verify a valid token or notcsrf()
: To generate a hidden field (csrf
) with the tokencsrfField()
: To generate a hidden field (csrf
) with the token, force new token generation and include javascript that will reload the page if the token expirescsrfRotate()
: To wipe and rotate the tokens for the userHere are the method signatures:
/**
* Provides a random token and stores it in the coldbox cache storages. You can also provide a specific key to store.
*
* @key A random token is generated for the key provided.
* @forceNew If set to true, a new token is generated every time the function is called. If false, in case a token exists for the key, the same key is returned.
*
* @return csrf token
*/
string function csrfToken( string key='', boolean forceNew=false )
/**
* Validates the given token against the same stored in the session for a specific key.
*
* @token Token that to be validated against the token stored in the session.
* @key The key against which the token be searched.
*
* @return Valid or Invalid Token
*/
boolean function csrfVerify( required string token='', string key='' )
/**
* Generate a random token and build a hidden form element so you can submit it with your form
*
* @key A random token is generated for the key provided.
* @forceNew If set to true, a new token is generated every time the function is called. If false, in case a token exists for the key, the same key is returned.
*
* @return HTML of the hidden field (csrf)
*/
string function csrf( string key='', boolean forceNew=false )
/**
* Generate a random token in a hidden form element and javascript that will refresh the page automatically when the token expires
* @key A random token is generated for the key provided. CFID is the default
* @forceNew If set to true, a new token is generated every time the function is called. If false, in case a token exists for the key, the same key is returned.
*
* @return HTML of the hidden field (csrf)
*/
string function csrfField( string key='', boolean forceNew=false )
/**
* Clears out all csrf token stored
*/
function csrfRotate()
The module also registers the following mapping in WireBox: @cbcsrf
so you can call our service model directly.
By default, the module is configured to rotate all user csrf tokens every 30 minutes. This means that every token that gets created has a maximum life-span of {rotationTimeout}
minutes. If you do NOT want the tokens to EVER expire during the user's logged in session, then use the value of 0
zero.
It is recommended to rotate your keys often, in case your token get's compromised.
We have provided several methods to rotate or clear out all of a user's tokens. If you are using cbAuth
as your module of choice for authentication, then we will listen to logins and logouts and rotate the keys for you if you turn on the enableAuthTokenRotator
setting.
If you are NOT using cbAuth
then we recommend you leverage the csrfRotate()
mixin or the cbsrf.rotate()
method on the @cbsrf
model.
function doLogin(){
if( valid login ){
// login user
csrfRotate();
}
}
function logout(){
csrfRotate();
}
Below is a simple example of manually verifying tokens:
component {
any function signUp( event, rc, prc ){
// Store this in a hidden field in the form
prc.token = csrfToken();
}
any function signUpProcess( event, rc, prc ){
// Verify CSFR token from form
if( csrfVerify( rc.token ) {
// save form
} else {
// Something isn't right
relocate( 'handler.signup' );
}
}
}
We have included an interceptor that if loaded will verify all incoming requests to make sure the token has been passed or it will throw an exception.
The settings for this feature are:
enableAutoVerifier : true,
// A list of events to exclude from csrf verification, regex allowed: e.g. stripe\..*
verifyExcludes : [
]
You can also register an array of regular expressions that will be tested against the incoming event and if matched, it will allow the request through with no verification.
The verification process is as follows:
get,options or head
skip verificationverifyExcludes
setting, then skip verificationskipCsrf
annotation, then skip verificationrc.csrf
exists and no x-csrf-token
header exists, throw a
TokenNotFoundException
exceptionTokenMismatchException
exceptionPlease note that this verifier will check the following locations for the token:
rc
) via the cbcsrf
keyx-csrf-token
) keyPlease note that you can bypass the CSRF token verifier if you can call your events via the GET
operation and passing the rc
variables via the query string. In order to avoid this, you will have to make sure your events are NOT allowed GET
operations. You can do this in two ways:
this.allowedMethods
handler action security: https://coldbox.ortusbooks.com/the-basics/event-handlers/http-method-securityskipCsrf
AnnotationYou can also annotate your event handler actions with a skipCsrf
annotation and the verifier will also skip the verification process for those actions.
component{
function doTestSave( event, rc, prc ) skipCsrf{
}
}
/cbcsrf/generate
EndpointThis module also allows you to turn on the generation HTTP endpoint via the enableEndpoint
boolean setting. When turned on the module will register the following route: GET /cbcsrf/generate/:key?
. You can use this endpoint to generate tokens for your users via AJAX or UI only applications. Please note that you can pass an optional /:key
URL parameter that will generate the token for that specific key.
This endpoint should be secured, so we have annotated it with a secured
annotation so if you are using cbSecurity
or cbGuard
this endpoint will only be available to logged in users.
Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp www.ortussolutions.com
Because of His grace, this project exists. If you don't like this, then don't read it, its not for you.
"Therefore being justified by faith, we have peace with God through our Lord Jesus Christ: By whom also we have access by faith into this grace wherein we stand, and rejoice in hope of the glory of God. And not only so, but we glory in tribulations also: knowing that tribulation worketh patience; And patience, experience; and experience, hope: And hope maketh not ashamed; because the love of God is shed abroad in our hearts by the Holy Ghost which is given unto us. ." Romans 5:5
"I am the way, and the truth, and the life; no one comes to the Father, but by me (JESUS)" Jn 14:1-12
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
box.json
enableAuthTokenRotator
which defaults to false, unlike previously which was true. This allows for rotation of keys for csrf tokens on login and logout if you are using cbauth via the new interceptor: AuthRotator
. Make sure you turn this flag to true to keep the previous version functionality.cacheStorage
actionMarkedToSkip()
returns false
when the handler is emptycsrfField()
to generate a self linking field and JS but forces a new token and adds a block of javascript to the document, synchronized with the rotateTimeout
setting, that will reload the page if the token expires.defaultValue
in case it's passed as an empty stringcbStorages
dependency to allow for distributed caching of tokenscbauth
to rotate tokens via login/logout methods
$
box install cbcsrf