Escaping content to prevent cross-site scripting (XSS)

Cross-site scripting (XSS) attacks happen when attackers are able to place client-side JavaScript code in a page viewed by other users. In our application, assuming that the name of our cat is not escaped, if we enter the following snippet of code as the value for the name, every visitor will be greeted with an alert message everywhere the name of our cat is displayed:

Evil Cat <script>alert('Meow!')</script>


While this is a rather harmless script, it would be very easy to insert a longer script or link to an external script that steals the session or cookie values. To avoid this kind of attack, you should never trust any user-submitted data or escape any dangerous characters. You should favor the double-brace syntax ({{ $value }}) in your Blade templates, and only use the {!! $value !!} syntax, where you’re certain the data is safe to display in its raw format.

Avoiding SQL injection

An SQL injection vulnerability exists when an application inserts arbitrary and unfiltered user input in an SQL query. This user input can come from cookies, server variables, or, most frequently, through GET or POST input values. These attacks are conducted to access or modify data that is not normally available and sometimes to disturb the normal functioning of the application.

By default, Laravel will protect you against this type of attack since both the query builder and Eloquent use PHP Data Objects (PDO) class behind the scenes. PDO uses prepared statements, which allows you to safely pass any parameters without having to escape and sanitize them.

In some cases, you might want to write more complex or database-specific queries in SQL. This is possible using the DB::raw method. When using this method, you must be very careful not to create any vulnerable queries like the following one:


Route::get('sql-injection-vulnerable', function() {
 $name = "'Bobby' OR 1=1";
 return DB::select(
 DB::raw("SELECT * FROM cats WHERE name = $name"));


To protect this query from SQL injection, you need to rewrite it by replacing the parameters with question marks in the query and then pass the values in an array as a second argument to the raw method:


Route::get('sql-injection-not-vulnerable', function() {
 $name = "'Bobby' OR 1=1";
 return DB::select(
 DB::raw("SELECT * FROM cats WHERE name = ?", [$name]));

The preceding query is known as a prepared statement, as we define the query and what parameters are expected, and any harmful parameters that would alter the query or data in the database in an unintended way are sanitized.

Chapter 2 of 3