mortimer333/api-skeleton

API Skeleton

dev-master 2024-02-19 21:28 UTC

This package is auto-updated.

Last update: 2024-11-19 23:00:34 UTC


README

Security Cheat Sheet

https://cheatsheetseries.owasp.org/index.html

Swagger

https://symfony.com/bundles/NelmioApiDocBundle/current/index.html

  • routes will show on swagger only if name starts with api.

https://zircote.github.io/swagger-php/guide/attributes.html

nelmio/NelmioApiDocBundle#1990

https://swagger.io/docs/specification/about/

Security

https://symfony.com/doc/current/security.html

  • #[CurrentUser] attribute doesn't work, use Symfony\Component\Security\Core\Security::getUser() instead - symfony/symfony#40333

CSRF Token

if we have api platform the csrf token should be generated from FE and added to headers. Let's create it when user logs in, save in the cookie and reuse. It will have few infromation set in:

  • browser
  • system
  • ip

This should be enough to determinate when user suddenly changed and log him out. We will be also adding salted app secret for csrf.

Email validation

https://github.com/symfonycasts/verify-email-bundle

SECRETS

We will be using symfony vault - https://symfony.com/doc/current/configuration/secrets.html

  • can commit keys from config/secrets/dev/ on dev
  • never commit private key - config/secrets/dev/dev.decrypt.private.php on PROD
    • run prod with APP_RUNTIME_ENV=prod php bin/console secrets:generate-keys
    • script to periodically change security keys by secrets:generate-keys --rotate
  • To set new env: php bin/console secrets:set [name]

Fixtures

To reset test DB and populate it new data use fixtures:

APP_ENV=test php bin/console doctrine:fixtures:load

or

make reset-test-env

TESTS

We are using codeception (which is base on PHPUint)

actor: ApiTester
modules:
  enabled:
    - REST:
        url: http://api.boardmeister.local/ # <-- url
        depends: Symfony
        part: Json
    - Symfony:
        app_path: 'src'
        environment: 'test'
  • to run tests as www-data to avoid permission issues: sudo runuser -u www-data make before-push
  • symfony module
  • to create tests you must run:
    • For Unit: php vendor/bin/codecept generate:test Unit Dir/TestNameWithoutTestAtEnd
    • For Integration: php vendor/bin/codecept generate:test Integration Dir/TestNameWithoutTestAtEnd
    • For Api: php vendor/bin/codecept generate:test Api Dir/TestNameWithoutTestAtEnd
  • To run tests: php vendor/bin/codecept run
  • To run detailed tests: php vendor/bin/codecept run --steps or php vendor/bin/codecept run --debug
  • To run with coverage: DEBUG_MODE=coverage php vendor/bin/codecept run --coverage --coverage-xml --coverage-html
  • To run only:
    • Unit: php vendor/bin/codecept run Unit
    • Integration: php vendor/bin/codecept run Integration
    • Api: php vendor/bin/codecept run Api
    • Single test: php vendor/bin/codecept run Integration SigninCest.php or full path php vendor/bin/codecept run tests/acceptance/SigninCest.php (https://codeception.com/docs/GettingStarted#running-tests)
  • Usefull knowledge:

PHP Mess Detector

To suppress warning use @SuppressWarnings(PHPMD.[warning name])

php vendor/bin/phpmd src text phpmd.xml
php vendor/bin/phpmd tests text phpmd.xml

PHP Stan

Command:

php vendor/bin/phpstan analyse src tests

To ignore single error use:

  • @phpstan-ignore-line
  • @phpstan-ignore-next-line

To ignore a batch of errors considers reading https://phpstan.org/user-guide/ignoring-errors and updating ./phpstan.neon

Known errors:

Could not write file: /tmp/phpstan/resultCache.php (file_put_contents(/tmp/phpstan/resultCache.php): Failed to open stream: Permission denied)

If you have previously run analysis as not current user that cache directory might have wrong owner. Change the owner to current user, and it should be fine

PHP Code Style Fixer

vendor/bin/php-cs-fixer fix --verbose

Config options - https://mlocati.github.io/php-cs-fixer-configurator/#version:3.13

PHP Code Sniffer

To ignore:

Psalm

To suppress warning @psalm-suppress InvalidReturnType more at https://psalm.dev/docs/running_psalm/dealing_with_code_issues/

Known problems: Can't create cache dir:

Uncaught RuntimeException: PHP Error: mkdir(): Permission denied in /var/www/html/boardmeister_internal/vendor/vimeo/psalm/src/Psalm/Config.php:2210 for command with CLI args "vendor/bin/psalm --taint-analysis" in /var/www/html/boardmeister_internal/vendor/vimeo/psalm/src/Psalm/Internal/ErrorHandler.php:75

if you are running commands as a www-data then make sure that /var/www/.cache directory is created and www-data is an owner of it.

PHP

Ubuntu - update-alternatives --config php

BCMath

in php.ini change bcmath.scale to 2

JWT

https://jwt.io/

Header manager

https://web-token.spomky-labs.com/the-components/header-checker

Claim manager

https://web-token.spomky-labs.com/the-components/claim-checker

Key

  • https://web-token.spomky-labs.com/advanced-topics-1/security-recommendations
  • symetric algorith
  • 256 bits symmetric keys and at lease 2048 bits RSA keys
  • additional in key:
    • kid: A unique key ID
    • use: indicates the usage of the key. Either sig (signature/verification) or enc (encryption/decryption).
    • alg: the algorithm allowed to be used with this key.
  • Key rotation - once a week
  • Token payload
    • as small as possible
    • have:
      • jti - unique identifier
      • exp: expiration time
      • iat: issuance time
      • nbf: validity point in time.
      • iss (issuer)
      • aud (audience)
    • When using encrypted tokens, the claims iss and aud should be duplicated into the header

Validate

  1. Unserialize the token
  2. For each signature/recipient (may be possible when using the Json General Serialization Mode):
    1. Check the complete header (protected and unprotected)
    2. Verify the signature (JWS) or decrypt the token (JWE)
    3. Check the claims in the payload (if any)

If an error occurred during this process, you should consider the token as invalid.

Header parameters have to be checked. You should at least check the alg (algorithm) and enc (only for JWE) parameters. The crit (critical) header parameter is always checked.

Nested Token

We wanna use nested tokens to signature and encrypt token - https://web-token.spomky-labs.com/advanced-topics-1/nested-tokens