Skip to content

Commit

Permalink
database extensive update
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Dec 17, 2024
1 parent 1e10b0d commit 1fb1a16
Show file tree
Hide file tree
Showing 49 changed files with 12,795 additions and 4,396 deletions.
1 change: 1 addition & 0 deletions database/bg/@left-menu.texy
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
- [Изследовател |Explorer]
- [Размисъл |Reflection]
- [Настройване |configuration]
- [Рискове за сигурността |security]
927 changes: 653 additions & 274 deletions database/bg/explorer.texy

Large diffs are not rendered by default.

145 changes: 145 additions & 0 deletions database/bg/security.texy
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
Риск за сигурността
*******************

.[perex]
Базите данни често съдържат чувствителни данни и позволяват опасни операции. Базата данни Nette предоставя редица функции за сигурност. От решаващо значение е обаче да се разбере разликата между безопасни и опасни API.


SQL инжектиране .[#toc-sql-injection]
=====================================

SQL инжектирането е най-сериозният риск за сигурността при работа с бази данни. То възниква, когато непроверен потребителски вход стане част от SQL заявка. Атакуващият може да инжектира свои собствени SQL команди, като по този начин получава или променя данни в базата данни.

```php
// ❌ БЕЗОПАСЕН КОД - уязвим към SQL инжекция
$database->query("SELECT * FROM users WHERE name = '$_GET[name]'");

// Нападателят може да въведе нещо подобно на: ' ИЛИ '1'='1
// Получената заявка ще бъде:
// SELECT * FROM users WHERE name = '' OR '1'='1'
// Това връща всички потребители!
```

Същото се отнася и за Database Explorer:

```php
// ❌ КОД ЗА БЕЗОПАСНОСТ
$table->where('name = ' . $_GET['name']);
$table->where("name = '$_GET[name]'");
```


Безопасни параметризирани заявки .[#toc-safe-parameterized-queries]
===================================================================

Безопасният начин за вмъкване на стойности в SQL заявките е чрез параметризирани заявки. Базата данни Nette предоставя няколко начина за използването им.


Заместващи въпросителни знаци .[#toc-placeholder-question-marks]
----------------------------------------------------------------

Най-простият метод е да се използват заместващи въпросителни знаци:

```php
// ✅ Безопасни параметризирани заявки
$database->query('SELECT * FROM users WHERE name = ?', $_GET['name']);

// ✅ Безопасно условие в Explorer
$table->where('name = ?', $_GET['name']);
```

Същото важи и за всички други методи в Database Explorer, които позволяват вмъкване на изрази с въпросителни знаци и параметри.

.[warning]
Стойностите трябва да са от скаларен тип (`string`, `int`, `float`, `bool`) или `null`. Ако например `$_GET['name']` е масив, Nette Database ще включи всички негови елементи в SQL заявката, което може да е нежелателно.


Масиви от стойности .[#toc-value-arrays]
----------------------------------------

За клаузите `INSERT`, `UPDATE` или `WHERE` можем да използваме масиви от стойности:

```php
// ✅ Безопасен INSERT
$database->query('INSERT INTO users', [
'name' => $_GET['name'],
'email' => $_GET['email'],
]);

// ✅ Безопасен UPDATE
$database->query('UPDATE users SET', [
'name' => $_GET['name'],
'email' => $_GET['email'],
], 'WHERE id = ?', $_GET['id']);
```

Nette Database автоматично ескапира всички стойности, предадени чрез параметризирани заявки. Трябва обаче да осигурим правилния тип данни на параметрите.


Ключовете на масива не са сигурен API .[#toc-array-keys-are-not-a-safe-api]
===========================================================================

Докато стойностите в масивите са безопасни, същото не може да се каже за ключовете:

```php
// ❌ БЕЗОПАСЕН КОД - ключовете могат да съдържат SQL инжекция
$database->query('INSERT INTO users', $_GET);
$database->query('SELECT * FROM users WHERE', $_GET);
$table->where($_GET);
```

За командите `INSERT` и `UPDATE` това е критичен недостатък в сигурността - атакуващият може да вмъкне или промени всяка колона в базата данни. Например, той може да зададе `is_admin = 1` или да вмъкне произволни данни в чувствителни колони.

В условията на `WHERE` това е още по-опасно, защото позволява **SQL enumeration** - техника за постепенно извличане на информация за базата данни. Нападателят може да се опита да проучи заплатите на служителите, като инжектира в `$_GET` по този начин:

```php
$_GET = ['salary >', 100000]; // започва да определя диапазони на заплатите.
```

Основният проблем обаче е, че `WHERE` условията поддържат SQL изрази в ключовете:

```php
// Законосъобразно използване на оператори в ключовете
$table->where([
'age > ?' => 18,
'ROUND(score, ?) > ?' => [2, 75.5],
]);

// ❌ БЕЗОПАСНО: атакуващият може да инжектира свой собствен SQL
$_GET = ['1) UNION SELECT name, salary FROM users WHERE (is_admin = ?' => 1];
$table->where($_GET); // позволява на нападателя да получи администраторски заплати
```

Това отново е **SQL инжекция**.


Създаване на бял списък на колоните .[#toc-whitelisting-columns]
----------------------------------------------------------------

Ако искате да разрешите на потребителите да избират колони, винаги използвайте бял списък:

```php
// ✅ Безопасна обработка - само разрешени колони
$allowedColumns = ['name', 'email', 'active'];
$values = array_intersect_key($_GET, array_flip($allowedColumns));

$database->query('INSERT INTO users', $values);
```


Динамични идентификатори .[#toc-dynamic-identifiers]
====================================================

За динамични имена на таблици и колони използвайте заместителя `?name`:

```php
// ✅ Безопасно използване на надеждни идентификатори
$table = 'users';
$column = 'name';
$database->query('SELECT ?name FROM ?name', $column, $table);

// ❌ UNSAFE - никога не използвайте потребителски вход
$database->query('SELECT ?name FROM users', $_GET['column']);
```

Символът `?name` трябва да се използва само за доверени стойности, дефинирани в кода на приложението. За стойности, предоставени от потребителя, отново използвайте бял списък.
1 change: 1 addition & 0 deletions database/cs/@left-menu.texy
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ Databáze
- [Explorer]
- [Reflexe |reflection]
- [Konfigurace |configuration]
- [Bezpečnostní rizika |security]
- [Upgrade |upgrading]
Loading

2 comments on commit 1fb1a16

@diegosardina
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion it would be better to use the more modern filter_input with INPUT_GET instead of $_GET
https://www.php.net/manual/en/function.filter-input.php

@dg
Copy link
Member Author

@dg dg commented on 1fb1a16 Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diegosardina I've edited the text

Please sign in to comment.