PHP Framework Protection Strategies

PHP Framework Protection Strategies

PHP's evolution from SQL injection poster child to secure development platform showcases the importance of framework adoption:

// Laravel Eloquent ORM - Secure by default
use App\Models\User;
use Illuminate\Support\Facades\DB;

class SecureLaravelQueries {
    // Eloquent automatically parameterizes queries
    public function findUsersByStatus($status) {
        return User::where('status', $status)
                   ->where('created_at', '>', now()->subDays(30))
                   ->get();
    }
    
    // Query Builder with automatic parameterization
    public function complexSearch($filters) {
        $query = DB::table('products')
                   ->join('categories', 'products.category_id', '=', 'categories.id');
        
        // Conditional filters - all automatically parameterized
        if (!empty($filters['name'])) {
            $query->where('products.name', 'like', '%' . $filters['name'] . '%');
        }
        
        if (!empty($filters['min_price'])) {
            $query->where('products.price', '>=', $filters['min_price']);
        }
        
        if (!empty($filters['categories'])) {
            $query->whereIn('categories.id', $filters['categories']);
        }
        
        return $query->paginate(20);
    }
    
    // Raw queries when needed - still parameterized
    public function customReport($startDate, $endDate, $userId) {
        return DB::select('
            SELECT DATE(created_at) as date, 
                   COUNT(*) as total_orders,
                   SUM(total_amount) as revenue
            FROM orders
            WHERE user_id = :user_id
              AND created_at BETWEEN :start_date AND :end_date
            GROUP BY DATE(created_at)
        ', [
            'user_id' => $userId,
            'start_date' => $startDate,
            'end_date' => $endDate
        ]);
    }
    
    // Dangerous pattern to avoid
    public function insecureSearch($input) {
        // NEVER DO THIS - Direct concatenation
        // DB::select("SELECT * FROM users WHERE name = '" . $input . "'");
        
        // Even with Laravel, you can create vulnerabilities
        // DB::statement("DROP TABLE IF EXISTS " . $input); // DANGEROUS!
    }
}

// Symfony Doctrine ORM
use Doctrine\ORM\EntityManagerInterface;

class SecureSymfonyQueries {
    private $entityManager;
    
    public function __construct(EntityManagerInterface $entityManager) {
        $this->entityManager = $entityManager;
    }
    
    // DQL with parameter binding
    public function findActiveUsers($role, $days) {
        $query = $this->entityManager->createQuery('
            SELECT u FROM App\Entity\User u
            WHERE u.role = :role
              AND u.lastLogin > :date
              AND u.isActive = true
        ');
        
        $query->setParameter('role', $role);
        $query->setParameter('date', new \DateTime("-{$days} days"));
        
        return $query->getResult();
    }
    
    // Query Builder for dynamic queries
    public function buildDynamicQuery($criteria) {
        $qb = $this->entityManager->createQueryBuilder();
        $qb->select('p')
           ->from('App\Entity\Product', 'p');
        
        $paramCount = 0;
        foreach ($criteria as $field => $value) {
            // Whitelist fields to prevent injection via field names
            if (in_array($field, ['name', 'category', 'price', 'stock'])) {
                $paramName = 'param' . $paramCount++;
                $qb->andWhere("p.{$field} = :{$paramName}")
                   ->setParameter($paramName, $value);
            }
        }
        
        return $qb->getQuery()->getResult();
    }
}