Skip to content

Security and compliance ​

ISO 27001 certifies an organization's information security management system, and the NIS2 directive sets obligations for the "essential" and "important" entities of the sectors it lists. Neither applies to a library: using Trek doesn't make an app compliant, and no setting does. What Trek does is provide many of the technical measures these frameworks expect from an application, with defaults chosen for them.

This page lists those measures for an auditor or a security questionnaire, and what stays with the app, its hosting and the organization running it. It describes the current version; measures still to come are marked as planned.

ISO 27001 controls ​

The controls of ISO/IEC 27001:2022's Annex A that an application takes part in:

ControlWhat Trek providesDocs
5.15 Access control, 8.2 Privileged access rights, 8.3 Information access restrictionRoles (admin, editor…), only admin and editor can sign in to the admin, and policies authorize each record and attribute per role, only admin the audit logUser › Roles, Policies
5.17 Authentication informationThe ANSSI's password recommendations for a privileged access: 12 characters or more, no common password, sequence, name or email; the last 5 passwords refused; optional expiry; an admin can ask everyone for a new password after a suspected compromise. Password reset links last 15 minutes, invitation links a week, and no column stores themPassword policy, Previous passwords
5.18 Access rightsEach user's last activity and previous sign-in. Planned: reviewing access, and deactivating dormant accountsUser › Sign-ins
5.34 Privacy and protection of PIIThe audit log records parameter names, not their values, and the docs set out the GDPR's conditions for keeping it. The breached password check, which would send part of a password's hash to an outside service, is off by default. Uploaded images lose their metadata (GPS location, camera serial number). The personal data Trek's generators create is listed, with how long it's kept and what deletes itPersonal data, Audit log › Personal data
8.5 Secure authenticationPasskeys, which can't be phished and count as two factors; failed sign-ins throttled per IP address and per account, with an email to the account's user; sign-in and password reset that don't reveal whether an account exists; sessions ending after 48 hours idle and 30 days in all, listed to their user, who can end them; an email on a sign-in from a new browser. Planned: TOTP codes, and requiring a second factorUser
8.8 Management of technical vulnerabilitiesGenerated apps' CI runs Brakeman and checks their gems (bundler-audit) and the npm packages they bundle (yarn npm audit) for known vulnerabilities, and can make a Software Bill of Materials (SBOM) of their gems and npm packages; Trek's own CI too, and Renovate keeps its dependencies up to date. Planned: a vulnerability disclosure policyInstaller, Vulnerable dependencies, Software Bill of Materials
8.9 Configuration managementThe installer gives every app the same configuration, security headers included: a Content Security Policy, report-only at first, and a Permissions-Policy turning off the browser features the app doesn't use. bin/rails trek:security:check checks a deployed app still follows the recommended settingsInstaller, Security headers, Self-check
8.15 LoggingAn audit log of every change in the admin and every sign-in: author, request, record, status, IP address. Rows can't be changed through the app, and are deleted after 6 months, as the CNIL recommends. Planned: sending them to a store outside the appAudit log
8.16 Monitoring activitiesErrors and performance reported to AppSignal, and the Content Security Policy's violations; users emailed on a sign-in from a new browser and when failed sign-ins lock their accountInstaller
8.20 Networks securityThe visitor's real IP address behind proxies and CDNs, which the limits and logs rely on; the admin can be restricted to IP addresses and ranges (ADMIN_ALLOWED_IPS)Proxies, Restricting the admin to IP addresses
8.24 Use of cryptographyHTTPS only (force_ssl, with HSTS and secure cookies), bcrypt password hashes, signed session cookies, signed tokens in emailed links. Planned: encrypting sensitive columnsCryptography
8.25 to 8.29 Secure developmentTrek's changes go through merge requests, with specs, RuboCop, Brakeman, bundler-audit and yarn npm audit in CI. Generated apps get the same CI, and specs checking Trek's behaviour in themInstaller
8.33 Test informationPlanned: anonymized production dumps for development

NIS2 measures ​

The measures of the directive's Article 21(2), and what Trek provides for each:

MeasureWhat Trek provides
(a) Risk analysis and security policies—
(b) Incident handlingEvidence: the audit log, AppSignal's errors, the sign-in emails
(c) Business continuity, backups, disaster recovery—
(d) Supply chain securityDependencies checked for known vulnerabilities in CI: gems (bundler-audit) and the npm packages an app bundles (yarn npm audit, which also fails on deprecated packages), with how to resolve one; kept up to date by Renovate. A CycloneDX SBOM of an app, made in its CI, to hand to a client who asks. The third parties a default app sends personal data to, and what
(e) Secure development and maintenance, vulnerability handling and disclosureChanges through merge requests, with specs, RuboCop, Brakeman, bundler-audit and yarn npm audit in CI; generated apps get the same CI. Planned: a vulnerability disclosure policy
(f) Assessing the measures' effectivenessbin/rails trek:security:check checks a deployed app's configuration against the recommended settings, and prints a dated report to keep as evidence (see Self-check)
(g) Cyber hygiene and training—
(h) Cryptography and encryptionHTTPS only (force_ssl, with HSTS and secure cookies), bcrypt password hashes, signed session cookies, signed tokens in emailed links (see Cryptography). Planned: encrypting sensitive columns
(i) Human resources security, access control, asset managementRoles, and policies authorizing each record and attribute per role; sessions that expire and that their user can end. Planned: reviewing access, and deactivating dormant accounts
(j) Multi-factor authenticationPasskeys. Planned: TOTP codes, and requiring a second factor

Measures (a), (c), (f) and (g) are up to the organization and its hosting (see What Trek expects from the hosting).

Reporting a significant incident (Article 23: an early warning within 24 hours, a notification within 72 hours, a final report within a month) is up to the organization too; the audit log helps establish what happened.

Cryptography ​

The cryptography a generated app uses, with Rails 8.1's defaults: an inventory for ISO 27001's control 8.24, and for planning the move to post-quantum cryptography. No tool can make one automatically for a Ruby app, so this inventory is maintained by hand.

UseAlgorithmAgainst a quantum computer
Passwordsbcrypt, cost 12Resists
Rails' session cookie (flash messages, CSRF token), the browsers a user signed in fromAES-256-GCMResists
Signed cookies: the session idHMAC-SHA1Resists
Password reset and invitation links (generates_token_for)HMAC-SHA1Resists
Keys of the above, derived from secret_key_basePBKDF2-HMAC-SHA256, 1,000 iterationsResists
Passkeys (the webauthn gem's defaults)ECDSA P-256 (ES256), RSA (PS256, RS256)Vulnerable, like all of today's public-key signatures; the move depends on browsers and authenticators
Breached password check (off by default)The first 5 characters of the password's SHA-1, sent to Have I Been Pwned to keep the password unknown to it; not a security function—
HTTPSTLS, as configured where it ends (platform router, CDN)Depends on the hosting
Planned: encrypting sensitive columnsAES-256-GCM (Active Record Encryption)Resists

HMAC-SHA1, Rails' default for signed cookies and tokens, isn't broken: an HMAC doesn't rely on SHA-1's collision resistance. The ANSSI advises against SHA-1 in new uses, though, and an audit following its guidance may question it.

What stays with the app, the hosting and the organization ​

  • The organization: its information security management system, risk analysis, policies, training, incident response and reporting, and its suppliers' assessment, the hosting provider's included.
  • The app: its own models and controllers, their policies, which data they hold, and keeping Trek and its other dependencies up to date.
  • The hosting: backups, redundancy, the network, the servers' security, and its certifications.

What Trek expects from the hosting ​

  • Backups of the database and of the uploads' bucket, encrypted, kept apart from the app, and restored now and then to check them.
  • HTTPS, with the proxies in front of the app forwarding the original host, scheme and visitor's IP address (see Proxies).
  • A cache store shared by all the app's processes and servers, for the sign-in limits (see Failed sign-ins).
  • An Active Job backend running the scheduled purges: Trek::PurgeExpiredSessionsJob, and Trek::AuditLog::PurgeJob with the audit log.
  • Secrets out of the code: the master key and API keys in the platform's environment variables, different in each environment.
  • Logs kept for a limited time, as they hold IP addresses.

For an app whose client is subject to ISO 27001 or NIS2:

  • install the audit log, and schedule its purge;
  • encourage passkeys; for admins signing in with a password only, make it expire after a year (self.password_expires_after = 1.year, as the ANSSI suggests);
  • keep the admin role to the few people who need it;
  • enforce the Content Security Policy once its reports show no violation left but noise (Report first, then enforce);
  • list the CDN's ranges in trusted_proxies when there is one (Proxies);
  • when the admins work from known networks (an office, a VPN), restrict the admin to them with ADMIN_ALLOWED_IPS.

Self-check ​

bin/rails trek:security:check checks a deployed app against the settings above, and what Trek expects from the hosting. Run it where the app runs in production, so it reads that configuration and database, e.g. from a shell on the server or through the hosting platform's command runner. It prints each check with a link to the page explaining it:

  • ✓ the setting follows the recommendation;
  • • a fact, for information: the number of admin users, whether trusted_proxies is set, ADMIN_ALLOWED_IPS left unset;
  • ⚠ a recommendation not followed, e.g. admins signing in with a password only, a Content Security Policy that only reports, or the purge of expired sessions not scheduled;
  • ✗ a setting Trek relies on: HTTPS, a Content Security Policy, a cache store shared by the app's processes, GoodJob's cron, the audit log's purge.

It checks HTTPS and HSTS, the Content Security Policy, the cache store, the proxies and ADMIN_ALLOWED_IPS, the audit log and the scheduled purges, the admin users (those signing in with a password only, those who haven't signed in for 6 months, password expiry), and Active Record Encryption's keys. The report starts with the date, the app, and Trek's, Rails' and Ruby's versions: keep it as evidence that the measures are in place.

The task exits with status 1 when a check fails, so a scheduled job or a deploy step can stop on it. Run it before going live, after changing the hosting or the app's configuration, and at least once a year.

In the admin ​

The admin's Settings › Security page shows the same checks to admins (editors are turned away), dated, to print or save as evidence without access to a production shell. It also checks the request that opened it, which the task can't: that it reached the app over HTTPS, and the IP address Rails sees. A CDN that forwards another address in its own header (CF-Connecting-IP, True-Client-IP, Fastly-Client-IP) than the one Rails sees fails the check, as its ranges are missing from trusted_proxies. The page comes from bin/rails g trek:install:admin:security_check, which trek:install runs.

Outside the app ​

The task reads the configuration only. Check what reaches the browser with external tools too: Mozilla Observatory for the security headers, SSL Labs for HTTPS, and the IP address Rails sees, as Proxies explains.

Released under the MIT License.