Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
CommandBox's web server supports enabling Basic Auth on your sites.
That will create the following data in your server.json
, which will be picked up the next time you start your server.
If there is no authPredicate
set, basic auth with secure ALL PAGES on the site. Once you set an authPredicate
, only the pages matching the predicate will require authentication.
The old setting location for Basic Auth (web.basicAuth
) will STILL WORK until the next major version of CommandBox, but should be considered deprecated. If both the settings exist (Ex: web.basicAuth.enable
and web.security.basicAuth.enable
), the new location will be given precedence.
CommandBox has profiles you can assign to a server when you start it to configure the default settings. This is to provide easy secure-by-default setups for your production servers, and to make it easier to switch between a development mode and production mode.
There are 3 currently supported profiles. Custom profiles will be added as a future feature.
Production - Locked down for production hosting
Development - Lax security for local development
None - For backwards compat and custom setups. Doesn't apply any web server rules
You can set the profile for your server in your server.json
Which create this property
Or you can specify it when starting the server like so:
If a profile is not set, these rules are used to choose the default value:
If there is an env var called environment
, it is used to set the default profile (same convention as ColdBox MVC)
If the site is bound on localhost
, default the profile to "development". Localhost is defined as any IP address starting with 127.
If neither of the above are true, the default profile is "production". This makes CommandBox servers secure by default.
When profile is set to "production", the following defaults are provided:
web.directoryListing
= false
web.blockCFAdmin
= external
web.blockSensitivePaths
= true
web.blockFlashRemoting
= true
When profile is set to "development", the following defaults are provided:
web.directoryListing
= true
web.blockCFAdmin
= false
web.blockSensitivePaths
= true
web.blockFlashRemoting
= true
When profile is set to "none", the following defaults are provided:
web.directoryListing
= false
web.blockCFAdmin
= false
web.blockSensitivePaths
= false
web.blockFlashRemoting
= false
The defaults above only apply if you do not have am explicit server.json
or server.defaults
config setting. If you have an explicit setting, it will override the profile's default. Therefore, if you set the profile
toproduction
but set web.blockCFAdmin
to false
, your CF administrator will be public, but the remaining production defaults will still be applied. This allows even the default profiles to be customizable.
It is common to protect pages on your site through your CF code that runs on every request. This does not protect static files like images, plus it can still expose extra surface area of your site for attack. CommandBox has a security system to block certain paths on your site at the web server level, so these requests never reach CF.
There are currently two authentication mechanisms you can enable in CommandBox. Any combination of them can be used to secure the protected portions of your site. When CommandBox determines that the current page requires authentication, it will check each enabled auth mechanism until it finds one that can validate the user.
Basic Authentication is built on a simple username/password list and challenges the user to provide credentials in their browser. Read more here
Client Cert auth is common for internal government sites and involves the user installing a private certificate on their PC which the server asks the browser to send while negotiation the SSL connection. Client certs are a PKI cert, and often times are stored on a CAC which is a physical card issued to the user. Read more here
There are more auth mechanisms we will add in the future including Digest Auth, Header Auth, and SSO. Contact us if you're wanting to sponsor any of these.
If you do not provide an auth predicate but you enable at least one auth mechanism, ALL PAGES on the entire site will be secured. This is quite secure, but often times you only want to protect a subfolder such as /CFIDE/administrator
or /lucee/admin
.
To limit the scope of what pages required authentication, you can specify an auth predicate, which follows the same syntax as Server Rules.
We don't recommend using path()
or path-prefix()
as they are not case sensitive, which can lead to them being easily worked around if you are on Windows. Even regex()
is case-sensitive by default. Only use a case sensitive predicate matcher if your file system and web server are set to be case sensitive! If your server is case sensitive, then the example above can be simplified to this:
The most common auth predicates match a subfolder, but you are not limited to this. Anything valid in a server rule predicate can be used here, including HTTP method, headers, remote IP, etc.
CommandBox servers have a method of locking down secure URLs and or implementing any of the Undertow predicate and handlers via a nice text based language. Undertow supports a “predicate language” that allows a string to be parsed into a graph of predicates (conditions) and handlers (actions to take). Ex:
These rules can be used for any of the following:
Security - Block paths, IPs, or users
URL rewrites - Rewrite incoming URLs to something different
Modifying HTTP requests on the fly - Set headers, cookies, or response codes
Much of this functionality overlaps with the existing Tuckey-based rewrites in CommandBox, but this functionality is built directly into Undertow, has a more streamlined syntax, and allows for easier ad-hoc rules to be layered into a server that allows for you to have custom rules layered on top of built in rules. It can be used to replace what Tuckey does, or added on top.
If you have Tuckey rewrites enabled AND use the Undertow predicate-based server rules, the server rules will fire BEFORE the Tuckey rewrites.
Unlike custom Tuckey-based rewrites that must be placed in a single XML file, server rules can be provided ad-hoc in a variety of locations. They are combined and passed to the server in the order defined. This allows you to easily "layer" custom rules along with out-of-the-box lockdown profiles.
For maximum configuration options, the following mechanisms are supported for specifying the rules for a given server. Rules are processed in the order listed. i.e., a rule defined in your server.json
is processed prior to a rule in your server.default
config setting.
Ad-hoc rule array in server.json
External rules files in server.json
in the order defined
Ad-hoc rule array in config setting server.defaults
External rules files in config setting server.defaults
in the order defined
CommandBox built-in rules (web.blockCFAdmin
, web.blockSensitivePaths
)
Any module listening to server interceptions can inject their rules wherever they please in the array.
server.json
RulesYou can specify ad-hoc rules in the web.rules
property as an array of strings in your server.json
as well as specify one or more external rule files in the web.rulesFile
property as an array or list of file glob patterns.
External rule files with a .json
suffix will be expected to be a valid JSON file containing an array of strings. Ex:
External rule files with any extension OTHER than .json
will be expected to be a raw text file with one rule per line. Emtpy lines are ignored and the rules are processed in the order defined.
Rules specified directly in the server.json
or in an external JSON file must be escaped for the JSON they are a part of. Using a plain text external file can help readability since no additional escaping is required for the rules.
server.defaults
RulesLike all other config server defaults, they follow the same pattern as the server.json
file.
You can comment out any rule (whether it's in JSON or a text file) by proceeding it with a pound sign (#
).
CommandBox allows you full control over the servers you start. This includes the port and host, custom JVM args, URL rewriting, web aliases, custom error pages, and custom welcome files.
Configuration can be set at several different levels:
Passed as parameters to the server start
command
Stored in a server.json
file for that server
Global defaults in the server.defaults
config setting
Internal defaults from the ServerService
Settings will be used in that order. Also, any parameters passed to the start
command will automatically be saved to your server.json
file unless you pass the --noSaveSettings
flag.
A lot of settings used to start a server involve file paths. Paths starting with a drive letter like C:/
, a UNC network path like \\
, or a leading slash like /
are considered absolute paths and will not be expanded. Try to avoid absolute paths if you want to make your server config portable.
Paths that start with a file/folder name like foo/bar.jar
or ../../lib/my.jar
are relative and the root folder that they are relative to depends on where there are specified.
If the path is passed as a parameter to the start command, the path is relative to the current working directory
If the path is in the server.json
file, it is relative to the folder containing the JSON file. (Remember the server.json
doesn't have to be in the web root!)
If the path is in a global server.defaults
config setting, it is relative to the web root of the server.
Client Cert Authentication is common for internal government sites and involves the user installing a private certificate on their PC which the server asks the browser to send while negotiation the SSL connection. Client certs are a PKI cert, and often times are stored on a CAC which is a physical card issued to the user.
It is a requirement that the user hit your site via SSL in order for their browser to send their client cert OR for you to opt into accepting upstream client cert HTTP headers from a proxy or web server that is negotiating your SSL connection. It is recommended you configure your server to either disable HTTP or automatically redirect all HTTP traffic to HTTPS, which can be enabled with the web.SSL.forceSSLRedirect
setting.
Configuring your SSL connection to accept or require client certs is covered in the SSL Client Cert portion of the docs. It's important to note configuring your server to accept SSL client certs and using these certs to authenticate a user two different things. It's possible to accept (or even require) your client (browser) to send a client cert in your web.ssl.clientCert
settings but not use the authentication mechanism to protect parts of your site automatically. Any time a browser has sent a client cert, you will be able to access those details from the CGI
and request
scopes to do your own custom authentication. It is also possible to use Client Cert authentication but not have.
If you have configured your SSL Client Cert settings to accept, but not require client certs, this will allow a user to visit your site and not be challenged to provide a cert until they hit a page that your authPredicate
kicks in and requires authentication. Only then will the user's browser prompt them for a cert.
SSL Renegotiation, when enabled, will disable HTTP/2 AND TLSv1.3. Both of these are not compatible with SSL Renegotiation.
Even if CommandBox is not using SSL directly, but is sitting behind a proxy or web server that takes care of negotiating the client cert, you can still use client cert auth to protect pages on your site if you configure CommandBox to trust any SSL_CLIENT_CERT
HTTP request header.
Only enable this setting if you TRUST your upstream proxy and you know it will overwrite any potentially-malicious SSL_CLIENT_CERT
header from the client. SSL Certs received through this header will appear in the CGI
and request
scope and will be trusted the same as a client cert directly negotiated through CommandBox, but there will be NO trust chain verification. The header will be trusted blindly from your upstream server. This setting is off by default.
You can enable the client cert auth mechanism like so:
Once enabled, all pages on your site will be secured if you have no authPredicate
configured. Otherwise, only pages that match the predicate will be secured.
By default, when you enable client cert auth, CommandBox simply checks that some client cert is present. Remember, your SSL settings require you to provide a Trust Store or a list of trusted root CAs and only client certs which are trusted by one of those CAs will be negotiated. This may be enough security for you right there if you are only allowing certs signed/trusted by a specific root cert. The client cert trust store requires you to explicitly provide every single CA you want trusted. It does NOT use your Operating system's trust store, nor does it use Java's trust store, nor does it use Lucee Servers.
If a request is authorized via a client cert, the Subject distinguished name of the client cert will be present in cgi.remote_user
just like basic auth works.
You can filter down a subset of client certs you want to be accepted for client cert auth by specifying a full or partial subject DN. This will not limit the certs which are negotiated and appear in the CGI
scope. It will only limit the certs which are allowed to provide authentication for pages secured by the authPredicate
. A Subject Distinguished Name (SDN) contains one or more parts known as Relative Distinguished Names, or RDNs. They follow an LDAP name RFC and look like this:
You may provide a single Subject DN ...
or an array of Subject DNs to filter on...
The RDNs can be in any order and you can supply a PARTIAL Subject DN. CommandBox will match all RDNs regardless of order or case sensitivity. You are not required to provide the full Subject DN, but all RDNs you provide MUST be present in the incoming cert or it will be rejected.
You can also filter down a subset of client certs you want to be accepted for client cert auth by specifying a full or partial Issuer DN. This will not limit the certs which are negotiated and appear in the CGI
scope. It will only limit the certs which are allowed to provide authentication for pages secured by the authPredicate
. An Issuer Distinguished Name (IDN) look and work the same as Subject DNs.
You may provide a single Issuer DN ...
or an array of Issuer DNs to filter on...
The RDNs can be in any order and you can supply a PARTIAL Issuer DN. CommandBox will match all RDNs regardless of order or case sensitivity. You are not required to provide the full Issuer DN, but all RDSs you provide MUST be present in the incoming cert or it will be rejected.
If you require more specific parsing of the cert pieces, then you’ll need to disable the built in security in CommandBox and write your own code that runs on every request and parses the CGI variables manually to decide if you accept the cert.
server.json
ConfigurationHere is a look at what your full config could look like in your server.json
. Note this doesn't show the web.ssl.clientCert
settings which are covered here.
There are endless combinations of predicates and handlers you can apply to your apps. Here's an assortment of examples to get you going. Many of these are contrived, but are just mean to show the range of syntax and functionality.
Rewrite a URL:
Stop processing rules for a given request:
For all GET requests, set a response header called type
with a value of get
If the incoming path ends with .css
it will rewrite the request to .xcss
and set a response header called rewritten
to true
.
Redirect all jpg requests to the same file name but with the png extension. The ${1}
exchange attribute is used to reference the first regex group.
Set a request header for all requests that you can access in your CFML app just like a normal HTTP header.
Set a Cache-Control response header only for default index pages(ie: index.html or index.cfm) in any folder.
Set a response header for a specific file.
Match certain SES-style URLs and store the place holders (referenced as exchange attributes) into HTTP request headers.
In this example, hitting the server with /restart
skips the first rule, the second rule rewrites the request and then restarts back at the first rule which fires the second time through.
Block access to a URL unless coming from a specific IP.
For more control over IP address matches, use the ip-access-control()
handler.
Leading slash is NOT required. Both of these rules are the same:
It is not required to include .*
_ at the end of a regex path unless you’ve set full-match=true
_
Perform a regex a case insensitive search like so:
When attribute values are not quoted, all leading and trailing whitespace will be trimmed. The following are all the same:
But this example is different. The leading and trailing spaces will be preserved in the path string.
Basic MVC rewrite:
Add a CORs header to every request
Rewrite requests to a sub folder based on the domain
Custom SES URL rewrite that turns 6 digit product code into a query string. (If this rule goes in your server.json
, you'll need \\
in front of the dollar sign to escape it twice. Once for the system setting expansion and once for the JSON file.)
Reject requests using an unknown host header.
Create reverse proxy
CommandBox has a few baked in rules that you can apply ad-hoc or as part of a server profile
.
web.blockCFAdmin - Returns 404 error page for any Adobe CF or Lucee Server admin administrator paths
web.blockSensitivePaths - Returns 404 error page for common config files such as box.json
or .env
web.blockFlashRemoting - Blocks all paths related to Flash and Flex remoting calls
If you want to customize the rules above, simply turn them off and include the rules directly in your server.json
where you can modify them as you see fit.
This setting has three possible settings:
true - Block ALL access to ColdFusion and Lucee admins
false - Do not block anything
external - Only block access not coming from localhost.
The exact rule activated when you set this property to true
is:
The exact rule activated when you set this property to external
is:
This setting only allows true
/false
. This is a bit of a catch-all rule for any sort of paths that a user should never be able to make on production that could reveal information or access secret parts of your CF installation. When set to true
, the following rules are activated:
When the profile
is set to production
, the following rule is also added which blocks the ColdFusion RDS access from CF Builder and access to TestBox runners:
If you need to legitimately access any of these paths, you'll need to turn off this setting and custom-add the rules that you want to keep. This setting is a convenience that adds several rules at once.
This setting only allows true
/false
. When set to true
, the following rules are activated:
If you need to legitimately access any of these paths, you'll need to turn off this setting and custom-add the rules that you want to keep. This setting is a convenience that adds several rules at once.
What if you want to go one step deeper? For instance, the blockSensitivePaths
setting blocks a whole bunch of stuff all in one shot. An example might be wanting to open up JUST the RDS IDE integration for your developers, which funnels through the /CFIDE/main/ide.cfm
path which you can see is blocked above.
The solution to this is quite simple and is all based on the ORDER in which your rules are processed. Built-in CommandBox rules are the last to process. This means that if you hijack the predicates with a custom rule FIRST, you can override the behavior of the built in rules. So, if we want to allow access to the /CFIDE/main/ide.cfm path, we just need to add a custom rule that matches that path and then aborts the predicate chain so no further rules fire.
Which gives you the following server.json
The done
handler is what bypasses all subsequent rules for the request.
Since your custom rules are processed BEFORE the built-in rules, that also means that you have the ability to accidentally bypass security rules by applying another rule that intercepts the request! By default a custom rule won't block subsequent rules from firing unless you rewrite the request or use the special done
handler.
CommandBox bundles some custom predicates and handlers to make your life easier.
The predicate cf-admin()
will returns true
if the incoming URL is to the Lucee or ColdFusion admin:
The handler block-external()
blocks any request not from localhost with a 404 response code. You can pair this with any predicate you choose.
The handler block-cf-admin()
blocks any request to the Lucee or ColdFusion admin with a 404 response code.
You can build your own predicates and handlers by compiling java classes that implement the io.undertow.predicate.PredicateBuilder
or io.undertow.server.handlers.builder.HandlerBuilder
interfaces. If the proper service metadata is present in your jar's META-INF folder, undertow will automatically find and register your builders via Java's service loader.
This isn't super difficult but involves a few moving parts. If you're interested in writing your own handlers and predicates to use in your server rules, reach out on the mailing list and we'll walk you through it.
You can see the custom handlers and predicates documented above in our Runwar source code here:
Custom handlers:
Custom Predicates:
And to test/debug your rules, start your server with the trace flag and tail the console output. Every hit in your browser will output several lines of debugging for each rule that is processed.
With the custom rule above, you'd see something like this:
The start
command will scan your system and find a random port that is not currently in use to start the server on. This ensures that multiple embedded servers can run at the same time on the same host without collisions. Ensure any redirects in your applications take the port into account.
You may want to set a specific port to use-- even port 80 if nothing else is using it. Pass the HTTP port parameter to the start command like so:
It is also possible to save the default port in your server.json
. Add a web.http.port
property, or issue the following command:
Now every time you start
your server, the same port will be used.
If the server won't start or is unreachable, make sure it's port is free with your operating system's netstat
command. On Unix-based OS's:
You can start your server to listen for SSL connections too.
You can customize what SSL protocols your HTTPS listener will respond to with the following XNIO option. Supply a comma-delimited list of valid protocols.
HTTP/2 is a newer standard of HTTP supported by all modern browsers. HTTP/2 is enabled by default any time you are using an HTTP/HTTPS listener, however all major browsers will only allow the server to negotiate HTTP/2 over an HTTPS connection. HTTP/2 runs over the same port and only changes the exchange between the server and browser. You can disable HTTP/2 support like so:
If you want to confirm whether your browser is using HTTP/2, you can open your debugging tools and look at the network requests. You may need to add the "protocol" column in the UI. HTTP/2 will usually show up as something like "h2" in the protocol column.
You can start your server to listen for AJP connections too.
CommandBox's AJP listener (provided by Undertow) is already protected against the Ghostcat vulnerability. However, if you would like to set up an AJP secret as well to ensure all requests coming into the AJP listener are from a trusted source, you can do by setting the web.ajp.secret
property.
For this to work, you must also configure your AJP proxy in your web server to send the same secret! For requests received to the AJP listener which do not contain the secret, a 403
status code will be returned. You can customize the output of the 403 page via the Error Pages settings.
The AJP secret is implemented via a Server Rule. Feel free to add your own server rule instead of this setting if you want to customize how it works.
Your application may rely on a specific host name other than the default of 127.0.0.1
. You can set the host to anything you like, but you must add a host
file entry that resolves your host name to an IP address assigned to your network adapter (usually 127.0.0.1)
If you have multiple IP addresses assigned to your PC, you can bind the server to a specific IP using the host
parameter.
A server configuration can only have one host entry. If you require your server to be available on multiple IP addresses of the machine it runs on, you can set the host to 0.0.0.0. This will effectively bind the server to all network interfaces (including local).
Or save in server.json
Most modern browsers allow you to make up any subdomain you want before localhost such as mySite.localhost
and will simply resolve them to localhost
(127.0.0.1
) even without a hosts file entry. CommandBox now supports using these domains and will bind your server's ports to localhost even without using the commandbox-hostupdater
module.
By default, CommandBox will open your browser with the host and port of the server. You can customize the exact URL that opens. This setting will be appended to the current host and port.
Or you can completely override the URL if your setting starts with http://
.
If CommandBox is running a server behind a trusted proxy which is known to set the X-Forwarded-For
HTTP header, then you can enable this setting for the remote IP in your CF engine's cgi
scope to represent the upstream IP.
This is disabled by default. Otherwise a malicious client could send a fake X-Forwarded-For
HTTP header to make it look like their traffic was coming from a trusted IP such as 127.0.0.1
to bypass any IP-based restrictions. Only enable this if you trust the proxy CommandBox is sitting behind. This should never be enabled if CommandBox is directly accessible on the internet.
Enable for all servers like so:
Turning on SSL in your web server will will enable SSL without an approved SSL certificate. If you need an official certificate so you don't have to confirm your SSL connection you can add these entries
The cert file and private key can be a PEM encoded file, or a DER-format binary file.
You can also use a PFX file (PKCS #8) by specifying it in the web.ssl.certFile
setting and then put the password for the PFX file in the web.ssl.keyPass
setting. You won't use the web.ssl.keyFile
setting for a PFX since the private key is contained in the main file.
Although free certificates are available (e.g LetsEncrypt) this is not very convenient, because these certs are valid only for three months. Automatic renewal it is difficult if your dev site is not accessible from the web. For a few dollars a year (< 10) you can apply for a domain validated certificate from companies like Comodo, RapidSSL, Trustwave, Digicert, Geotrust and others or a reseller for these certs. For a domain validated certificate you need a valid domain which is under your control which means (depending on provider):
mail is sent to domain owner
or mail is sent to well-known administrative contact in the domain, e.g. (admin@, postmaster@, etc.)
or you can publish a DNS TXT record
So, now you have a valid domain, you have to generate a SSL key and a SSL Certificate Signing Request. With the CSR you can apply for the certificate. Generating a key and CSR with openSSL
This will generate output and some questions, and will finally result in a key file named dev_mydomain_com.key
and a certificate signing request (csr) named dev_mydomain_com.csr
You have to enter Country Name, State and City. Organization Name is preferably the same as the domain owner. Organizational Unit Name will not be checked, so enter something simple such as ICT Common Name is the host name for your site, such as dev.mydomain.com
You can skip Email Address and optional company name. For development you don't need a challenge password, which means your key file is NOT protected. But don't give this key to others or protect it with a challenge password. If you protect your key you have to server set web.SSL.keyPass=MyChallengePassword
Now you have a CSR, which you can submit at your SSL provider. They will send you a certificate file (*.csr), and probably one or more intermediate certificates. Create a new my.csr
file and copy everything from your certificate file into it, and append the intermediate certificate(s). Now you have a valid my.csr
certificate file and a key file. Place both files in a location accessible for your CommandBox and enter the corresponding paths to web.SSL.certFile
and web.SSL.keyFile
Accepting a client cert as part of the SSL negotiation is a totally separate idea as using the existence of a client cert to authorize a given request. This is why the settings are in two different place in the server.json
. You can have CommandBox ask (or require!) the browser to hand over a client cert, but all that does is set a bunch of CGI variables and servlet request attributes to document what the incoming cert is. The same client cert details can also be passed from an upstream proxy which negotiated the SSL connection and the details can be sent via HTTP headers to CommandBox to use for request authorization. Therefore, CommandBox can enable client certs at the SSL level and NOT enable request authorization, or it can disable its own SSL client cert negotiation but still perform request-level authorization based purely on upstream headers. The two features are not mutually dependent. To read how to have CommandBox automatically protect portions of your site based on a client cert, read here.
To enable client certs to be negotiated by CommandBox SSL must be enabled, and then web.ssl.clientCert.mode
can be set to one of the following options:
NOT_REQUESTED - (default) SSL client authentication is not requested. (same as “ignore” in IIS)
REQUESTED - SSL client authentication is requested but not required. (same as “request” in IIS)
REQUIRED - SSL client authentication is required. (same as “require” in IIS)
CommandBox will NOT use your OS trust store nor your Java trust store, nor Lucee Server's trust store by default to establish a trust chain for incoming client certs. You must specify the trusted root CA certs that you want trusted. ONLY client certs trusted by one of these CAs will be accepted. Any intermediate certs must also be included. You can specify a comma-delimited list of absolute or relative paths OR an array of strings in the web.ssl.clientCert.CACertFiles
setting that point to any number of public keys in a DER format (typically .crt or .cer extension)
or
If you have a large number of trusted CA’s, you can specify a JKS trust store (same format as Java’s cacerts
file) along with the password for the store in the web.ssl.clientCert.CATrustStoreFile
and web.ssl.clientCert.CATrustStorePass
file. All CAs in that trust store will be used to validate incoming client certs.
The user's browser will ONLY be able to send client certs signed/trusted by one of the CAs you specify. All other certs will be rejected. If your mode is set to REQUIRED, that means your user would never be able to reach any CF pages at all (unless you are using SSL renegotiation which is covered here.
server.json
ConfigurationHere's an example of what your config could look like:
If both a trust store AND individual trusted CA's are provided, CommandBox will use all of them.
If the user's browser sends a client cert which is trusted by one of your trusted CAs, then the details of the cert will be available for Client Cert Authentication as documented here. There are also a number of CGI
and request
variables automatically made available to you any time a client cert was presented. These variables will be available on every page, not just the first page where they select their cert.
When a valid client cert is present, the following CGI
variables will be available to your CF code. If client certs are “requested”, these CGI variables will be wiped from any upstream sources so you can always trust them to be set from CommandBox, even if they are empty. There are several duplicate values since we are mimicking IIS, Apache, and Nginx client cert implementations for maximum compatibility.
CGI.SSL_CLIENT_CERT
- PEM-encoded cert (base 64 string)
CGI.X_ARR_CLIENTCERT
- PEM-encoded cert (base 64 string)
CGI.SSL_CLIENT_S_DN
- The Subject distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.CERT_SUBJECT
- The Subject distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.CERT_KEYSIZE
- The key size of the negotiated SSL connection
CGI.CERT_SERIALNUMBER
- The serial number of the cert in the format 91-7e-5f-a5-b2-20-a1-8b-4c-d0-40-3b-1c-a1-a8-58
CGI.SSL_CLIENT_M_SERIAL
- The serial number of the cert in the format 91-7e-5f-a5-b2-20-a1-8b-4c-d0-40-3b-1c-a1-a8-58
CGI.SSL_CLIENT_I_DN
- The Issuer distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.CERT_ISSUER
- The Issuer distinguished name of the client cert (CN=foo, O=bar, OU=baz)
CGI.SSL_CLIENT_VERIFY
- Matches Apache HTTP. Values will be "SUCCESS" or "NONE"
CGI.SSL_SESSION_ID
- Unique ID of the SSL connection
Note, some of these vars may not appear when you cfdump out the CGI
scope, but will still be available when you specify cgi.var_name
Due to some differences between Adobe ColdFusion and Lucee Server, the above variables are loaded as HTTP Request Headers in Lucee and Servlet Request Attributes in Adobe ColdFusion. You can access them in either engine though through the CGI
scope, but they may be case sensitive (always upper case)
The following servlet request attribute will also be set, which are accessible in a case sensitive manner from both Adobe and Lucee Server request
scopes:
javax.servlet.request.cipher_suite
- The cipher suite of the SSL connection such as TLS_AES_128_GCM_SHA256
javax.servlet.request.key_size
- The key size of the negotiated SSL connection
javax.servlet.request.ssl_session_id
- Unique ID of the SSL connection
javax.servlet.request.X509Certificate
- An array of java.security.cert.X509Certificate
instances representing the certificate chain. These cert objects contain the same data as the PEM-encoded headers.
javax.servlet.request.X509Certificate.issuerDNMap
- A struct containing all the parts of the Issuer distinguished name. So for (CN=foo, O=bar
) there would be a key for CN
and O
in the struct with respective values of foo
, and bar
. USE THIS instead of regex on the full Issuer DN because this map is generated by following the exact RFC for LDAP names.
javax.servlet.request.X509Certificate.subjectDNMap
- A struct containing all the parts of the Subject distinguished name. So for (CN=foo, O=bar
) there would be a key for CN
and O
in the struct with respective values of foo
, and bar
. USE THIS instead of regex on the full Subject DN because this map is generated by following the exact RFC for LDAP names.
Access these request vars like so in CFML
Note using quoted string inside of bracket notation is required not only due to the periods in the variable name, but also to preserve the case-sensitivity of them.
All of the CGI and request vars above can also be present even if CommandBox’s built in client cert negotiation is not enabled if you have PEM-encode headers being sent from your upstream web server. However, you must explicitly tell CommandBox to trust these headers. Only do this if you trust the upstream proxy to always set trusted values into these headers. Enable this by setting the web.security.clientCert.trustUpstreamHeaders
key by setting it to true
. Them CommandBox will look for the SSL_CLIENT_CERT
, SSL_CIPHER
, and SSL_SESSION_ID
HTTP request headers and associate those certs with the request just as though CommandBox had negotiated them itself.
CommandBox allows you to create web aliases for the web server that are similar to virtual directories. The alias path is relative to the folder the server.json
lives in, but can point to any folder on the hard drive. Aliases can be used for static or CFM files.
For compatibility reasons as of version 5.3.0
, relative alias paths can also be relative to the web root, if that is not where the server.json
lives. CommandBox will check if the folder exists relative to the web root FIRST, and if not, it will then check relative to the folder the server.json
lives in.
To configure aliases for your server, create an object under web
called aliases
. The keys are the web-accessible virtual paths and the corresponding values are the relative or absolute path to the folder the alias points to.
Here's what your server.json
might look like.
Here's how to create aliases from the server set
command:
info On Adobe ColdFusion servers, .cfm files will be run automatically from inside an aliases directory. On Railo and Lucee servers, you'll need to create a CF mapping that maps the alias name and path for .cfm files to work.
When using a CommandBox web server in production, you may wish to force your users to visit your site over HTTPS for security (and for HTTP/2 to work). However, it is desirable to still have your web server listening on HTTP so a user just typing your address in his browser can still connect to HTTP and then redirect.
CommandBox can be configured to redirect all HTTP traffic over to HTTPS with the following rule. The redirect will use a 301
status code and will include the URL and query string. The redirect will only fire for GET
HTTP requests since redirecting a form POST
would lose the form fields (request body).
Or in the server.json
as:
If you want to customize how this redirect happens, you can skip this setting and manually add the following , which is basically what the setting above does automatically:
If you want to go one step further, you can add a Strict-Transport-Security
header to your site. This instructs the browser to automatically use HTTPS every time the user visits your site again. With an HSTS header, once your browser has cached the fact that you want HTTPS to always be used, even if the user just types your domain and hits enter, the browser will change it over to HTTPS before sending the request. This prevents having an initial HTTP request before the redirect kicks in.
HSTS headers can have a "max age" set, which tells the browser how long to "remember" to use HTTPS. This defaults to 1 year if you do not override the value. The max age is set in second. So 31,536,000 is one year. You can also set whether you want the HSTS header to apply to all sub domains of your site. The default is false
for this setting.
Here is how you enable HSTS. Only the first web.SSL.HSTS.enable
setting is required. The rest are optional.
Or in the server.json
as:
The HSTS header is added via a . Here is what the rule looks like in case you want to manually add the rule to customize it.
You can customize the error page that CommandBox servers return. You can have a setting for each status code including a default error page to be used if no other setting applies.
Create an errorPages
object inside the web
object in your server.json
where each key is the status code integer or the word default
and the value is a relative (to the web root) path to be loaded for that status code.
This is what you server.json
might look like:
You can set error pages via the server set
command like this:
If your error page points to a CFM file, you can get access to the original path being accessed for 404s and the error that was thrown for 500s. To see all the request headers that are available, use the following snippet of code:
An example of getting the original missing path in a 404 in Lucee would look like this:
In Adobe ColdFusion, you can access ServletRequest
Attributes directly via the CGI scope:
CommandBox will automatically set the content type in the HTTP response for common static file types. If you come across a file extention that doesn't have the correct type, you can set it like so in your server.json
:
Which creates the following
In the above example, hitting a file such as foo.log
would come back with a text/plain
content type header.
This setting will override any <mime-mapping>
tag in your web.xml
file.