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 18, 2024
1 parent c24c1fc commit fad6ec8
Show file tree
Hide file tree
Showing 49 changed files with 13,035 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.

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

<div class=perex>

Базите данни често съдържат чувствителни данни и позволяват извършването на опасни операции. За сигурна работа с Nette Database основните аспекти са:

- Разбиране на разликата между сигурен и несигурен API
- Използване на параметризирани заявки
- Правилно валидиране на входните данни

</div>


Какво представлява SQL инжектирането? .[#toc-what-is-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
// ❌ ОПАСЕН КОД - уязвим към SQL инжекция
$table->where('name = ' . $_GET['name']);
$table->where("name = '$_GET[name]'");
```


Сигурни параметризирани заявки .[#toc-secure-parameterized-queries]
===================================================================

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

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

```php
// ✅ Сигурна параметризирана заявка
$database->query('SELECT * FROM users WHERE name = ?', $name);

// ✅ Защитено условие в Explorer
$table->where('name = ?', $name);
```

Това важи за всички други методи в [Database Explorer |explorer], които позволяват вмъкване на изрази със заместители с въпросителни знаци и параметри.

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

```php
// ✅ Secure INSERT
$database->query('INSERT INTO users', [
'name' => $name,
'email' => $email,
]);

// ✅ Secure INSERT в Explorer
$table->insert([
'name' => $name,
'email' => $email,
]);
```

.[warning]
Трябва обаче да осигурим [правилния тип данни на параметрите |#Validating input data].


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

Докато стойностите на масивите са защитени, това не важи за ключовете!

```php
// ❌ ОПАСЕН КОД - ключовете на масивите не са обработени
$database->query('INSERT INTO users', $_POST);
```

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

При условията WHERE това е още по-опасно, тъй като те могат да съдържат оператори:

```php
// ❌ ОПАСЕН КОД - ключовете на масивите не са обработени
$_POST['salary >'] = 100000;
$database->query('SELECT * FROM users WHERE', $_POST);
// Изпълнява заявка WHERE (`salary` > 100000)
```

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

Методът `where()` поддържа SQL изрази, включително оператори и функции в ключовете. Това дава възможност на нападателя да извършва сложни SQL инжекции:

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

Тази атака прекратява оригиналното условие с `0)`, добавя своя собствена `SELECT` с помощта на `UNION`, за да получи чувствителни данни от таблицата `users`, и приключва със синтактично правилна заявка с помощта на `WHERE (1)`.


Бял списък на колони .[#toc-column-whitelist]
---------------------------------------------

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

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

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


Потвърждаване на входните данни .[#toc-validating-input-data]
=============================================================

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

Например, ако `$name` в предишните примери беше неочаквано масив вместо низ, Nette Database щеше да се опита да вмъкне всички негови елементи в SQL заявката, което щеше да доведе до грешка. Затова **никога не използвайте** невалидирани данни от `$_GET`, `$_POST` или `$_COOKIE` директно в заявки към базата данни.

На второ ниво проверяваме техническата валидност на данните - например дали низовете са в кодировка UTF-8 и дали дължината им съответства на дефиницията на колоната, или дали числовите стойности са в допустимия диапазон за дадения тип данни на колоната. За това ниво на валидиране можем частично да разчитаме на самата база данни - много бази данни отхвърлят невалидните данни. Поведението на различните бази данни обаче може да е различно, като някои могат мълчаливо да съкращават дълги низове или да изрязват числа извън обхвата.

Третото ниво представлява логически проверки, специфични за вашето приложение. Например проверка дали стойностите от полетата за избор съответстват на предложените опции, дали числата са в очаквания диапазон (например възраст 0-150 години) или дали взаимозависимостите между стойностите имат смисъл.

Препоръчителни начини за прилагане на валидиране:
- Използвайте [формуляри на Nette, |forms:] които автоматично осигуряват цялостно валидиране на всички входни данни
- Използвайте [Presenters |application:] и посочете типове данни за параметрите в методите `action*()` и `render*()`
- Или реализирайте свой собствен слой за валидиране, като използвате стандартни инструменти на PHP, като например `filter_var()`


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

За динамични имена на таблици и колони използвайте заместителя `?name`. Това гарантира правилното ескапиране на идентификаторите в съответствие с дадения синтаксис на базата данни (например използване на задни тирета в MySQL):

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

// ❌ ОПАСНО - никога не използвайте потребителски вход
$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

0 comments on commit fad6ec8

Please sign in to comment.