Securing Your Laravel Application Smartly With UUID

Published Dec 27, 2017Last updated Feb 20, 2018
Securing Your Laravel Application Smartly With UUID

Heyo! We will be learning a smart way of securing our Laravel Application and making it difficult to be hacked.

UUID will help us achieve this.

I am sure you are thinking about what UUID means. It simply means Universal Unique Identifier and what it does, basically, is prevent us from exposing our ID to the world. The UUID has 36 characters and is very difficult to get into by the black hats.

In this tutorial, we will be learning how to work with UUIDs with a simple directory list appilcation that stores the names of dogs.

Let's get started.

Requirements

  • Laravel Installed (5.5.*)
  • PHP (>=7.1)
  • Text Editor You Love

Setup Application

We will start by creating a Laravel application with the command below:

laravel new dogApp

or you can use:

composer create-project --prefer-dist laravel/laravel

After doing this, you should fire up your text editor and let us get our hands dirty.

Model and Migrations

At this point, it is important we create models and migrations for our directory application. First, we will create a model and migration file for storing the names of the dogs. Run the command below:

php artisan make:model Dog -m

After doing this, go to your database/migrations folder and open the migration file we just created. Mine is called 2017_12_06_011644_create_dogs_table.php.

Add columns to the table to be created. Let your up method look like the one below:

public function up()
   {
       Schema::create('dogs', function (Blueprint $table) {
           $table->increments('id');
           $table->string('dog_name');
           $table->timestamps();
       });
   }

After doing that, go to your .env and make sure your database configuration is perfect. Then, run the command below.

php artisan migrate

That command will create tables in your database.

Working With Controllers

Now, to speed this tutorial up, we will create a controller called DogController.php and then we will create methods that handle adding new dog names, listing the dog names in the database, and also, editing the dog.

First, run php artisan make:controller DogController to create the controller file, then go to the app/Http/Controllers directory to open DogController.php.

Finally, in this section, make sure your controller looks like the one below:

<?php

namespace App\Http\Controllers;

use App\Dog;
use Illuminate\Http\Request;

class DogController extends Controller
{
    public function create()
    {
        return view('dog.new');
    }

    public function store(Request $request)
    {
        $dog = new Dog();
        $dog->dog_name = $request->name;

        if ($dog->save()) {
            return redirect()->back()->with('success','Dog with name: '.$dog->dog_name.' was added successfully');
        } else {
            return redirect()->back()->with('error','Sorry! We apologize for this error');
        }
    }

    public function show()
    {
        $dogs = Dog::all();
        return view('dog.list',['dogs' => $dogs]);
    }

    public function edit($id)
    {
        $dog = Dog::find($id);
        return view('dog.edit',['dog' => $dog]);
    }

    public function update(Request $request,$id)
    {
        $dog = Dog::find($id);
        $dog->dog_name = $request->name;

        if ($dog->save()) {
            return redirect()->back()->with('success','Dog with name: '.$dog->dog_name.' was updated successfully');
        } else {
            return redirect()->back()->with('error','Sorry! We apologize for this error');
        }

    }
}

Routing

Before creating the views, let us create routes. Go to the routes folder and open web.php file. Erase everything you have in the file and add the following below:

<?php

Route::get('/', [
    'uses' => 'DogController@create'
]);

Route::post('/create/', [
    'uses' => 'DogController@store'
]);

Route::get('/list', [
    'uses' => 'DogController@show'
]);

Route::get('/edit/{id}', [
    'uses' => 'DogController@edit'
]);

Route::post('/update/{id}', [
    'uses' => 'DogController@update'
]);

Views

We will be creating a series of views, but I would make it a lot easier. Just navigate to the resources/views directory then we'll start creating views for our app.

  1. Create thelayouts folder, then create the master.blade.php file in the layouts folder and add the following:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="Dog Directory List APp">
    <meta name="author" content="goodnesskay">
    <link rel="icon" href="favicon.ico">
    <title>Dog Directory List App</title>

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
<div style="margin-top:50px;" class="container">
    <div class="row">
        @include('partials.message')
        @yield('content')
    </div>
</div>
</body>
</html>
  1. Create dog folder, then create new.blade.php, list.blade.php, and edit.blade.php files in dog folder.
  • Add the code below to new.blade.php file:
@extends('layouts.master')
@section('content')
    <div class="col-md-8">
        <form action="{{ url('create') }}" method="post">
            {{ csrf_field() }}
            <h2 class="text-center">Create New Dog</h2><br>
            <label for="dogName" class="sr-only">Dog's Name</label>
            <input type="text"  class="form-control" name="name" placeholder="Dog Name" required autofocus>
            <br>
            <button class="btn btn-lg btn-primary btn-block" type="submit">Create</button>
        </form>
        <hr>
        <div class="text-center">
            <a href="{{ url('list') }}" class="btn btn-success">View Dog List</a>
        </div>
    </div>
@endsection
  • Also, add the code below to list.blade.php file:
@extends('layouts.master')
@section('content')
    <div class="col-md-12">
            <div class="panel panel-default panel-table">
                <div class="panel-heading">
                    <div class="row">
                        <div class="col col-xs-6">
                            <h3 class="panel-title">Panel Heading</h3>
                        </div>
                        <div class="col col-xs-6 text-right">
                            <a href="{{ url('/') }}" class="btn btn-sm btn-primary btn-create">Add New</a>
                        </div>
                    </div>
                </div>
                <div class="panel-body">
                    <table class="table table-striped table-bordered table-list">
                        <thead>
                        <tr>
                            <th class="hidden-xs">#</th>
                            <th>Name</th>
                            <th>Action</th>
                        </tr>
                        </thead>
                        <tbody>
                        @foreach($dogs as $dog)
                            <tr>
                                <td class="hidden-xs">#</td>
                                <td>{{ ucfirst($dog->dog_name) }}</td>
                                <td><a href="{{ url('edit',['id' => $dog->id ]) }}">Edit</a></td>
                            </tr>
                        @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
  • Then, add the code below to edit.blade.php file:
@extends('layouts.master')
@section('content')
    <div class="col-md-8">
        <form action="{{ url('update',['id' => $dog->id ]) }}" method="post">
            {{ csrf_field() }}
            <h2 class="text-center">Edit Dog Record With Name "{{ $dog->dog_name }}" </h2><br>
            <label for="dogName" class="sr-only">Dog's Name</label>
            <input type="text"  class="form-control" name="name" value="{{ $dog->dog_name }}" placeholder="Dog Name" required autofocus>
            <br>
            <button class="btn btn-lg btn-primary btn-block" type="submit">Update</button>
        </form>
        <hr>
        <div class="text-center">
            <a href="{{ url('list') }}" class="btn btn-success">View Dog List</a>
        </div>
    </div>
@endsection
  1. Create the partials folder, then create message.blade.php file in the partials folder for alert messages once requests are made. Add the following to the file:
<div class="container">
    @if (session('success'))
        <div class="notice notice-success">
            <strong>Success! </strong>{{ session('success') }}
        </div>
    @endif
    @if (session('error'))
        <div class="notice notice-success">
            <strong>Error! </strong>{{ session('error') }}
        </div>
    @endif
</div>
<style type="text/css">
    .notice {
        padding: 15px;
        background-color: #fafafa;
        border-left: 6px solid #7f7f84;
        margin-bottom: 10px;
        -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2);
        -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2);
        box-shadow: 0 5px 8px -6px rgba(0,0,0,.2);
    }
    .notice-success {
        border-color: #80D651;
    }
    .notice-success>strong {
        color: #80D651;
    }
    .notice-danger {
        border-color: #d73814;
    }
    .notice-danger>strong {
        color: #d73814;
    }
</style>

Now, The Problem

The problem in this application is simple. From the URL, I can access any data from the database via id and any anonymous user can make changes to it. How do we solve this?

Install Package and Configure

We will be working with a package that simply helps us create UUIDs with ease. You can find the package here. Install the package by running the command below:

composer require webpatser/laravel-uuid
  • Open config/app.php file and add 'Uuid' => Webpatser\Uuid\Uuid::class, to the aliases array.

Update Migration

Now, we have to make changes to our migration file so it can cater to the UUIDs we want to create.
Open your migration file and replace $table->increments('id'); with the below:

$table->uuid('id');
$table->primary('id');

After doing this, go ahead to run php artisan migrate:refresh to reset and re-run all migrations.

Create Trait

Now, we have to create a trait file that handles the creation of UUIDs once the event for creating a new resource is triggered. Go to app folder and create a PHP traits file called Uuids.php, then add the code below:

namespace App;
use Webpatser\Uuid\Uuid;
trait Uuids
{
    protected static function boot()
    {
        parent::boot();
        static::creating(function ($model) {
            $model->{$model->getKeyName()} = Uuid::generate()->string;
        });
    }
}

Updating Models

We need to update our models to carry out the action we want it to carry. We will add the following to the body of our class in app/Dog.php.

  use Uuids;
    /**
     * Set auto-increment to false.
     *
     * @var bool
     */
    public $incrementing = false;

What we did here is to use the trait file we created and set auto-incrementing to false.

Run Your More Secured App

Now, run your app with php artisan serve. Fire up your browser and test your application. Go to the edit page of the resource you created and check the URL. Yippee! We have our UUID working and it is now difficult for a user without access to the page to update.

Discover and read more posts from Goodness Toluwanimi Kayode
get started