Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 134 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
[![Review Assignment Due Date](https://classroom.github.com/assets/deadline-readme-button-22041afd0340ce965d47ae6ef1cefeee28c7c493a6346c4f15d667ab976d596c.svg)](https://classroom.github.com/a/NSTTkgmb)
# Лабораторная работа №4 — Анализ и тестирование безопасности веб-приложения

## Цель
Expand Down Expand Up @@ -42,12 +43,12 @@

| Актив | Тип | Ценность | Примечание |
|-------|-----|----------|------------|
| Данные пользователей (userId, userName) | Данные | ? | |
| Данные о сессиях (время входа/выхода) | Данные | ? | |
| Файловая система сервера | Инфраструктура | ? | |
| Внутренняя сеть / метаданные окружения | Инфраструктура | ? | |
| Данные пользователей (userId, userName) | Данные | High | Имея userId можно смотреть чужие данные |
| Данные о сессиях (время входа/выхода) | Данные | Low | Тамперинг аналитики входа/выхода |
| Файловая система сервера | Инфраструктура | High | Path traversal |
| Внутренняя сеть / метаданные окружения | Инфраструктура | High | SSRF moment |

> **Вопрос для размышления:** какие из активов наиболее критичны и почему?
> **Вопрос для размышления:** какие из активов наиболее критичны и почему? (внутренняя сеть)

---

Expand All @@ -57,12 +58,12 @@

| Категория угрозы | Расшифровка | Применимо к этому приложению? |
|------------------|------------------------|-------------------------------|
| **S**poofing | Подмена идентификации | ? |
| **T**ampering | Модификация данных | ? |
| **R**epudiation | Отказ от авторства | ? |
| **I**nformation Disclosure | Утечка данных | ? |
| **D**enial of Service | Отказ в обслуживании | ? |
| **E**levation of Privilege | Повышение привилегий | ? |
| **S**poofing | Подмена идентификации | Да. Источник - внешний. Все эндпоинты. |
| **T**ampering | Модификация данных | Да. Источник - внешний. recordSession, exportData |
| **R**epudiation | Отказ от авторства | Да. Источник - внешний и внутренний. Везде где нет логов. |
| **I**nformation Disclosure | Утечка данных | Да. Источник - внешний. totalActivity, userProfile |
| **D**enial of Service | Отказ в обслуживании | Да. Источник - внешний. register, recordSession |
| **E**levation of Privilege | Повышение привилегий | Да. Источник - внешний. notify, exportReport |

Для каждой применимой угрозы укажите:
- **Источник угрозы** (кто/что может её реализовать)
Expand Down Expand Up @@ -241,6 +242,128 @@ src/test/java/ru/itmo/testing/lab4/pentest/XssPentestTest.java

---

#### 🔴 Finding #1 — Hardcoded World-Readable Path

| Поле | Значение |
|------|----------|
| **Компонент** | `UserAnalyticsController.java` (константа класса) |
| **Тип** | Hardcoded Sensitive Path |
| **CWE** | [CWE-552](https://cwe.mitre.org/data/definitions/552.html) |
| **CVSS v3.1** | `4.0 MEDIUM (AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N)` |
| **Статус** | Confirmed |

**Описание:** Путь экспорта отчётов жёстко задан как `/tmp/reports/` — общедоступная директория.

**Влияние:** Локальный пользователь или процесс может прочитать или изменить отчёты, содержащие пользовательские данные.

**Рекомендации по исправлению:** Заменить путь на защищённую директорию внутри домашнего каталога приложения, например `System.getProperty("user.home") + "/.app/reports"`.

**Шаги воспроизведения:**
1. Открыть UserAnalyticsController.java:39.
2. REPORTS_BASE_DIR = "/tmp/reports/".
3. Ожидаемый результат: защищённая директория.
4. Фактический результат: общедоступная временная папка.


---

#### 🔴 Finding #2 — Information Disclosure via Exception Messages

| Поле | Значение |
|------|----------|
| **Компонент** | `/recordSession`, `/monthlyActivity` |
| **Тип** | Information Disclosure |
| **CWE** | [CWE-209](https://cwe.mitre.org/data/definitions/209.html) |
| **CVSS v3.1** | `5.3 MEDIUM (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N)` |
| **Статус** | Confirmed |

**Описание:** Сообщения исключений напрямую возвращаются клиенту.

**Влияние:** Атакующий получает информацию о внутренней структуре приложения, что облегчает дальнейшие атаки.

**Рекомендации по исправлению:** Возвращать общее сообщение об ошибке, а детали логировать на сервере.

**Шаги воспроизведения:**
1. POST /recordSession с loginTime=invalid.
2. Ответ содержит "Invalid data: Text 'invalid' could not be parsed...".
3. Ожидаемый результат: "Invalid data format".
4. Фактический результат: утечка деталей парсинга.


---

#### 🔴 Finding #3 — Path Traversal in Report Export

| Поле | Значение |
|------|----------|
| **Компонент** | `/exportReport` |
| **Тип** | Path Traversal |
| **CWE** | [CWE-22](https://cwe.mitre.org/data/definitions/22.html) |
| **CVSS v3.1** | `7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H)` |
| **Статус** | Confirmed |

**Описание:** `filename` конкатенируется без проверки, позволяя выход за пределы `/tmp/reports/`.

**Влияние:** Атакующий может перезаписать системные файлы или записать вредоносные данные в произвольные директории.

**Рекомендации по исправлению:** Использовать `Paths.get(baseDir).resolve(filename).normalize()` и проверять, что результат начинается с `baseDir`.

**Шаги воспроизведения:**
1. GET /exportReport?userId=x&filename=../../../etc/passwd
2. Файл создаётся вне разрешённой директории.
3. Ожидаемый результат: отклонение запроса.
4. Фактический результат: запись в произвольную локацию.


---

#### 🔴 Finding #4 — Server-Side Request Forgery (SSRF)

| Поле | Значение |
|------|----------|
| **Компонент** | `/notify` |
| **Тип** | SSRF |
| **CWE** | [CWE-918](https://cwe.mitre.org/data/definitions/918.html) |
| **CVSS v3.1** | `8.6 HIGH (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N)` |
| **Статус** | Confirmed |

**Описание:** Сервер выполняет запросы по переданному URL без валидации.

**Влияние:** Атакующий может сканировать внутреннюю сеть, получать метаданные облака или атаковать внутренние сервисы.

**Рекомендации по исправлению:** Реализовать allowlist разрешённых доменов и блокировать внутренние IP-адреса (localhost, 169.254.169.254, 10.0.0.0/8 и т.д.).

**Шаги воспроизведения:**
1. POST /notify?userId=x&callbackUrl=http://169.254.169.254/latest/meta-data/
2. Сервер обращается к внутреннему адресу.
3. Ожидаемый результат: запросы только к разрешённым хостам.
4. Фактический результат: доступ к внутренним ресурсам.


---

#### 🔴 Finding #5 — Reflected XSS

| Поле | Значение |
|------|----------|
| **Компонент** | `/userProfile` |
| **Тип** | Reflected XSS |
| **CWE** | [CWE-79](https://cwe.mitre.org/data/definitions/79.html) |
| **CVSS v3.1** | `6.1 MEDIUM (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)` |
| **Статус** | Suspected |

**Описание:** Имя пользователя вставляется в HTML без экранирования.

**Влияние:** Атакующий может выполнить произвольный JavaScript в браузере жертвы, что приводит к краже сессий или фишингу.

**Рекомендации по исправлению:** Использовать `StringEscapeUtils.escapeHtml4()` или шаблонизатор (JTE, Thymeleaf) с автоматическим экранированием.

**Шаги воспроизведения:**
1. Зарегистрировать пользователя с именем: <script>alert(1)</script>
2. Открыть /userProfile?userId=...
3. Ожидаемый результат: отображение как текст.
4. Фактический результат: выполнение скрипта.

## Полезные ресурсы

- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
Expand Down
24 changes: 24 additions & 0 deletions devshell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{ inputs, ... }:

let
pkgs = import inputs.nixpkgs {
system = "x86_64-linux";
config.allowUnfree = true;
};
in
(pkgs.buildFHSEnv {
name = "java-devshell";

targetPkgs = p: with p; [
just
jdk
gradle
kotlin
jetbrains.idea
semgrep
];

profile = ''
export JAVA_HOME="${pkgs.jdk.home}"
'';
}).env
78 changes: 78 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
description = "Nix devshell with Java, IntelliJ IDEA, Gradle, and Kotlin";

inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
blueprint.url = "github:numtide/blueprint";
};

outputs = inputs: inputs.blueprint { inherit inputs; };
}
1 change: 1 addition & 0 deletions semgrep-report.sarif

Large diffs are not rendered by default.

Loading