Cross-Site Scripting (XSS)
What is cross-site scripting?
XSS (Cross-Site Scripting) is a security vulnerability that affects web applications. It allows an attacker to inject malicious code, typically JavaScript, into a legitimate web page. That code is then executed in the browsers of other users who visit the affected page, which can lead to serious consequences.
Impact of XSS
The impact of an XSS attack can vary, but common effects include:
- Session theft: stealing the user's session cookies, which can allow impersonation and account takeover.
- Malicious redirects: redirecting the user to a malicious website (phishing or drive-by attacks).
- Content tampering: modifying the page content to show false or misleading information.
- Unauthorized actions: performing actions as the user (sending messages, making purchases, etc.).
How does an XSS attack happen?
An XSS attack happens when a Laravel web application does not properly validate and sanitize user-provided data before rendering it in the UI. If an attacker can inject malicious code into those inputs, the user's browser may execute it without realizing it is malicious.
There are three main types of XSS:
- Reflected (Non-Persistent) XSS: malicious code is injected into a request and reflected back in the server response. This often happens via URL parameters or forms.
- Stored (Persistent) XSS: malicious code is stored on the server (for example, in a database) and shown to all users who view the affected page.
- DOM-based XSS: malicious code is injected directly into the browser's DOM without going through the server, often due to unsafe client-side rendering.
Mitigation for Cross-Site Scripting (XSS)
Laravel provides fundamental building blocks to mitigate XSS. A practical approach combines (1) safe handling at input, (2) safe output encoding, and (3) HTTP protections like Content-Security-Policy (CSP). Examples:
Storing data in a controller
- Validate user input (official Laravel Validation).
- Sanitize input using
e()(Laravel Strings -e()). - Trim whitespace using
trim()(PHPtrim()). - Remove HTML tags using
strip_tags()(PHPstrip_tags()). - Use Eloquent ORM to create records (Laravel Eloquent).
# CommentController.php // Input validation$validated = $request->validate([ 'comment' => 'required|string',]); // Input sanitization$comment = strip_tags(trim(e($validated['comment']))); // Use Eloquent ORMComment::create([ 'comment' => $comment,]);
Rendering data in a view
- Use
e()to encode output before displaying it (Laravel Strings -e()). - Use Blade's
{{ $variable }}syntax to safely display data (Blade - Displaying Data).
# comment.blade.php @foreach ($comments as $comment)<article class="..."> <footer>...</footer> {{-- Display encoded output --}} <p class="...">{{ e($comment->comment) }}</p></article>@endforeach
Create a middleware to set secure HTTP headers with CSP
- Create a security middleware (Laravel Middleware).
# terminal php artisan make:middleware SecurityHeadersMiddleware
- Configure secure HTTP headers.
# SecurityHeadersMiddleware.php namespace App\Http\Middleware; use Closure;use Illuminate\Http\Request;use Symfony\Component\HttpFoundation\Response; class SecurityHeadersMiddleware{ /** * Handle an incoming request. * * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next */ public function handle(Request $request, Closure $next): Response { $response = $next($request); $response->headers->set('Content-Security-Policy', "default-src 'self';". "script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com/;". "style-src 'self' 'unsafe-inline' https://fonts.bunny.net;". "img-src 'self' https://laravel.com https://flowbite.com;". "font-src 'self' https://fonts.bunny.net;" ); return $response; }}
- Register the middleware in Laravel configuration.
# bootstrap/app.php use App\Http\Middleware\SecurityHeadersMiddleware; ... ->withMiddleware(function (Middleware $middleware) { $middleware->append(SecurityHeadersMiddleware::class); })...
More details about CSP directives
Commonly used directives:
default-src: a fallback policy for loading resources unless more specific directives are set.script-src: controls which scripts can be loaded and executed.style-src: controls which CSS styles can be loaded and applied.img-src: controls from where images can be loaded.font-src: controls from where fonts can be loaded.
For a complete list of directives, see Mozilla's documentation (CSP).