Security 

Protecting your API endpoints 

The nnrestapi extension provides several security features to protect your API from common attacks and abuse. These can be applied:

  • Globally via TypoScript for all endpoints
  • Per endpoint via annotations

Global security checks 

You can define security checks that are executed before every API request by configuring them in TypoScript. This is useful for applying consistent security policies across your entire API.

plugin.tx_nnrestapi.settings.security {
   defaults {
      10 = \Nng\Nnrestapi\Utilities\Security->checkInjections
      20 = \Nng\Nnrestapi\Utilities\Security->checkLocked
   }
}
Copied!

The checks are executed in order of their numeric keys. If any check returns FALSE, the API will respond with a 403 Forbidden status code.

Built-in security checks 

checkInjections 

Scans the request body and GET parameters for typical SQL injection patterns. If a potential injection is detected, the IP is automatically blacklisted for 24 hours.

10 = \Nng\Nnrestapi\Utilities\Security->checkInjections
Copied!

Detected patterns include:

  • SQL comments and escape sequences
  • UNION SELECT statements
  • INSERT, UPDATE, DELETE statements
  • Sleep injection attacks
  • Boolean-based injection patterns
checkLocked 

Checks if the current IP or frontend user has been blacklisted. Locked IPs/users are denied access to all endpoints.

20 = \Nng\Nnrestapi\Utilities\Security->checkLocked
Copied!

Custom security checks 

You can create your own security checks by defining a class with a method that returns TRUE (allow) or FALSE (deny):

<?php
namespace My\Extension\Utilities;

class Security
{
   /**
    * Check for honeypot fields in the request.
    * 
    * @param \Nng\Nnrestapi\Mvc\Request $request
    * @return bool
    */
   public function checkHoneypots($request)
   {
      $body = $request->getBody();
      
      // If honeypot field is filled, it's a bot
      if (!empty($body['hp_field'])) {
         // Optionally lock the IP
         \nn\rest::Security($request)->lockIp(86400);
         return false;
      }
      
      return true;
   }
}
Copied!

Register it in TypoScript:

plugin.tx_nnrestapi.settings.security {
   defaults {
      5 = \My\Extension\Utilities\Security->checkHoneypots
      10 = \Nng\Nnrestapi\Utilities\Security->checkInjections
      20 = \Nng\Nnrestapi\Utilities\Security->checkLocked
   }
}
Copied!

Per-endpoint security annotations 

For more granular control, you can apply security checks to individual endpoints using annotations.

@Api\Security\CheckInjections 

Check for SQL injection patterns on a specific endpoint:

/**
 * @Api\Security\CheckInjections()
 */
public function postSearchAction($data)
{
   // Request body is checked for injection patterns
}
Copied!

To disable auto-locking when an injection is detected:

/**
 * @Api\Security\CheckInjections(false)
 */
public function postSearchAction($data)
{
   // Injection check without auto-locking
}
Copied!

See @Api\Security\CheckInjections for details.

@Api\Security\CheckLocked 

Check if the current IP or user is blacklisted:

/**
 * @Api\Security\CheckLocked()
 */
public function postLoginAction($credentials)
{
   // Locked IPs/users are denied access
}
Copied!

See @Api\Security\CheckLocked for details.

@Api\Security\MaxRequestsPerMinute 

Limit the number of requests from a single IP to prevent brute-force attacks and abuse:

/**
 * Limit to 60 requests per minute (default)
 * @Api\Security\MaxRequestsPerMinute()
 */
public function getDataAction()
{
}

/**
 * Limit to 5 requests per minute
 * @Api\Security\MaxRequestsPerMinute(5)
 */
public function postLoginAction($credentials)
{
}

/**
 * Limit to 10 requests per minute for this specific endpoint ID
 * @Api\Security\MaxRequestsPerMinute(10, "login")
 */
public function postLoginAction($credentials)
{
}
Copied!

See @Api\Security\MaxRequestsPerMinute for details.

IP and user locking 

The extension provides methods to manually lock and unlock IPs or frontend users.

Locking an IP 

// Lock current IP for 24 hours (default)
\nn\rest::Security()->lockIp();

// Lock current IP for 1 hour
\nn\rest::Security()->lockIp(3600);

// Lock with additional data for logging
\nn\rest::Security()->lockIp(86400, 'Suspicious activity detected');
Copied!

Unlocking an IP 

\nn\rest::Security()->unlockIp();
Copied!

Locking a frontend user 

// Lock current frontend user for 24 hours
\nn\rest::Security()->lockFeUser();

// Lock specific user for 1 hour
\nn\rest::Security()->lockFeUser(123, 3600);
Copied!

Unlocking a frontend user 

// Unlock current frontend user
\nn\rest::Security()->unlockFeUser();

// Unlock specific user
\nn\rest::Security()->unlockFeUser(123);
Copied!

Privacy considerations 

This ensures compliance with privacy regulations like GDPR while still allowing effective rate limiting and IP-based blocking.

Database table 

Security data is stored in the nnrestapi_security table. Expired entries are automatically cleaned up when new security checks are performed.

The table stores:

  • iphash - Hashed IP address
  • feuser - Frontend user UID (if logged in)
  • identifier - Type of entry (e.g., "lock", "all", custom IDs)
  • expires - Timestamp when the entry expires
  • data - Additional data (e.g., the suspicious request content)