# Secure coding notes

Based on the [OWASP secure coding practices](https://owasp.org/www-pdf-archive/OWASP_SCP_Quick_Reference_Guide_v2.pdf).

## Summary
* Zentral is based on the [Django web framework](https://www.djangoproject.com/). It provides important building blocks for authentication, authorization, password and session management. All these building blocks follow the industry’s best practices and regular security updates are available.
* Local user accounts (not federated Identity provider accounts) can be protected with MFA.
* In all standard Zentral deployments the communications are protected by TLS.
* Secrets needed for the Zentral operations do not have to be provided in a configuration file and can be read from the process environment or from secret stores. Secrets stored in the database can be encrypted.
* Zentral follows the principle of least privilege.

## Input Validation

Zentral leverages python and the Django framework, more specifically the [Forms API](https://docs.djangoproject.com/en/4.0/ref/forms/api/).

## Output Encoding

HTML generated by Zentral is sanitized using the auto-escaping functionality of the Django framework.

[Content security policies](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) are [configured](https://github.com/zentralopensource/zentral/blob/1259456c4a439e5a074cadc30153250040047ba6/server/base/middlewares.py#L12-L19) to block any content coming from third parties. Only inline scripts with a correct nonce attribute are allowed.

## Authentication and password management

The [Django auth framework](https://docs.djangoproject.com/en/3.2/topics/auth/) is used to manage the authentication and authorization of the users in the Zentral administration console. Other means of authentication and authorization are used for the different agents.

Only the login, password reset and health check views can be accessed without authentication.

In a standard deployment, the user management pages are protected by a rate limiter.
Passwords are hashed by PBKDF2 with SHA256 using [260000 iterations (Django 3.2 default)](https://github.com/django/django/blob/e01b383e021d37e1b7ee62f1cf2e490fb849b95d/django/contrib/auth/hashers.py#L268).

Password reset links have a short expiration time.

TOTP authentication codes or WebAuthn compatible devices can be used for MFA. The removal of a MFA verification device requires to re-authenticate using the password.

Well known libraries ([pysaml2](https://github.com/IdentityPython/pysaml2), [python-ldap](https://www.python-ldap.org), [josepy](https://github.com/certbot/josepy)) are used to provide user federation.

[Dependabot scans provided by GitHub](https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/about-dependabot-version-updates) inform us of any dependencies that have a security issue.

## Session management

The session expiry can be configured for local or federated users.

Session data is stored in the database and referenced by an identifier stored in a [HttpOnly](https://docs.djangoproject.com/en/3.2/ref/settings/#std:setting-SESSION_COOKIE_HTTPONLY) [Secure](https://github.com/zentralopensource/zentral/blob/1259456c4a439e5a074cadc30153250040047ba6/server/server/settings.py#L107) cookie.

The [Django CSRF protection](https://docs.djangoproject.com/en/3.2/ref/csrf/) is used by default and is only disabled on some views that require a non-standard method of authentication (webhooks, agent endpoints).

## Access control

The [Django auth framework](https://docs.djangoproject.com/en/3.2/topics/auth/) is used to manage the authentication and authorization of users in the Zentral administration console. Other means of authentication and authorization are used for the different agents.

Groups can be defined with a restricted set of permissions. Members of those groups inherit those permissions.

Federated users are not authorized to modify the users and the user federation settings, whatever the permissions they have.

## Cryptography practices

Django uses the platform cryptographic random generator by default.

In standard deployments, the legacy protocols and algorithms for TLS are disabled.

## Error handling and logging

Secrets are not logged.

All Django framework errors are logged. In standard Zentral deployments those logs, along with important OS logs and Nginx logs, are collected in a centralized system.

In supported cloud environments all access to secrets are logged.

## Data protection

A secret framework is included in Zentral to encrypt sensitive data stored in the database.

In a standard Zentral deployment database backups are encrypted at rest.

## Communication security

TLS everywhere.

Encrypted communication with the database if not on the same host.

Agents can be configured to use mTLS.

## System configuration

In standard Zentral deployments, software updates are automatically applied. We can also provide up to date images and containers. Dependabot scans are set up in our Github repository to inform us about eventual security issues. Deployment infrastructure is managed via Terraform and each principal (VM, cloud service) only gets the minimum required permissions.

## Database security

Only strongly parameterized queries are used. See [Django QuerySet API](https://docs.djangoproject.com/en/3.2/ref/models/querysets/), and [psycopg2](https://pypi.org/project/psycopg2/).

In supported cloud environments, a database connection proxy can be used to strongly encrypt and authenticate the connection to the database.

The role used by the Zentral application cannot be used to create or change other databases or users.

## File management

File uploads are only used in a few Zentral contrib applications and can be turned off if necessary.

In standard deployments, an upload file size limit is set in the Nginx configuration.

Files are only served from the Zentral application after validation.

## Memory management

Python is memory safe. We make sure we do not have memory leaks.

## General coding practice

The `main` branch is protected in Github and tests must pass on the whole project before being able to merge the changes.

Our organization is growing and we will make code reviews mandatory as soon as possible.

We choose third party libraries carefully and make sure they only introduce reasonable dependencies.

All python dependencies versions are pinned to a specific version number.
