Проект реализует простой REST API с аутентификацией по JWT и набором мер защиты от распространённых веб-уязвимостей (SQL-инъекции, XSS). Непрерывная интеграция (GitHub Actions) включает сборку, статический анализ (SpotBugs + FindSecBugs) и анализ зависимостей (OWASP Dependency-Check).
- Java 25, Maven (wrapper
mvnw) - Spring Boot 4.1.1
- Spring Data JPA + Hibernate, PostgreSQL
- Bean Validation (Jakarta Validation)
- JWT:
io.jsonwebtoken:jjwt0.13.0 (HMAC-SHA256) - BCrypt:
spring-security-crypto
Приложение читает конфигурацию из переменных окружения (src/main/resources/application.yaml):
| Переменная | Назначение |
|---|---|
DB_URL |
JDBC URL PostgreSQL (например jdbc:postgresql://localhost:5432/infosec) |
DB_USERNAME |
Пользователь БД |
DB_PASSWORD |
Пароль БД |
JWT_SECRET |
Секрет для подписи JWT (не менее 256 бит / 32 символа) |
NVD_API_KEY |
Ключ NVD API (нужен для локального запуска OWASP Dependency-Check) |
Пример (Windows PowerShell):
$env:DB_URL="jdbc:postgresql://localhost:5432/infosec"
$env:DB_USERNAME="postgres"
$env:DB_PASSWORD="..."
$env:JWT_SECRET="<случайная_строка_не_короче_32_символов>"
.\mvnw spring-boot:runТаблица users создаётся автоматически (ddl-auto: update).
Все эндпоинты работают с JSON.
Ожидает регистрационные данные, создаёт пользователя и возвращает JWT:
{
"username": "alice_01",
"email": "alice@example.com",
"password": "Password123"
}Ограничения полей:
username— 3–50 символов, только[A-Za-z0-9_-];email— валидный email, до 50 символов;password— 8–50 символов, минимум одна строчная, одна заглавная латинская буква и одна цифра, без пробелов.
Пример:
curl -X POST http://localhost:8080/auth/register \
-H "Content-Type: application/json" \
-d '{"username":"alice_01","email":"alice@example.com","password":"Password123"}'Ответ — JWT-токен (строка). Коды ошибок: 400 (не прошла валидация),
409 (username или email уже заняты).
curl -X POST http://localhost:8080/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"alice_01","password":"Password123"}'Ответ — JWT-токен. Коды ошибок: 404 (пользователь не найден),
401 (неверный пароль).
Требует заголовок Authorization: Bearer <token>:
curl http://localhost:8080/api/data \
-H "Authorization: Bearer <JWT-токен>"Ответ — массив объектов {"username": "...", "email": "..."}. Пароли не отдаются.
Без токена или с невалидным/просроченным токеном — 401.
- JWT (HS256) — при логине/регистрации выдаётся подписанный токен
(
security/JwtService.java). Ключ подписи берётся изJWT_SECRET; для HMAC-SHA256 требуется ключ ≥ 256 бит, иначеKeys.hmacShaKeyForвыбрасывает ошибку при старте. - Проверка токена в фильтре (
security/JwtFilter.java) — фильтр перехватывает запрос, требует заголовокAuthorization: Bearer ..., проверяет подпись, срок действия и корректность токена. Любая ошибка (невалидная подпись, истекший/повреждённый токен) приводит к401 UNAUTHORIZED. - Публичные пути —
/auth/login,/auth/registerисключены из фильтра (shouldNotFilter); всё остальное доступно только с валидным токеном. - Хеширование паролей BCrypt (
config/PasswordConfig.java) — при сохранении пароль хешируется с солью (BCryptPasswordEncoder), при логине сверяется толькоpasswordEncoder.matches(...). В открытом виде пароль нигде не хранится. - Политика пароля — набор правил Bean Validation
(
RegisterRequest): длина от 8, требуются строчные/заглавные буквы и цифры, запрещены пробелы. - Разделение кодов ошибок логина для различных сценариев (пользователь не найден —
404, неверный пароль —401), единый безопасный форматProblemDetail.
- Все обращения к БД идут через Spring Data JPA: запросы формируются JPQL/derived-методами
репозитория (
findByUsername,findByEmail), параметры всегда передаются как bind-параметры через JDBC, строка пользователя никогда не конкатенируется в SQL. - Поле
usernameперед сохранением дополнительно ограничено строгой маской[A-Za-z0-9_-]+, что исключает попадание произвольных символов. - Ограничения на уровне схемы: длины колонок (
username/email= 50,password= 100, для BCrypt-хэша),nullable = false, уникальные индексы наusernameиemail.
- Вывод пользовательских данных экранируется на уровне ответа: DTO
UserDto(dto/UserDto.java) пропускаетusernameиemailчерезHtmlUtils.htmlEscape(...), превращая<,>,&,",'в HTML-сущности. Даже если такой символ попадёт в БД, он не будет интерпретирован как разметка/скрипт в клиенте. - Входные данные ограничены строгой маской для
username(XSS-векторы вида<script>не проходят валидацию) и проверены на соответствие форматуemail.






