Security Logo

Laravel Security Best Practices – A List of Tips for Coding

In this blog we describe a few easy security mistakes and how to fix them.

1. Not Using HTTPS

  • Mistake: Serving your Laravel application over HTTP instead of HTTPS leaves it vulnerable to man-in-the-middle (MITM) attacks where sensitive data can be intercepted.
  • Solution: Always use HTTPS in production environments by setting up SSL certificates and forcing HTTPS by adding this to the($this->app->environment(‘production’)) { \URL::forceScheme(‘https’); }

2. Using Weak Encryption Keys

  • Mistake: Failing to set a strong APP_KEY in the .env file, which is crucial for encryption, session security, and password hashing.
  • Solution: Set a strong application key using the following command:bash
    php artisan key:generate Ensure this key remains secret and never shared publicly.

3. Not Validating Input Data

  • Mistake: Skipping input validation can open your application to various attacks such as SQL injection, cross-site scripting (XSS), and other vulnerabilities.
  • Solution: Use Laravel’s built-in validation to ensure that all input data is sanitized and follows the expected format.php
    $request->validate([ 'email' => 'required|email', 'password' => 'required|min:8', ]);

4. Storing Sensitive Data in the Codebase

  • Mistake: Hardcoding sensitive data such as API keys, database credentials, or private tokens directly in the codebase can lead to security breaches if the code is shared or exposed.
  • Solution: Store sensitive information in environment variables (.env) and use Laravel’s configuration system to load them. Never commit the .env file to version control.

5. Improper File Permissions

  • Mistake: Allowing write permissions on sensitive files, such as the .env file, can lead to unauthorized users gaining access to configuration data.
  • Solution: Set proper file permissions for your Laravel project. Generally, you want directories like storage and bootstrap/cache to be writable by the web server, but other files should not be writable.

6. Not Escaping User-Generated Content

  • Mistake: Failing to escape user-generated data before rendering it on the page can lead to XSS attacks.
  • Solution: Use Laravel’s built-in templating engine, Blade, which automatically escapes output. If you need to disable escaping (which is rare), ensure the content is properly sanitized.
{{ $userInput }}  // Escaped
{!! $userInput !!} // Unescaped (Be careful)

7. Not Limiting Mass Assignment

  • Mistake: Allowing mass assignment on models without properly controlling which fields are fillable can let attackers modify unintended fields.
  • Solution: Use the $fillable or $guarded properties in your Eloquent models to specify which fields can be mass-assigned.php
    protected $fillable = ['name', 'email'];

8. Exposing Debug Mode in Production

  • Mistake: Leaving APP_DEBUG=true in the .env file in production environments can expose sensitive information such as stack traces, database credentials, and API keys in error messages.
  • Solution: Always set APP_DEBUG=false in production, and consider using error logging to capture and safely store errors without revealing them publicly.

9. Insecure File Upload Handling

  • Mistake: Not properly validating and sanitizing uploaded files can lead to malicious file uploads, which can execute server-side code.
  • Solution: Use Laravel’s file upload validation rules to check the type, size, and other attributes of uploaded files.php
    $request->validate([ 'file' => 'required|file|mimes:jpg,png,pdf|max:2048', ]);

Store the files outside of the public directory and use secure methods to access them.

10. Failing to Implement Rate Limiting

  • Mistake: Not implementing rate limiting on sensitive routes like login or API endpoints can expose your application to brute force attacks or denial-of-service (DoS) attacks.
  • Solution: Use Laravel’s built-in rate limiting middleware to protect your routes.php
    Route::middleware('throttle:10,1')->group(function () { Route::post('/login', 'AuthController@login'); });

11. Unnecessary Exposure of Sensitive Endpoints

  • Mistake: Leaving sensitive routes like /telescope/horizon, or /admin accessible to the public can expose valuable debugging or administrative tools.
  • Solution: Protect these routes by restricting access via middleware or IP whitelisting. For example, limit access to Laravel Telescope to local environments:php
    if (app()->environment('local')) { Telescope::auth(function () { return true; }); }

12. Outdated Laravel and Dependencies

  • Mistake: Running outdated versions of Laravel or its dependencies can leave known vulnerabilities unpatched.
  • Solution: Regularly update Laravel and its dependencies by running composer update, and monitor security advisories for packages you use.

13. Not Using CSRF Protection

  • Mistake: Failing to implement Cross-Site Request Forgery (CSRF) protection can allow attackers to trick users into performing actions on their behalf.
  • Solution: Laravel includes CSRF protection by default for all POST, PUT, PATCH, and DELETE requests using the @csrf directive in forms.blade
    <form method="POST" action="/submit"> @csrf <button type="submit">Submit</button> </form>

14. Not Using Secure Password Hashing

  • Mistake: Storing passwords in plain text or using weak hashing algorithms makes your application vulnerable if the database is compromised.
  • Solution: Always use Laravel’s bcrypt (or argon2 for stronger security) for hashing passwords:php
    use Illuminate\Support\Facades\Hash; $hashedPassword = Hash::make($password);

15. Ignoring Logs and Alerts

  • Mistake: Failing to monitor application logs for suspicious activities or errors can lead to missed security incidents.
  • Solution: Regularly check Laravel logs (storage/logs) and set up alerts for critical events. You can integrate Laravel with third-party monitoring tools like Sentry or New Relic for real-time monitoring.

16. Updating with $request->all()

A bit similar like point 7.

Although, it seems really convenient, when you update a user like this:

$user->update($request->all());

There is a security risk. For example, if you have a column this_is_an_admin=1, a user can set this variable via the browser’s Developer Console.

It would be better to only filter the right $request variable with:

$request->only(['name', 'newsletter_subscribed']);

Got any other security points? Let us know in the comments!

Leave a Comment

Your email address will not be published. Required fields are marked *

en_USEnglish
Scroll to Top