Shopware 6 Plugin entwickeln – Sicherheit & Best Practices
Wer ein Shopware 6 Plugin entwickeln möchte, steht vor einer wichtigen Frage: Wie stelle ich sicher, dass mein Code nicht nur funktioniert, sondern auch sicher ist? Shopware 6 bietet durch seine moderne Symfony-basierte Architektur viele eingebaute Sicherheitsmechanismen – aber nur wenn du sie richtig einsetzt.
In diesem Artikel zeige ich dir die wichtigsten Sicherheitsaspekte und Best Practices beim Shopware 6 Plugin entwickeln. Von Input-Validierung über ACL-Rechte bis zu häufigen Sicherheitslücken: Du erfährst, worauf es wirklich ankommt.
Warum Sicherheit beim Plugin-Entwickeln kritisch ist
Shopware 6 Plugins haben oft weitreichende Zugriffe auf das System: Kundendaten, Bestellungen, Zahlungsinformationen. Ein unsicheres Plugin kann zum Einfallstor für Angreifer werden und nicht nur deinen Ruf, sondern auch den deiner Kunden gefährden.
Die gute Nachricht: Mit den richtigen Praktiken lassen sich die meisten Sicherheitsprobleme von Anfang an vermeiden.
Input-Validierung: Niemals Benutzereingaben vertrauen
Die goldene Regel der Webentwicklung gilt auch, wenn du ein Shopware 6 Plugin entwickeln willst: Vertraue niemals Benutzereingaben. Jede Eingabe muss validiert und sanitisiert werden.
Symfony Validator nutzen
Shopware 6 nutzt den Symfony Validator. Definiere deine Validierungsregeln direkt in Entity-Klassen:
<?php declare(strict_types=1);
namespace MyPlugin\Core\Content\Example;
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class ExampleEntity extends Entity
{
#[Assert\NotBlank]
#[Assert\Length(min: 3, max: 255)]
private string $name;
#[Assert\Email]
private string $email;
#[Assert\Regex(
pattern: '/^[a-zA-Z0-9_-]+$/',
message: 'Only alphanumeric characters allowed'
)]
private string $identifier;
}
Request-Daten validieren
In Controllern solltest du Request-Parameter explizit validieren:
<?php declare(strict_types=1);
namespace MyPlugin\Storefront\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Shopware\Storefront\Controller\StorefrontController;
#[Route(defaults: ['_routeScope' => ['storefront']])]
class ExampleController extends StorefrontController
{
#[Route(path: '/example/save', name: 'example.save', methods: ['POST'])]
public function save(Request $request): Response
{
$data = $request->request->all();
// Explizite Validierung
if (empty($data['name']) || strlen($data['name']) > 255) {
throw new \InvalidArgumentException('Invalid name');
}
// Whitelist-Ansatz: Nur erwartete Felder verarbeiten
$allowedFields = ['name', 'email', 'description'];
$filtered = array_intersect_key($data, array_flip($allowedFields));
// Weitere Verarbeitung...
}
}
SQL-Injection vermeiden: DAL richtig einsetzen
Einer der größten Vorteile beim Shopware 6 Plugin entwickeln ist das Data Abstraction Layer (DAL). Es verhindert SQL-Injection automatisch – wenn du es richtig nutzt.
Richtig: DAL-Criteria verwenden
<?php declare(strict_types=1);
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
// RICHTIG: Parametrisierte Queries durch DAL
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('email', $userInput));
$result = $this->exampleRepository->search($criteria, $context);
Falsch: Raw SQL mit unescapten Werten
<?php declare(strict_types=1);
// FALSCH: Niemals so machen!
$sql = "SELECT * FROM user WHERE email = '" . $userInput . "'";
$connection->executeQuery($sql);
Falls du doch Raw SQL brauchst (sehr selten), nutze Prepared Statements:
<?php declare(strict_types=1);
$sql = "SELECT * FROM custom_table WHERE identifier = :identifier";
$result = $connection->executeQuery($sql, ['identifier' => $userInput]);
XSS-Schutz in Templates
Cross-Site-Scripting (XSS) ist ein häufiges Problem. Shopware nutzt Twig, das automatisch Output-Escaping bietet.
Automatisches Escaping nutzen
{# SICHER: Automatisches HTML-Escaping #}
<p>{{ userInput }}</p>
{# UNSICHER: Raw-Output nur für vertrauenswürdige Daten #}
<p>{{ trustedHtml|raw }}</p>
JavaScript-Context beachten
{# UNSICHER in JavaScript-Context #}
<script>
var data = "{{ userInput }}";
</script>
{# BESSER: JSON-Encoding #}
<script>
var data = {{ userInput|json_encode|raw }};
</script>
ACL: Berechtigungen korrekt implementieren
Beim Shopware 6 Plugin entwickeln für die Administration sind Access Control Lists (ACL) unverzichtbar.
ACL-Ressourcen definieren
Definiere ACL-Privileges in deiner plugin.xml oder per Code:
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<admin>
<privileges>
<privilege key="my_plugin.viewer">
<resource>my_custom_entity</resource>
<privilege>read</privilege>
</privilege>
<privilege key="my_plugin.editor">
<resource>my_custom_entity</resource>
<privilege>update</privilege>
</privilege>
</privileges>
</admin>
</plugin>
ACL in API-Routes prüfen
<?php declare(strict_types=1);
namespace MyPlugin\Core\Api;
use Symfony\Component\Routing\Annotation\Route;
use Shopware\Core\Framework\Routing\Annotation\Acl;
#[Route(defaults: ['_routeScope' => ['api']])]
class ExampleApiController
{
#[Route(
path: '/api/_action/my-plugin/data',
name: 'api.action.my_plugin.data',
methods: ['GET']
)]
#[Acl(['my_plugin.viewer'])]
public function getData(): JsonResponse
{
// Nur Nutzer mit my_plugin.viewer Berechtigung kommen hier rein
}
}
CSRF-Protection
Shopware 6 bietet CSRF-Schutz für Formulare. Nutze ihn konsequent:
{% block example_form %}
<form method="post" action="{{ path('example.save') }}">
{{ sw_csrf('example.save') }}
<input type="text" name="name" required>
<button type="submit">Speichern</button>
</form>
{% endblock %}
Im Controller wird das Token automatisch validiert, wenn du die Route entsprechend konfigurierst.
Secrets und API-Keys sicher speichern
Niemals API-Keys oder Secrets hardcoded im Code speichern!
System-Config nutzen
<?php declare(strict_types=1);
namespace MyPlugin\Service;
use Shopware\Core\System\SystemConfig\SystemConfigService;
class ApiService
{
public function __construct(
private SystemConfigService $systemConfig
) {}
public function callApi(): void
{
// API-Key aus Plugin-Config laden
$apiKey = $this->systemConfig->get('MyPlugin.config.apiKey');
if (empty($apiKey)) {
throw new \RuntimeException('API-Key not configured');
}
// API-Call mit Key...
}
}
Definiere die Config in config.xml mit type="password" für sensible Daten:
<input-field type="password">
<name>apiKey</name>
<label>API Key</label>
<label lang="de-DE">API-Schlüssel</label>
</input-field>
Häufige Sicherheitsfehler beim Shopware 6 Plugin entwickeln
1. Fehlende Context-Prüfung
// FALSCH: Sales-Channel-Context in Admin-Kontext verwenden
public function process(SalesChannelContext $context): void
{
// Kann zu Rechte-Eskalation führen
}
// RICHTIG: Context-Typ prüfen
public function process(Context $context): void
{
if (!$context->getSource() instanceof AdminApiSource) {
throw new \RuntimeException('Admin access required');
}
}
2. Ungeschützte API-Endpoints
Jeder API-Endpoint braucht explizite Berechtigungsprüfung – entweder per ACL oder manuelle Validierung.
3. File-Upload ohne Validierung
// IMMER Dateityp, Größe und Inhalt validieren
$allowedMimeTypes = ['image/jpeg', 'image/png'];
$maxSize = 5 * 1024 * 1024; // 5MB
if (!in_array($file->getMimeType(), $allowedMimeTypes)) {
throw new \InvalidArgumentException('Invalid file type');
}
Dependency-Management und Updates
Halte deine Dependencies aktuell. Nutze composer audit regelmäßig:
composer audit
Definiere in deiner composer.json Versions-Constraints, die Security-Updates erlauben:
{
"require": {
"guzzlehttp/guzzle": "^7.5"
}
}
Testing: Sicherheit automatisiert prüfen
Schreibe Tests, die auch Sicherheitsaspekte abdecken:
<?php declare(strict_types=1);
namespace MyPlugin\Tests\Unit;
use PHPUnit\Framework\TestCase;
class SecurityTest extends TestCase
{
public function testSqlInjectionPrevention(): void
{
$maliciousInput = "'; DROP TABLE users; --";
// Test, dass Input korrekt escaped wird
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('name', $maliciousInput));
// Weitere Assertions...
}
}
Fazit: Sicherheit von Anfang an mitdenken
Wenn du ein Shopware 6 Plugin entwickeln willst, ist Sicherheit kein nachträglicher Gedanke, sondern muss von Beginn an Teil deiner Architektur sein. Die wichtigsten Punkte:
- Nutze das DAL statt Raw SQL
- Validiere alle Eingaben mit Symfony Validator
- Implementiere ACL-Rechte für Admin-Funktionen
- Escapen Output in Twig-Templates
- Speichere Secrets in der System-Config
- Halte Dependencies aktuell
Mit diesen Best Practices schaffst du eine solide Grundlage für sichere und professionelle Shopware 6 Plugins.
Du arbeitest an einem Shopware 6 Projekt und brauchst Unterstützung bei der Plugin-Entwicklung? Ich helfe dir gerne – mit über 10 Jahren Erfahrung in E-Commerce und maßgeschneiderten Shopware-Lösungen.