85 lines
2.4 KiB
PHP
85 lines
2.4 KiB
PHP
<?php
|
|
|
|
// use Normalizer;
|
|
|
|
/**
|
|
* High security sanitizer
|
|
* - Normalizes unicode
|
|
* - Removes control chars
|
|
* - Removes null bytes
|
|
* - Removes invisible unicode tricks
|
|
* - Strips dangerous HTML
|
|
* - Prevents polyglot payloads
|
|
*/
|
|
function sanitizeInputArrayAdvanced(array $data, array $htmlAllowedFields = []): array
|
|
{
|
|
foreach ($data as $k => $v) {
|
|
|
|
if (is_array($v)) {
|
|
$data[$k] = sanitizeInputArrayAdvanced($v, $htmlAllowedFields);
|
|
continue;
|
|
}
|
|
|
|
if (!is_string($v)) {
|
|
continue;
|
|
}
|
|
|
|
// 1. Unicode normalization (prevents homoglyph attacks)
|
|
if (class_exists('Normalizer')) {
|
|
$v = \Normalizer::normalize($v, \Normalizer::FORM_C);
|
|
}
|
|
|
|
// 2. Remove NULL bytes & control chars
|
|
$v = preg_replace('/[\x00-\x1F\x7F]/u', '', $v);
|
|
|
|
// 3. Remove invisible unicode chars (zero width, etc)
|
|
$v = preg_replace('/[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{206F}]/u', '', $v);
|
|
|
|
// 4. Decode HTML entities (so hidden payloads are exposed)
|
|
$v = html_entity_decode($v, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
|
|
|
// 5. Trim
|
|
$v = trim($v);
|
|
|
|
// 6. If this field is NOT allowed to contain HTML → strip aggressively
|
|
if (!in_array($k, $htmlAllowedFields, true)) {
|
|
|
|
// Remove all tags
|
|
$v = strip_tags($v);
|
|
|
|
// Kill any leftover JS protocol
|
|
$v = preg_replace('/(javascript:|data:|vbscript:)/i', '', $v);
|
|
|
|
} else {
|
|
// This is HTML-allowed field → run HTML sanitizer
|
|
$v = sanitizeTrustedHtml($v);
|
|
}
|
|
|
|
$data[$k] = $v;
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
function sanitizeTrustedHtml(string $html): string
|
|
{
|
|
// Allowed tags for email templates
|
|
$allowedTags = '<p><br><b><strong><i><u><em><ul><ol><li><table><thead><tbody><tr><td><th><a><img><div><span><h1><h2><h3><h4><h5><h6>';
|
|
|
|
// Strip all other tags
|
|
$html = strip_tags($html, $allowedTags);
|
|
|
|
// Remove event handlers like onclick, onerror, etc
|
|
$html = preg_replace('/\son\w+="[^"]*"/i', '', $html);
|
|
$html = preg_replace("/\son\w+='[^']*'/i", '', $html);
|
|
|
|
// Remove javascript: and data:
|
|
$html = preg_replace('/(javascript:|vbscript:|data:)/i', '', $html);
|
|
|
|
// Remove iframe, object, embed even if sneaked in
|
|
$html = preg_replace('/<(iframe|object|embed|script|style)[^>]*>.*?<\/\1>/is', '', $html);
|
|
|
|
return $html;
|
|
}
|
|
|