Secure Controller

SecureController extends BaseController and automatically applies security headers to all controller methods. Controllers should extend SecureController when handling sensitive operations or user data to ensure comprehensive security protection without manual header configuration.

Using SecureController

Extend SecureController in your controller classes to automatically apply security headers to all responses:

<?php
namespace App\Controllers;

use Quellabs\Canvas\Controllers\SecureController;
use Quellabs\Canvas\Annotations\Route;
use Symfony\Component\HttpFoundation\Response;

class AdminController extends SecureController {

    /**
     * @Route("/admin/dashboard")
     */
    public function dashboard(): Response {
        // All security headers are automatically applied
        return $this->render('admin/dashboard.tpl');
    }
}

Automatic Security Headers

The following headers are automatically added to all responses. If a header is already set in your controller method, SecureController will not override it, allowing for custom configurations when needed.

Header Value Protection
X-Frame-Options SAMEORIGIN Prevents clickjacking by disallowing framing from external sites
X-Content-Type-Options nosniff Prevents MIME-type sniffing attacks
X-XSS-Protection 1; mode=block Enables browser XSS filtering and blocks detected attacks
Strict-Transport-Security max-age=31536000; includeSubDomains
(HTTPS only)
Forces HTTPS connections for 1 year, including all subdomains
Referrer-Policy strict-origin-when-cross-origin Controls referrer information sent with requests

Default Configuration

SecureController uses SecurityHeadersAspect with the following default settings:

Setting Default Value Description
frameOptions SAMEORIGIN Can be DENY, SAMEORIGIN, or ALLOW-FROM
noSniff true Enable X-Content-Type-Options header
xssProtection true Enable X-XSS-Protection header
hstsMaxAge 31536000 HSTS duration in seconds (1 year)
hstsIncludeSubdomains true Apply HSTS to all subdomains
referrerPolicy strict-origin-when-cross-origin Referrer information policy
csp null Content-Security-Policy (disabled by default)

Customizing Security Headers

To customize security headers for specific controllers, apply the @InterceptWith annotation directly with custom settings:

<?php
namespace App\Controllers;

use Quellabs\Canvas\Controllers\BaseController;
use Quellabs\Canvas\Annotations\InterceptWith;
use Quellabs\Canvas\Security\SecurityHeadersAspect;
use Quellabs\Canvas\Annotations\Route;
use Symfony\Component\HttpFoundation\Response;

/**
 * @InterceptWith(
 *     SecurityHeadersAspect::class,
 *     frameOptions="DENY",
 *     csp="default-src 'self'; script-src 'self' 'unsafe-inline'"
 * )
 */
class StrictSecurityController extends BaseController {

    /**
     * @Route("/secure/page")
     */
    public function securePage(): Response {
        // Uses custom security headers
        return $this->render('secure/page.tpl');
    }
}

For per-method customization, apply the annotation to individual methods:

<?php
namespace App\Controllers;

use Quellabs\Canvas\Controllers\SecureController;
use Quellabs\Canvas\Annotations\InterceptWith;
use Quellabs\Canvas\Security\SecurityHeadersAspect;
use Quellabs\Canvas\Annotations\Route;
use Symfony\Component\HttpFoundation\Response;

class ApiController extends SecureController {

    /**
     * @Route("/api/data")
     * @InterceptWith(
     *     SecurityHeadersAspect::class,
     *     frameOptions="DENY",
     *     referrerPolicy="no-referrer"
     * )
     */
    public function getData(): Response {
        // This method uses stricter security than other methods
        return $this->json(['data' => 'sensitive']);
    }
}

Inherited Helper Methods

SecureController extends BaseController, providing access to all convenience methods:

Method Description Example
render($template, $data, $status) Render a template and return Response $this->render('admin/users.tpl', ['users' => $users])
json($data, $status) Return JSON response $this->json(['success' => true])
text($text, $status) Return plain text response $this->text('Operation complete')
redirect($url, $status) Redirect to another URL $this->redirect('/admin/login')
notFound($message, $status) Return 404 response $this->notFound('Resource not found')
forbidden($message, $status) Return 403 response $this->forbidden('Insufficient permissions')
em() Get EntityManager instance $this->em()->findAll(User::class)
view() Get template engine instance $this->view()->render('partial.tpl')
service($className) Get any service from container $this->service(CacheInterface::class)