Tutorial
Secure Coding with Laravel
May 27, 2024
May 27, 2024
Coding is a dangerous job. Hackers are around every corner, eager to poke and prod every line of code created and published by a developer, always looking for that elusive vulnerability that will lead to immense wealth and power! Bwahahaha! But, coding doesn’t have to be dangerous if you follow the industry standard. Follow along and we'll teach you some of the tricks of the trade for writing secure code in one of our favorite web frameworks; Laravel.
Laravel is inherently a very secure framework. Its massive open source community is constantly publishing patches and updates to keep its codebase secure and relevant to the current security landscape. Vulnerabilities typically exist in websites created with the framework rather than the framework itself. We’ll look at a few security issues that developers may overlook when creating a Laravel web application. First, we’ll look at writing secure database queries, then we’ll learn about writing validators to protect against dangerous inputs. Finally, we’ll delve into writing security policies for authorization.
Database query injection attacks are a very common attack method used when attempting to exfiltrate sensitive database information from a server. Sometimes, they can even be used to launch remote-code execution (RCE) attacks on a server. Query injection vulnerabilities are caused by incorrect/missing user input validation leading to database query manipulation; which in turn leads to sensitive data leaks or unauthorized data changes. Laravel’s powerful and extremely easy to use ORM, Eloquent, contains the tools needed to combat these attacks. In raw PHP, parameterized queries are used to sanitize user input so it can’t be used to hijack queries. Parameterized queries are usually quite time consuming to set up, however. Eloquent performs this parameterization automatically.
It allows us to transform a parametrized query (SQL query sample) that looks like this:
$username = "Robert'); DROP TABLE Students;--";
$stmt = mysqli_prepare($dbc, "SELECT * FROM users WHERE username = ?");
mysqli_stmt_bind_param($stmt, "s", $username);
mysqli_stmt_execute($stmt);
$row = mysqli_stmt_fetch($stmt);
to a much simpler Eloquent query with automatic parameterized input:
$username = "Robert'); DROP TABLE Students;--";
User::where('username', $username)->first();
See the famous XKCD comic!
Although Laravel helps keep your database queries safe, you should always validate user inputs; both for database queries and anywhere else user inputs are being used to control backend functionalities. An industry faux pas is to ever trust user input. If no input validation is implemented for file uploads, hackers could DDOS your server or possibly even launch a remote code execution (RCE) attack if they can upload (and afterwards execute) PHP files. File name inputs that aren’t sanitized could possibly lead to path traversal attacks. Even ignoring the security aspect of input validation, it prevents the user-supplied input from being gibberish, such as a user inputting the word “cheeseburger” as their age.
Writing validators is simple and easy but they are also very powerful. A manually created validator is shown below:
$userData = [‘title’ => ‘some title’, ‘file’ => [some file]];
Validator::make($userData, [
'title' => 'required|string|max:255',
'file' => 'file|size:100|mimes:jpg,bmp,png',
])->validate();
For an even simpler appoarch, you can validate inputs directly on a request object as shown below:
$request->validate([
'title' => 'required|string|max:255',
'file' => 'file|size:100|mimes:jpg,bmp,png',
]);
With this code, simple validation controls separated by the pipe character ensure that titles are neither outrageously long nor omitted. Files are forced to be within a specified size and range of file types. There are many validator controls available to fit any use case; from regex checking to email format checking and everything in between.
Implementing authorization in a Laravel application is also easy with its extremely useful and robust security policy functionalities. With Laravel’s security policies and “gates”, backend functions and model viewing/editing can be blocked from prying eyes and only allow access to users who have been granted rights. After a few simple configuration steps, a security policy check (allowing only a user to change their own notes), will end up looking something like below.
public function update(?User $user, Note $note): bool
{
return $user?->id === $note->author_user_id;
}
The check can be easily called in any function that has a reference to the note model with the gate authorize function. In this example the check would look like this:
Gate::authorize('update', $note);
Laravel will automatically pass the current user and note model to the security policy function and verify that the user is authorized to update the note. If the check fails, Laravel will throw a 403 exception and go no further. The security policies can also be used as middleware and run the function before a page is even reached. For example, the code below wouldn’t allow an unauthorized user to view a secret note page.
Route::get('/secret-note/{note}', function (Note $note) {
// Page where the user can view a secret note
})->middleware('can:view,note');
These examples only scratch the surface of what Laravel’s authorization framework allows you to do. You can conditionally render blade files and much much more, but we hope this is enough to get you started!
These are just a few key features every developer should know, but Laravel offers much more, like CSRF protection and rate-limiting. Now it's time to use your new found knowledge to write secure code with Laravel!
If you want to learn more or need help with an app idea or existing project, contact us today.
Unlock Specialized Skills Through Team Augmentation
Friday, August 2, 2024
Unlock Specialized Skills Through Team Augmentation
Friday, August 2, 2024
Follow along as we learn the industry standards for writing secure web applications in Laravel.
Monday, May 27, 2024
Building apps is costly and time-consuming; Flutter simplifies focus, saves resources.
Friday, February 9, 2024