Skip to content

Commit df4e99f

Browse files
committed
database extensive update
1 parent 651ad91 commit df4e99f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+13035
-4396
lines changed

database/bg/@left-menu.texy

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
- [Изследовател |Explorer]
55
- [Размисъл |Reflection]
66
- [Настройване |configuration]
7+
- [Рискове за сигурността |security]

database/bg/explorer.texy

+653-274
Large diffs are not rendered by default.

database/bg/security.texy

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
Рискове за сигурността
2+
**********************
3+
4+
<div class=perex>
5+
6+
Базите данни често съдържат чувствителни данни и позволяват извършването на опасни операции. За сигурна работа с Nette Database основните аспекти са:
7+
8+
- Разбиране на разликата между сигурен и несигурен API
9+
- Използване на параметризирани заявки
10+
- Правилно валидиране на входните данни
11+
12+
</div>
13+
14+
15+
Какво представлява SQL инжектирането? .[#toc-what-is-sql-injection]
16+
===================================================================
17+
18+
SQL инжектирането е най-сериозният риск за сигурността при работа с бази данни. То възниква, когато нефилтриран потребителски вход стане част от SQL заявка. Нападателят може да вмъкне свои собствени SQL команди и по този начин:
19+
- да извлече неоторизирани данни
20+
- да променя или изтрива данни в базата данни
21+
- да заобиколи удостоверяването
22+
23+
```php
24+
// ❌ ОПАСЕН КОД - уязвим към SQL инжекция
25+
$database->query("SELECT * FROM users WHERE name = '$_GET[name]'");
26+
27+
// Нападателят може да въведе стойност като: ' ИЛИ '1'='1
28+
// Получената заявка би била: SELECT * FROM users WHERE name = '' OR '1'='1'
29+
// което връща всички потребители
30+
```
31+
32+
Същото важи и за Database Explorer:
33+
34+
```php
35+
// ❌ ОПАСЕН КОД - уязвим към SQL инжекция
36+
$table->where('name = ' . $_GET['name']);
37+
$table->where("name = '$_GET[name]'");
38+
```
39+
40+
41+
Сигурни параметризирани заявки .[#toc-secure-parameterized-queries]
42+
===================================================================
43+
44+
Сигурният начин за вмъкване на стойности в SQL заявките е чрез параметризирани заявки. Nette Database предлага няколко начина за използването им.
45+
46+
Най-простият начин е да се използват **заместващи знаци за въпроси**:
47+
48+
```php
49+
// ✅ Сигурна параметризирана заявка
50+
$database->query('SELECT * FROM users WHERE name = ?', $name);
51+
52+
// ✅ Защитено условие в Explorer
53+
$table->where('name = ?', $name);
54+
```
55+
56+
Това важи за всички други методи в [Database Explorer |explorer], които позволяват вмъкване на изрази със заместители с въпросителни знаци и параметри.
57+
58+
За командите INSERT, UPDATE или клаузите WHERE можем спокойно да предаваме стойности в масив:
59+
60+
```php
61+
// ✅ Secure INSERT
62+
$database->query('INSERT INTO users', [
63+
'name' => $name,
64+
'email' => $email,
65+
]);
66+
67+
// ✅ Secure INSERT в Explorer
68+
$table->insert([
69+
'name' => $name,
70+
'email' => $email,
71+
]);
72+
```
73+
74+
.[warning]
75+
Трябва обаче да осигурим [правилния тип данни на параметрите |#Validating input data].
76+
77+
78+
Ключовете на масива не са сигурен API .[#toc-array-keys-are-not-secure-api]
79+
---------------------------------------------------------------------------
80+
81+
Докато стойностите на масивите са защитени, това не важи за ключовете!
82+
83+
```php
84+
// ❌ ОПАСЕН КОД - ключовете на масивите не са обработени
85+
$database->query('INSERT INTO users', $_POST);
86+
```
87+
88+
За командите INSERT и UPDATE това е сериозен пропуск в сигурността - атакуващият може да вмъкне или промени всяка колона в базата данни. Той може например да зададе `is_admin = 1` или да вмъкне произволни данни в чувствителни колони (известно като уязвимост при масово задаване).
89+
90+
При условията WHERE това е още по-опасно, тъй като те могат да съдържат оператори:
91+
92+
```php
93+
// ❌ ОПАСЕН КОД - ключовете на масивите не са обработени
94+
$_POST['salary >'] = 100000;
95+
$database->query('SELECT * FROM users WHERE', $_POST);
96+
// Изпълнява заявка WHERE (`salary` > 100000)
97+
```
98+
99+
Атакуващият може да използва този подход, за да разкрива систематично заплатите на служителите. Той може да започне със заявка за заплати над 100 000, след това под 50 000 и чрез постепенно стесняване на обхвата да разкрие приблизителните заплати на всички служители. Този тип атака се нарича SQL enumeration.
100+
101+
Методът `where()` поддържа SQL изрази, включително оператори и функции в ключовете. Това дава възможност на нападателя да извършва сложни SQL инжекции:
102+
103+
```php
104+
// ❌ ОПАСЕН КОД - атакуващият може да вмъкне свой собствен SQL
105+
$_POST['0) UNION SELECT name, salary FROM users WHERE (?'] = 1;
106+
$table->where($_POST);
107+
// изпълнява заявка WHERE (0) UNION SELECT name, salary FROM users WHERE (1)
108+
```
109+
110+
Тази атака прекратява оригиналното условие с `0)`, добавя своя собствена `SELECT` с помощта на `UNION`, за да получи чувствителни данни от таблицата `users`, и приключва със синтактично правилна заявка с помощта на `WHERE (1)`.
111+
112+
113+
Бял списък на колони .[#toc-column-whitelist]
114+
---------------------------------------------
115+
116+
Ако искате да разрешите на потребителите да избират колони, винаги използвайте бял списък:
117+
118+
```php
119+
// ✅ Сигурна обработка - само разрешени колони
120+
$allowedColumns = ['name', 'email', 'active'];
121+
$values = array_intersect_key($_POST, array_flip($allowedColumns));
122+
123+
$database->query('INSERT INTO users', $values);
124+
```
125+
126+
127+
Потвърждаване на входните данни .[#toc-validating-input-data]
128+
=============================================================
129+
130+
**Най-важното е да се гарантира правилният тип данни на параметрите** - това е необходимо условие за сигурно използване на базата данни Nette. Базата данни приема, че всички входни данни имат правилния тип данни, съответстващ на дадената колона.
131+
132+
Например, ако `$name` в предишните примери беше неочаквано масив вместо низ, Nette Database щеше да се опита да вмъкне всички негови елементи в SQL заявката, което щеше да доведе до грешка. Затова **никога не използвайте** невалидирани данни от `$_GET`, `$_POST` или `$_COOKIE` директно в заявки към базата данни.
133+
134+
На второ ниво проверяваме техническата валидност на данните - например дали низовете са в кодировка UTF-8 и дали дължината им съответства на дефиницията на колоната, или дали числовите стойности са в допустимия диапазон за дадения тип данни на колоната. За това ниво на валидиране можем частично да разчитаме на самата база данни - много бази данни отхвърлят невалидните данни. Поведението на различните бази данни обаче може да е различно, като някои могат мълчаливо да съкращават дълги низове или да изрязват числа извън обхвата.
135+
136+
Третото ниво представлява логически проверки, специфични за вашето приложение. Например проверка дали стойностите от полетата за избор съответстват на предложените опции, дали числата са в очаквания диапазон (например възраст 0-150 години) или дали взаимозависимостите между стойностите имат смисъл.
137+
138+
Препоръчителни начини за прилагане на валидиране:
139+
- Използвайте [формуляри на Nette, |forms:] които автоматично осигуряват цялостно валидиране на всички входни данни
140+
- Използвайте [Presenters |application:] и посочете типове данни за параметрите в методите `action*()` и `render*()`
141+
- Или реализирайте свой собствен слой за валидиране, като използвате стандартни инструменти на PHP, като например `filter_var()`
142+
143+
144+
Динамични идентификатори .[#toc-dynamic-identifiers]
145+
====================================================
146+
147+
За динамични имена на таблици и колони използвайте заместителя `?name`. Това гарантира правилното ескапиране на идентификаторите в съответствие с дадения синтаксис на базата данни (например използване на задни тирета в MySQL):
148+
149+
```php
150+
// ✅ Безопасно използване на надеждни идентификатори
151+
$table = 'users';
152+
$column = 'name';
153+
$database->query('SELECT ?name FROM ?name', $column, $table);
154+
// Резултат в MySQL: SELECT `name` FROM `users`
155+
156+
// ❌ ОПАСНО - никога не използвайте потребителски вход
157+
$database->query('SELECT ?name FROM users', $_GET['column']);
158+
```
159+
160+
Важно: използвайте символа `?name` само за доверени стойности, дефинирани в кода на приложението. За потребителски стойности вместо това използвайте подхода на белия списък.

database/cs/@left-menu.texy

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ Databáze
44
- [Explorer]
55
- [Reflexe |reflection]
66
- [Konfigurace |configuration]
7+
- [Bezpečnostní rizika |security]
78
- [Upgrade |upgrading]

0 commit comments

Comments
 (0)