The Laravel PHP framework is known for its simple yet elegant syntax, making it a popular choice for rapid web app development. However, without proper security measures, Laravel applications can become vulnerable to various attacks. In this article, we will explore 11 Laravel security best practices and offer strategies that every laravel developer should implement to safeguard their application.
Security is a huge topic, and this article won’t cover everything. Still, I’ll try to share as many practical tips and best practices as I can.
11 Laravel Security Best Practices
Here are 11 essential security best practices you should apply to protect your Laravel application.
#1. Do Not Keep Your .env File in Your Project Repository :
Your .env file contains important and private information. Make sure to exclude it from being tracked by adding it to the .gitignore file.
Most data leaks originate from within the company. It is recommended to use a password manager to securely share credentials instead.
If you need to share sensitive information with your team, choose a password manager known for its strong security measures.
#2. Keep Laravel Up to Date
It’s important to regularly update Laravel to ensure you have the latest security features. Make sure you’re using a version of Laravel that is still receiving updates to stay protected against potential security vulnerabilities.
Keeping Laravel up to date involves several steps. Here’s a simple guide to help you:
Check the Current Version:
Use the following command to check the current version of your Laravel installation :
php artisan --version
Update Composer Dependencies:
Update your composer.json
file to specify the latest version of Laravel. For example:
"require": { "laravel/framework": "^10.0" }
Run the Composer update command:
composer update
Check for Deprecated Features:
Review the Laravel upgrade guide for deprecated features and breaking changes. The upgrade guide is available in the official documentation.
Run Database Migrations:
If the update includes database changes, run the migrations:
php artisan migrate
Test Your Application:
Thoroughly test your application to ensure that everything works as expected after the update. Automated tests can be particularly useful here.
Update Configuration Files:
Check for any new configuration options or changes in the configuration files. Merge any necessary changes from the new configuration files into your existing ones.
Update Frontend Dependencies:
If you are using Laravel Mix or any other frontend build tools, make sure to update those dependencies as well:
npm update
#3. Keep Your First and Third-party Packages Up to Date
Having access to many packages from Laravel’s ecosystem and community packages does make development easier, but outdated packages pose serious security risks. When packages aren’t updated, they may contain vulnerabilities such as:
- Remote Code Execution (RCE): Malicious actors can inject and execute arbitrary code, compromising your system.
- Cross-Site Scripting (XSS): Attackers can inject malicious scripts into web pages viewed by other users, leading to data theft.
- SQL Injection: Poorly maintained packages may allow attackers to manipulate database queries, risking unauthorized access to your database.
- Authentication Bypass: Weak or outdated authentication mechanisms may allow unauthorized users to gain access to sensitive areas.
- Denial of Service (DoS): Vulnerabilities in packages allow attackers to crash your application, which blocks user access.
When you regularly update your packages and use security tools like composer audit
, you can detect these vulnerabilities early and apply necessary security patches.
#4. Disable Debug Messages in Production
Make sure to set these two environment variables correctly when your app is live:
APP_ENV=production
APP_DEBUG=false
This is important to ensure that sensitive information about your app’s setup and design is not accidentally exposed. Debug messages often contain such details, so it’s best to keep them hidden in a production environment.
Exposed debug messages can reveal critical information like database credentials, Laravel Telescope access, and your application’s architecture, making it easier for attackers to exploit vulnerabilities and gain unauthorized access to your system.
#5. Don’t Send Sensitive Information to Error Monitoring Tools
Discussing private details in debug messages is still a problem that has not been completely resolved. When using a tool for tracking errors, such as Flare, it is important to hide this sensitive information there too.
With the release of PHP 8.2, a new feature called \SensitiveParameter was introduced. Developers can use this attribute to hide any confidential data from the stack trace, which is typically shared with error tracking tools.
Suppose your application includes a function that processes user data, and you accidentally log a stack trace with sensitive parameters like user IDs or payment details.
By marking these parameters with the \SensitiveParameter
attribute, you can prevent this confidential information from appearing in error logs or stack traces. This ensures that even if an error occurs, sensitive details are not exposed to potential attackers or unauthorized users.
#6. Limit Access to Certain Areas of Your App Using Policies
In Laravel, policies help to control access to various actions on your models. They allow you to define who can perform specific actions on resources based on user roles or attributes.
For example, policies ensure that users can only access or modify resources they are authorized to.
Here’s how it works:
- Defining a Policy: In the
PostPolicy
class, theupdate
method checks if the user trying to update a post is the owner of that post. If the user’s ID matches the post’s owner ID, they are authorized to proceed. - Using a Policy: In the
PostController
, theupdate
method uses$this->authorize('update', $post)
to check if the current user has permission to update the given post. If the user is authorized, the update process continues; otherwise, they are denied access.
This approach keeps your code secure and ensures that only authorized users can perform specific actions.
Example:
// app/Policies/PostPolicy.php
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
// app/Http/Controllers/PostController.php
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// ...
}
Be sure to review the documentation to learn more about the rules.
#7. Keep Your Forms Safe From Cross-site Request Forgery (CSRF) Attacks.
You should consider using the @csrf
Blade directive in your forms. This directive adds a hidden field with a unique token to your form, which helps verify that the form submission is coming from your own website and not an external source.
CSRF (Cross-Site Request Forgery) attacks take advantage of unprotected forms by misleading users into submitting forms on a website where they are already logged in, often without them realizing it.
This can let attackers carry out actions as if they were the user, which can lead to serious problems.
Laravel comes with a feature called VerifyCsrfToken middleware that automatically checks for a special token on all the pages of your website to make sure form submissions are real.
This middleware helps protect against CSRF attacks on all forms, unless it is specifically turned off for certain forms.
<form method="POST" action="{{ route('register') }}">
@csrf
<p>
<label for="name">First Name</label>
<input type="text" id="name" name="name" value="{{ old('name') }}" required />
</p>
…
</form>
Learn more about : CSRF protection
#8. Validate User’s Input
Validation rules are important guidelines that can help you clean and check the data sent by your users. It’s essential to be cautious and never fully rely on the input provided by users.
use Illuminate\Http\Request;
class PostController extends Controller
{
function store(Request $request)
{
$validated = $request->validate([
'user_id' => 'required|exists:users,id',
'title' => 'required|string|min:3|max:255',
'content' => 'required|string|min:3',
'published' => 'sometimes|boolean'
]);
Post::create($validated);
//
}
}
Learn more about validation.
#9. Be Careful With Uploaded Files
Here are some suggestions to keep in mind:
- Make sure to check the files MIME type.(Validation rule of laravel)
$request->validate([
'file' => 'required|mimes:gif,jpeg,png,webp',
]);
- Avoid allowing public access to uploaded files, especially when using the local file driver.
- Consider uploading files to a different server. This can help prevent hackers from running unauthorized code or accessing important information even if they manage to bypass your security measures.
- If possible, delegate the task of file uploads to a trusted third-party service known for their strong security practices and commitment to never exposing data.
10. Encrypt the Payload of Your Jobs
When you dispatch a job, its payload is stored in the database, Redis, or another system you specified for Laravel to use through the QUEUE_DRIVER setting.
This data might include sensitive information that could be viewed and potentially misused by any of your staff. As I mentioned earlier in this post, data breaches often start with employees.
Luckily, Laravel provides the Illuminate\Contracts\Queue\ShouldBeEncrypted Contract, which automatically encrypts the data.
To ensure that no one can decrypt it, ensure that the Laravel’s APP_KEY specified in your .env file is only accessible to a select few trusted individuals.
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
class SomeJob implements ShouldQueue, ShouldBeEncrypted
{
//
}
#11. Do Regular Security Audit
This method is highly effective and should be required for those truly concerned about security. Getting feedback from outside sources can provide valuable insights.
Security audits come at a cost, which may be justified for large companies to avoid even higher fines. Building a strong reputation and earning the trust of your customers is priceless.
FAQ
What is SQL Injection?
SQL injection is a kind of attack where a hacker adds malicious SQL commands into a program’s database request.
What is the Eloquent ORM?
Eloquent Object Relational Mapper (ORM) is a part of the PHP Laravel framework that makes it easier to work with databases. It offers a simple way to write code for common database tasks.
What is a Real Life Example of XSS Attack?
A real-life example of an XSS attack is when a malicious user injects harmful code into a website, tricking unsuspecting visitors into clicking on it. This code can then steal personal information or take control of the user’s device.
What is an Injection Attack?
Injection attacks happen when hackers take advantage of weak spots in an application to deliver malicious code into a system.