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();
}
}