Purple Zest takes security very seriously, and we employ a contractor with many years of experience.

To demonstrate our commitment to security, we check our website is following industry best practices with the following tools:

However, we recognise these tests only cover the basics.

So from a technical point of view, these are the extra steps we take to protect your data:

  • We only store the information we need.

  • Any time a person requests information from our website, it checks that they have permission to do so. This includes preventing people from seeing each others data, and stopping basic accounts from being able to access data/features that they should not be able to (privilege escalation).

  • We always use HTTPS, with a good configuration, to ensure that data is encrypted when it's being sent over the internet.

  • To ensure that browsers always use an encrypted connection, we use the HTTP Strict Transport Security (HSTS) header.

  • We do not store passwords in plain text. This is an extra level of defence just in case our database was to be compromised. Instead we use the bcrypt hashing algorithm, so the passwords cannot be identified easily (even with a brute force approach to guess each password).

  • We enforce a maximum number of login attempts per IP address (this is higher than normal, at 20 attempts every 30 minutes, as we often have a room full of people all trying to login at the same time). Additionally we keep an eye on the failed login attempts when reviewing our access logs.

  • All uploaded files (e.g. images) are put into a folder where code execution is disabled, and the images are re-saved to reduce the risk of these files containing malicious content.

  • To further protect against someone uploading a file as one type (e.g. an image), and the browser seeing it as another type (e.g. JavaScript), we send the X-Content-Type-Options: nosniff header.

  • The server automatically applies security patches every day. We realise there is a small risk that a patch may result in the website becoming unavailable, but it ensures that security vulnerabilities are patched as soon as possible.

  • The server is configured to only run the services needed, with the most restrictions possible. This includes only allowing certain types of connections (limited open ports), server admin login only by authorised SSH Keys (no passwords), accounts having very limited access (file permissions), etc.

  • All data is sent to our database via Prepared Statements, which protects against SQL Injection, a type of attack where someone accesses or modifies the data we store. We take this even further, by ensuring our SQL is only defined by strings in our source code, using Literal-Strings.

  • All data displayed on the website is encoded appropriately; this is typically done though HTML and URL encoding, which protects against Cross Site Scripting (XSS) attacks.

  • As an additional layer of defence, we use a very strict Content Security Policy, where we are proud to not include any of the "unsafe" statements (i.e. we do not use inline JavaScript or CSS). We also have a "default-src" of "none", so we can limit the sources and features we use (typically just our own website).

  • We set the Referrer Policy to not expose data in the URL (not that we put any sensitive data in the URL).

  • If you log in to our website, we will generate a session for you, where the unique token is stored in a cookie (query strings are potentially vulnerable to session fixation and information leakage attacks), and we use several other mechanisms to protect against other session based attacks - e.g. if someone malicious did discover the token value; it's changed on login, every 5 minutes, and we reject any tokens we didn't generate.

  • Once logged in, we also protect against Cross Site Request Forgery (CSRF) attacks, where a malicious website could cause the victims browser to perform actions on our website (e.g. edit or delete an account). We block these malicious requests by setting a random value in a cookie, and repeating that value in every form (so for every request that attempts to modify something, we can check that the values match). Also, the value in the form is hashed with the page URL, so if anyone malicious was able to access this value from the HTML, they will only be able to attack that page.

  • We check any provided Sec-Fetch-* headers, where the browser can tell us where the request came from, and what the response will be used for - this is useful for detecting and blocking CSRF attacks.

  • We are using the SameSite Cookie Attribute, so malicious requests from other websites do not include those cookies (depending on the request type), which is another defence against CSRF attacks.

  • We set "HttpOnly" and "Secure" attributes on all Cookies, so they are only used on HTTPS connections, and not available to JavaScript (important for the Session Token). We also enforce the Secure attribute by using the "__Host-" name prefix.

  • We set the "Cross-Origin-Opener-Policy" header, so any malicious websites that open a new window for this website, they cannot keep a reference to our window, which could be used to change the page being viewed (e.g. to show a phishing website).

  • We set the "Cross-Origin-Embedder-Policy" header to "require-corp", so that the browser checks that all resources can be included in a way that allows our web pages to be Cross-Origin Isolated, giving our website protection against Spectre attacks, because it can be run in a separate process.

  • For any outbound links, while we rarely open a new window, we use rel="noopener", so the remote website will not have access to `window.opener`.

  • We set the "Cross-Origin-Resource-Policy" header to stop any of our resources from being loaded by remote websites, which helps the browser improve site isolation. Historically this was done by checking the Referrer header, which no longer works.

  • All JavaScript has been written to support asynchronous loading (faster), and to provide variables in data attributes or <meta> tags, which keeps code and data separate.

  • All JavaScript and CSS is provided with the "integrity" attribute, which ensures the received content is correct, and this is enforced with "require-sri-for" in the Content Security Policy.

  • All JavaScript has been written to work with Trusted Types, to ensure unsafe methods aren't used - e.g. link.setAtribute('href', url). This is enforced via the "trusted-types" Content Security Policy.

  • During development we use the "application/xhtml+xml" mime type, which ensures all attributes are quoted (important), and tags are nested correctly.

  • And finally, to protect against Click Jacking attacks, we set the "X-Frame-Options" header to either DENY (default) or SAMEORIGIN. And for more modern browsers, this is repeated in the "frame-ancestors" Content Security Policy.

Please see our Privacy Policy to find out how we process your data.