Errores de seguridad comunes en aplicaciones de Laravel

Introducción

En la mayoría de los casos, las vulnerabilidades de seguridad surgen solo por falta de conciencia, no por negligencia. Si bien descubrimos que la mayoría de los desarrolladores se preocupan por la seguridad, a veces no entienden cómo un patrón de código en particular puede generar vulnerabilidades, por lo que en el libro electrónico decidimos compartir los problemas de seguridad más comunes que vimos mientras ayudamos a varias startups a proteger sus aplicaciones. Laravel. Con cada ejemplo de ataque, también le mostraremos las mejores prácticas para proteger su aplicación de ataques. Esperamos que esta información sea útil para usted y su equipo de desarrollo.

Equipo CyberPanda

inyección SQL

Laravel proporciona un generador de consultas robusto y un ORM elocuente. Y, gracias a ellos, la mayoría de las solicitudes están protegidas por defecto en las aplicaciones, por lo tanto, por ejemplo, una solicitud como

Product::where('category_id', $request->get('categoryId'))->get();

se protegerá automáticamente ya que Laravel traducirá el código en una declaración preparada y se ejecutará.

Pero los desarrolladores suelen cometer el error de creer que Laravel protege contra todas las inyecciones de SQL, aunque hay algunos vectores de ataque que Laravel no puede proteger.

Estas son las razones más comunes de inyección de SQL que hemos visto en las aplicaciones modernas de Laravel durante nuestras auditorías de seguridad.

1.Inyección SQL a través del nombre de la columna

, , , Laravel , Query Builder Eloquent. , , , , .

Laravel:

PDO does not support binding column names. Therefore, you should never allow user input to dictate the column names referenced by your queries, including "order by" columns, etc. If you must allow the user to select certain columns to query against, always validate the column names against a white-list of allowed columns.

, SQL-:

$categoryId = $request->get('categoryId');
$orderBy    = $request->get('orderBy');

Product::query()
  ->where('category_id', $categoryId)
  ->orderBy($orderBy)
  ->get();

- orderBy

http://example.com/users?orderBy=id->test"' ASC, IF((SELECT count(*)
FROM users ) < 10, SLEEP(20), SLEEP(0)) DESC -- "'

SQL-:

select
  *
from `users`
order by `id`->'$."test"' ASC,
  IF((SELECT count(*) FROM users ) < 10, SLEEP(20), SLEEP(0))
DESC -- "'"' asc limit 26 offset 0

, Laravel*, , , Laravel , Query Builder .

, SQL-, - , , .

, «users» - "secretAnswer", SQL-.

2. SQL-

$id = $request->route('id');
$rules = [
    'username' => 'required|unique:users,name,' . $id,
];
$validator = Validator::make($request->post(), $rules);

Laravel $id , SQL-. " " > "SQL-".

3. SQL-

, , , , DB::raw . , , - . DB::raw - , , DB::getPdo()->quote.

:

public function update(Request $request) {
    $id = $request->route('id');

    $rules = [
        'username' => 'required|unique:users,username,' . $id,
    ];

    $validator = Validator::make($request->post(), $rules);

    if ($validator->fails()) {
        return response()->json($validator->errors(), 422);
    }

    $user = User::findOrFail($id);
    $user->fill($validator->validated());
    $user->save();

    return response()->json(['user' => $user]);
}

required|unique:users,username,'. $id? ! ()

, unique , . , $id , , . , , , .

1.

, - ID = 10|sometimes, required|unique:users,username,10|sometimes , - , .

2. DDOS REGEX

Regex ReDoS DDOS . , , , :

PUT /api/users/1,id,name,444|regex:%23(.*a){100}%23
{
    "username": "aaaaa.....ALOT_OF_REPETED_As_aaaaaaaaaa"
}

3. SQL-

SQL- . :

PUT /api/users/1,id,name,444|unique:users,secret_col_name_here
{
    "username": "secret_value_to_check"
}

, unique ( PDO) SQL- . Laravel .

:

  1. - , , ;

  2. (ID ), , .

XSS ( ) Laravel Blade

XSS 1990- , , - , , . , , XSS- :

Some text
<input onfocus='$.post("/admin/users", {name:"MaliciousUser", email:
"MaliciousUser@example.com", password: "test123", });' autofocus />
test

- . IP- , , /.

, XSS- Laravel.

Laravel Blade, XSS-, , :

// $name = 'John Doe <script>alert("xss");</script>';
<div class="user-card">
 <div> ... </div>
 <div>{{ $name }}</div>
 <div> ... </div>
</div>

Blade {{ }} . , :

<div class="user-card">
 <div> ... </div>
 <div>John Doe
&lt;script&gt;alert(&quot;xss&quot;);&lt;/script&gt;</div>
 <div> ... </div>
</div>

XSS. Laravel ( ) , XSS-, :

1. XSS {!! $userBio !!}

, HTML, {!! !!}:

// $userBio = 'Hi, I am John Doe <script>alert("xss");</script>';
<div class="user-card">
 <div> ... </div>
 <div>{!! $userBio !!}</div>
 <div> ... </div>
</div>

Laravel , $userBio JavaScript , XSS-.

:

  1. html , .

  2. , HTML, , htmlpurifier.org, HTML JS .

2. XSS a.href

, , , , XSS-:

1: javascript:code

// $userWebsite = "javascript:alert('Hacked!');";

<a href="{!! $userWebsite !!}" >My Website</a>

2: base64:

, .

// $userWebsite =
"data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg
==";

<a href="{!! $userWebsite !!}" >My Website</a>

(«Hacked!») , « -» ...

:

  1. , . http/https ;

  2. , http/https «#broken-link».

3. XSS

Blade , , HTML. , , , Laravel :

// Registering the directive code
Blade::directive('hello', function ($name) {
    return "<?php echo 'Hello ' . $name; ?>";
});

// user.blade.php file
// $name = 'John Doe <script>alert("xss");</script>';

@hello($name);

:

Laravel e(), , . 3 , Laravel . , XSS- Laravel, XSS-, , , React.js, Vue.js, javascript jQuery, XSS-.

Laravel

Eloquent, ORM, , . , , .

, , :

// app/Models/User.php file
class User extends Authenticatable
{
    use SoftDeletes;

    const ROLE_USER = 'user';
    const ROLE_ADMINISTRATOR = 'administrator';

    protected $fillable = ['name', 'email', 'password', 'role'];

    // ... rest of the code ...
}

// app/Http/Requests/StoreUserRequest.php file
class StoreUserRequest extends Request
{
    public function rules()
    {
        return [
            'name'             => 'string|required',
            'email'            => 'email|required',
            'password'         => 'string|required|min:6',
            'confirm_password' => 'same:password',
        ];
    }
}
// app/Controllers/UserController.php file
class UserController extends Controller
{
    public function store(StoreUserRequest $request)
    {
        $user = new User();
        $user->role = User::ROLE_USER;
        $user->fill($request->all());
        $user->save();

        return response()->json([
            'success' => true,
        ],201);
    }

    // ... rest of the code ...
}

, , - , , .

{
    "name" : "Hacker",
    "email" : "hacker@example.com",
    "role" : "administrator",
    "password" : "some_random_password",
    "confirm_password" : "some_random_password"
}

"role" $fillable. "role" , . , , , API, - , Laravel, . $fillable , , , API, ACL.

, Laravel.

:

1.

, , . , . "name", "email" "password". Laravel $request->validated(), .

, $request->all() $request->validated() :

public function store(StoreUserRequest $request)
{
    $user = new User();
    $user->role = User::ROLE_USER;
    $user->fill($request->validated());
    $user->save();
    
    return response()->json([
        'success' => true,
    ],201);
}

Laravel, $request->validate() $validator->validated(), .

, , , .

2.

$fillable ( , ) $guarded ( , ), $guarded, .

3. . $model->forceFill($data)

$model->forceFill , $forceFill $fillable . forceFill, , .

, , ? , , . , , / . , , , 0,1-0,2% . , - 1 , 10 , 10'000-20'000 . , .

- , .

- Laravel Auth , , IP- , . , :

1.

, . Symantec , 80% 2FA.

2. IP-

, IP, .

3.

IP, 100% , .

4. , /

FaceBook, - , :

5.

, , .

, Laravel, SQL- XSS, , ACL . ACL - , .

Laravel , .

HTTP

- HTTP (HTTP Strict Transport Security, X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, , . .), . HTTP . , HTTP Strict Transport Security HTTPS ( , HTTP HTTPS ). X-Frame-Options .

Laravel, . , , ? , , , , , .

Laravel , . , :

. , , 700 Equifax. , Equifax Apache Struts, 2 . Equifax 147,9 .

Laravel , , , , .

Laravel - , - - . , Laravel, API (, Eloquent), , Laravel , .

, , , , :

  1. Race Condition

  2. Server Side Request Forgery

  3. PHP Type Juggling

  4. Unrestricted File Upload

  5. Path Traversal

  6. Sensitive Data Exposure

  7. Server Side Template Injection

  8. Insecure Deserialization

  9. Session Fixation

  10. XML External Entity (XXE) Processing

  11. JWT Security

. , {{$userBio}} {!!$userBio!!}.

* "El vector de ataque se ha solucionado en la última versión de Laravel" - según el artículo original, la fecha de su lanzamiento no está clara, así como de su sitio web, por lo que no fue posible establecer qué versión de Laravel era la más reciente en ese momento. Sin embargo, el artículo llegó a las manos el día de la traducción, y en ese momento Laravel 8 existió durante un par de días.




All Articles