Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

8.3KB

Security Skill

Purpose

Use this skill for input validation, output escaping, passwords, authentication, authorization, sessions, CSRF, secrets, error disclosure, dangerous functions, serialization, and file/path safety.


Security Baseline

Treat all external data as untrusted.

Untrusted data includes:

  • $_GET
  • $_POST
  • $_REQUEST
  • $_COOKIE
  • $_SERVER
  • uploaded files
  • request bodies
  • session values
  • database values originally supplied by users
  • third-party API responses

Input Validation

Validate on input. Use Core\Validator for field validation — it is a fluent chain that collects all errors before returning.

Validator API

Method Description
required(field, value, message?) Fails if value is null or blank
maxLength(field, value, max, message?) Fails if string length exceeds max
minLength(field, value, min, message?) Fails if string length is below min
numeric(field, value, message?) Fails if value is not numeric
min(field, value, min, message?) Fails if numeric value is below min
max(field, value, max, message?) Fails if numeric value exceeds max
email(field, value, message?) Fails if non-empty value is not a valid email
date(field, value, format?, message?) Fails if non-empty value does not match the date format (default Y-m-d)
in(field, value, allowed[], message?) Fails if value is not in the allowed list (strict comparison)
passes() Returns true when no errors were collected
fails() Returns true when any errors were collected
errors() Returns array<string, list<string>> of field errors

email(), date(), min(), and max() skip empty or non-numeric values respectively — pair them with required() or numeric() when the field is mandatory.

Example:

$validator = new Validator();

$validator
    ->required('email', $form['email'], 'Email is required.')
    ->maxLength('email', $form['email'], 255)
    ->email('email', $form['email'], 'Enter a valid email address.')
    ->required('start_date', $form['start_date'], 'Start date is required.')
    ->date('start_date', $form['start_date'], 'Y-m-d', 'Enter a valid start date.');

if ($validator->fails()) {
    // $validator->errors() returns field => [messages] map
}

Rules:

  • Validate type, range, length, format, and allowed values.
  • Validate server-side even when client-side validation exists.
  • Reject unexpected fields when appropriate.
  • Normalize data intentionally, not accidentally.
  • Do not reimplement email or date validation inline in controllers — use the Validator methods.

Output Escaping

Escape on output based on context.

For HTML output:

function e(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

Usage:

<p><?= e($user->name()) ?></p>

Rules:

  • Escape based on context: HTML, attribute, JavaScript, CSS, URL, SQL, shell.
  • Do not use the same escaping function for every context.
  • Prefer template engines with automatic escaping only when appropriate for the project.
  • Avoid allowing raw HTML from users. If required, sanitize with a proven whitelist sanitizer.
  • Use escapeshellarg() when passing controlled values to shell commands, and avoid shell execution when possible.
  • Never trust file paths supplied by users.
  • Reject path traversal values such as ../, /, \, and null bytes when user-provided paths are not allowed.

Passwords and Authentication

Never store plain-text passwords.

Use PHP’s password API:

$hash = password_hash($plainPassword, PASSWORD_DEFAULT);

if (! password_verify($plainPassword, $hash)) {
    throw new RuntimeException('Invalid credentials.');
}

Rules:

  • Use password_hash() for new password hashes.
  • Use password_verify() for login checks.
  • Use password_needs_rehash() when algorithm/cost settings change.
  • Do not create your own password hashing algorithm.
  • Do not use general-purpose hashes like md5, sha1, or raw sha256 for passwords.
  • Rate-limit login attempts.
  • Regenerate session IDs after login.
  • Use secure, HTTP-only, SameSite cookies for sessions.

Authorization

  • Check authorization separately from authentication.
  • Do not assume logged-in means allowed.
  • Enforce permissions server-side.
  • Avoid hiding buttons as the only authorization control.
  • Prefer explicit permission checks near protected actions or service boundaries.

CSRF

Use CSRF protection for state-changing forms and unsafe HTTP methods.

State-changing actions include:

  • Create
  • Update
  • Delete
  • Login/logout state changes
  • Password changes
  • Email changes
  • Permission changes

When using _method override to tunnel PUT, PATCH, or DELETE through a POST form, always include a CSRF token. The override is only honoured for POST requests, and only for the values PUT, PATCH, and DELETE — all other values are rejected by the framework.

In MindVisionCode PHP, use the built-in helpers from core/helpers.php:

Helper Purpose
csrf_token() Generates and persists the token in the session
csrf_field() Outputs a hidden <input> carrying the token — use in every state-changing form
verify_csrf_token(string $token) Returns bool — call before any business logic in POST actions

Always verify CSRF before field validation and business logic. A token failure is a security event, not a form validation error. Use a dedicated private method that returns ?Response and short-circuits the action:

private function verifyCsrf(Request $request): ?Response
{
    if (!verify_csrf_token((string) $request->input('_token', ''))) {
        return new Response('Your session has expired. Please go back and try again.', 419);
    }

    return null;
}

Call it as the first thing in the action:

public function store(): Response
{
    $request = Request::capture();

    if ($guard = $this->verifyCsrf($request)) {
        return $guard;
    }

    // field validation and business logic follow
}

Serialization and Data Exchange

Do not call unserialize() on untrusted data.

Prefer JSON for data exchange:

$data = json_decode($json, true, flags: JSON_THROW_ON_ERROR);
$json = json_encode($data, JSON_THROW_ON_ERROR);

Rules:

  • Use JSON_THROW_ON_ERROR for new code.
  • Validate decoded data before using it.
  • Avoid PHP serialization for data that crosses trust boundaries.

Configuration and Secrets

Rules:

  • Keep secrets out of source control.
  • Do not commit passwords, API keys, private keys, tokens, or production DSNs.
  • Store configuration outside the public web root.
  • Use environment variables or ignored local config files for secrets.
  • Provide a safe example file such as .env.example.

Example .gitignore entries:

.env
.env.local
/config/local.php
/var/cache/
/var/log/
/vendor/

Error Handling and Logging

Development:

  • Show errors locally.
  • Log errors.
  • Use Xdebug when debugging complex issues.

Production:

  • Do not display errors to users.
  • Log errors to a secure log destination.
  • Return safe, generic error messages.
  • Preserve enough context in logs for troubleshooting.

Do not leak:

  • stack traces to users
  • SQL statements with secrets
  • environment variables
  • full filesystem paths
  • tokens or passwords

Example:

try {
    $service->handle($request);
} catch (Throwable $e) {
    $logger->error('Order processing failed.', [
        'exception' => $e,
        'requestId' => $requestId,
    ]);

    http_response_code(500);
    echo 'An unexpected error occurred.';
}

Security Checklist

Before completing any feature, verify:

  • All external input is validated.
  • All output is escaped for the correct context.
  • SQL uses prepared statements or safe query builders.
  • Authentication and authorization are checked server-side.
  • Secrets are not committed.
  • Errors are not exposed in production responses.
  • File uploads validate size, extension, MIME type, and storage path.
  • Passwords use password_hash() and password_verify().
  • CSRF protection exists for state-changing requests.
  • Dangerous functions are avoided or justified: eval, exec, shell_exec, system, passthru, unserialize.
  • Dependencies have no known vulnerabilities according to composer audit.

Powered by TurnKey Linux.