ddspringle / framework-one-secure-auth

An example fw/1 application with secure single and two-factor (2FA) authentication and session management functions
Apache License 2.0
31 stars 5 forks source link

FW/1 Secure Authentication Example

This project is an example fw/1 application with secure single and two-factor (2FA) authentication and session management functions. This code was originally put together for the ColdFusion: Code Security Best Practices presentation by Denard Springle at NCDevCon 2015 and has since been transformed into a concise starting point for developers who need to create a secure application using the fw/1 CFML MVC framework.

This code has been expanded multiple times to include additional functionality not shown during the initial presentation. More details on how (and why) these security functions work and are important can be gleaned from reading the ColdFusion Code Security guides on the bottom half of CFDocs and from reviewing the SecurityService.cfc in /model/services/ which has been expanded with comments to help aid in understanding how and why security features have been implemented and should be easy to pick up and run with for anyone with a passing familiarity of CFML and fw/1.

Features and Notes

<cfscript>
    if( !structKeyExists( variables, 'rc' ) ) {
        variables.rc = {};
        structAppend( rc, url );
        structAppend( rc, form, true );
    }

    // set a keyring path
    rc.keyRingPath = expandPath( './keyrings/[ABCDEF0123456789].bin' );
    // set a keyring backup path
    rc.backupPath = rc.keyRingPath & '_BACKUP_' & dateTimeFormat( now(), 'yyyymmddhhnnss' );

    // validate the keyring file exists
    if( !fileExists( rc.keyRingPath ) ) {
        throw( rc.keyRingPath & ': keyring path does not exist!' );
    }

    // backup the existing keyring file
    fileCopy( rc.keyRingPath, rc.backupPath );

    // validate the backup file exists
    if( !fileExists( rc.backupPath ) ) {
        throw( rc.backupPath & ': backup path does not exist!' );
    }

    // load the CTR encrypted keyring from the file
    rc.keyring = charsetEncode( fileReadBinary( rc.keyRingPath ), 'utf-8' );

    // decrypt the keyring with the master key and BLOWFISH/CTR block mode
    rc.roundOne = decrypt( rc.keyring, rc.masterKey, 'BLOWFISH/CTR/PKCS5Padding', 'HEX' );
    rc.roundTwo = decrypt( roundOne, rc.masterKey, 'AES/CBC/PKCS5Padding', 'HEX' );

    // re-encrypt the keyring with the master key and BLOWFISH/CBC block mode
    rc.roundOne = encrypt( rc.roundTwo, rc.masterKey, 'AES/CBC/PKCS5Padding', 'HEX' );
    rc.roundTwo = encrypt( roundOne, variables.masterKey, 'BLOWFISH/CBC/PKCS5Padding', 'HEX' );

    // write the keyring back to disk
    fileWrite( rc.keyRingPath, charsetDecode( rc.roundTwo, 'utf-8' ) );
</cfscript>

Compatibility

Installing

  1. Drop the code into your favorite CFML engine's webroot OR install using CommandBox using the command box install fw1-sa
  2. Create a database and generate the users and smsProviders database tables (MSSQL SQL and Excel data provided in the 'database' folder)
  3. Create a datasource called twofactorauth for your database in your CFML engine's admin (or change in Application.cfc)
  4. Configure an object cache, if one is not already defined (or, optionally, add it to Application.cfc if running Lucee 5.x+)
  5. Configure a mail server in your CFML engine's admin
  6. Move the keyrings folder to a location outside your webroot
  7. Modify the default developmentHmacKey value in Application.cfc (use generateSecretKey( 'HMACSHA512' ))
  8. Change the keyRingPath location to where you moved the keyrings folder to in Application.cfc
  9. Change the hash iterations for the hashed keyring file name from the default value of 173 to some other integer number of iterations in Application.cfc
  10. Provide a unique BASE64 encoded value for the application password in Application.cfc (instead of c2VjdXJlX2F1dGhfbWFzdGVyX2tleQ==)
  11. Provide a unique BASE64 encoded value for the application salt in Application.cfc (instead of UnRUcFBBS1hOQmgwem9XYg==)
  12. Provide a unique BASE64 encoded value for the keyring filename in Application.cfc (instead of c2VjdXJlX2F1dGhfa2V5cmluZw==)
  13. Change the hash iterations for the hashed master key from the default value of 512 to some other integer number of iterations in Application.cfc
  14. Change the starting location for the mid() function of the hashed master key to start at a position other than 38 in a range from 1 to 106
  15. Provide unique values for the cookieName and dummyCookieOne, dummyCookieTwo and dummyCookieThree values in Application.cfc
  16. Modify remaining application variables in Application.cfc as needed (see notes in Application.cfc)
  17. Browse to webroot to launch the application and generate a unique set of encryption keys in your keyring
  18. Modify the check if the keyring is a valid array of keys statement in Application.cfc to prevent regeneration of a new keyring file after initial launch. See notes in Application.cfc.
  19. Register an account, login and enjoy!

Upgrading

NOTE If you are currently running a version of fw1-sa without the 2FA integration, then you'll need to complete the following steps before updating to the latest master branch:

If not using 2FA:

  1. Preserve a copy of your existing Application.cfc (or MyApplication.cfc if included in your distribution) so you can copy values for keyring and other application variables as needed.
  2. Modify your users table to include providerId and phone as additional fields before updating

If using 2FA:

  1. Preserve a copy of your existing Application.cfc (or MyApplication.cfc if included in your distribution) so you can copy values for keyring and other application variables as needed.
  2. Modify your users table as above
  3. Add the smsProviders table and import the included data
  4. Assign sms provider id's and phone numbers to existing users (this must be done before switching 2FA on else users will not be able to authenticate)

Bugs and Feature Requests

If you find any bugs or have a feature you'd like to see implemented in this code, please use the issues area here on GitHub to log them.

Contributing

This project is actively being maintained and monitored by Denard Springle. If you would like to contribute to this example please feel free to fork, modify and send a pull request!

Attribution

This project utilizes the free open source MVC CFML (ColdFusion) framework Framework One (fw/1) by Sean Corfield.

License

The use and distribution terms for this software are covered by the Apache Software License 2.0 (http://www.apache.org/licenses/LICENSE-2.0).