While there is no such thing as 100% secure, you can take specific measures to mitigate against a wide range of attacks and secure your webapp as much as possible.
In this post we discuss some of the steps we’ve taken as part of our efforts to secure our server monitoring tool.
1. Cover the Basics
Before considering any of the suggestions listed here, make sure you’ve covered the basics. Those include industry best practices like protecting against SQL injection, filtering, session handling, and XSRF attacks.
2. Use SSL only
When we launched Server Density in 2009, we offered HTTPS for monitoring agent postbacks but didn’t go as far as to block standard HTTP altogether.
Later on, when we made the switch to HTTPS-only, the change was nowhere near as onerous as we thought it would be.
SSL is often viewed as a performance bottleneck but that isn’t really true. In most situations, we see no reason not to force SSL for all connections right from the start.
Server Density v2 uses a new URL. As part of this, we can force SSL for new agent deployments and access to the web UI alike. We still support the old domain endpoint under non-SSL but will eventually be retiring it.
To get an excellent report on how good your implementation is, run your URL against the Qualys SSL server test. Here is ours:
3. Support SSL with Perfect Forward Secrecy
Every connection to an SSL URL is encrypted using a single private key. If someone obtains that key they can decrypt and access the traffic of that URL.
Perfect forward secrecy addresses this risk by negotiating a new key with every session. A compromise of one key would therefore only affect the data in that one session.
To do this, you need to allow certain cipher suites in your web server configuration.
ECDHE-RSA-AES128-SHA:AES128-SHA:RC4-SHA is compatible with most browsers (for more background and implementation details check out this post).
We terminate SSL at our nginx load balancers and implement SSL using these settings:
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; # prefer RC4-SHA to avoid BEAST ssl_ciphers ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH;
You can easily tell if you're connected using perfect forward secrecy. In Chrome, just click on the lock icon preceding the URL and look for ECDHE_RSA under the Connection tab:
4. Use Strict Transport Security
Forcing SSL should be combined with HTTP Strict Transport Security. Otherwise you run a risk of users entering your domain without specifying a protocol.
For example, typing example.com rather than https://example.com and then being redirected to HTTPS. This redirect opens a security hole because there’s a short time when communication is still over HTTP.
You can address this by sending an STS header with your response. This forces the browser to do the HTTP to HTTPS conversion without issuing a request at all. Instead, it sends the header together with a time setting that the browser stores, before checking again:
Our header is set for 10 years and includes all subdomains because each account gets their own URL, for example: foo.serverdensity.io.
5. Submit STS Settings to Browser Vendors
Even with STS headers in place there’s still a potential hole, because those headers are only sent after the first request.
One way to address this is by submitting your URL to browser vendors so they can force the browser to only ever access your URL over SSL.
You can read more about how this works and submit your URL for inclusion in Chrome. Firefox seeds from the Chrome list.
6. Enforce a Content Security Policy
Of the top 10 most common security vulnerabilities, cross site scripting (XSS) is number 3. This is where remote code is injected and executed on your site, usually through incorrect (or non-existing) filtering.
A good way to combat this is to whitelist the specific remote resources you want to allow. If a script URL is not matched by this list then browsers will block it.
It’s much easier to implement this on a new product because you can start out by blocking everything. You then open specific URLs as and when you add functionality.
Using browser developer tools you can easily see which remote hosts are being called. The CSP we use is:
content-security-policy:script-src 'self' 'unsafe-eval' https://maps.google.com https://*.gstatic.com https://*.googleapis.com https://*.mixpanel.com https://*.mxpnl.com; connect-src 'self' https://maps.google.com https://*.gstatic.com https://*.googleapis.com https://*.mixpanel.com https://*.mxpnl.com; frame-src 'self' https://maps.google.com https://*.gstatic.com https://*.googleapis.com https://*.mixpanel.com https://*.mxpnl.com; object-src 'none'
We have to specifically allow unsafe-eval here, as a number of third party libraries require this. You might not use any third party libraries—or the libraries you do use may not require unsafe eval—in which case you should not allow unsafe-eval.
script-src is a directive that controls a set of script-related privileges for a specific page. For more information on connect-src, script-src and frame-src this is a good introduction on CSP.
Be careful with wildcarding on domains which can have any content hosted on them. For example wildcarding *.cloudfront.net would allow anyone to host any script. This is Amazon’s CDN which everyone can upload files to!
Also note that Content-Security-Policy is the standard header but Firefox and IE only support X-Content-Security-Policy. See the OWASP documentation for more information about the header names and directives.
7. Enable HTTP security headers
You can enable some additional security features in certain browsers by setting the appropriate response headers. While not widely supported, they are still worth considering:
- x-content-type-options is an IE only header which can prevent content sniffing XSS attacks. This is especially useful if you allow user uploaded content.
- x-frame-options can help prevent some click-jacking attacks by stopping your site from being loaded in a frame.
- x-xss-protection is another IE only header to enable some XSS filtering in the browser.
8. Setup passwords, “remember me” and login resets properly
This is the main gateway to your webapp, so make sure you implement all stages of logging-in properly. It only takes a short amount of time to research and design a secure process:
- Registration and login should use salting and cryptographic functions (such as bcrypt) to store passwords, not plain text or MD5 hashing.
- Password reset should use an out-of-band method to trigger resets, for example: requiring a username then emailing a one-time, expiring link to the on-record email address where the user can then choose a new password. Here is more guidance and a checklist.
- "Remember me" functionality should use secure tokens to recognise the user, and not storing their credentials in cookies.
9. Offer Multi Factor Authentication
If your webapp is anything more than a trivial consumer product, you should implement—and encourage your users to use—multi factor authentication.
This requires them to authenticate using something they carry with them (token), before they can log in. An attacker would therefore need both this token (phone, RSA SecurID etc) and user credentials before they obtain access.
We use the Google Authenticator standard because it has authentication apps available for all platforms, and has libraries for pretty much every platform.
It is quite onerous to install a custom, proprietary MFA app so we don’t recommend you implement your own system.
Be sure to re-authenticate for things like adding/removing MFA tokens. We require re-authentication for all user profile changes.
We do however have a timeout in place during which users won’t have to re-authenticate. This timeout applies for simple actions like changing passwords (adding or removing tokens requires authentication even during the timeout).
To sum up, MFA is crucial for any serious application as it’s the only way to protect against account hijacking.
10. Schedule Security Audits
We inspect security as part of our code review and deployment process (many eyes on the code). We also have regular reviews from external security consultants.
We recommend having one firm do an audit, implement their fixes, and then have another firm audit those changes.
Security is all about identifying and mitigating possible risks of attack. The operative word here is mitigation, since new threats are always emerging.
This is an ongoing exercise. Be sure to conduct regular reviews of all existing measures, check for new defence mechanisms and keep abreast of security announcements.