initial prototype based on nat-as-server
Some checks failed
PHPUnit / test (push) Has been cancelled
Some checks failed
PHPUnit / test (push) Has been cancelled
This commit is contained in:
61
lib/text_sanitize.php
Normal file
61
lib/text_sanitize.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Sanitize user-entered free text before storage (defense in depth; queries use prepared statements).
|
||||
*/
|
||||
function sanitize_free_text(mixed $value, int $maxLength = 2000): string {
|
||||
if (!is_string($value) && !is_numeric($value)) {
|
||||
return '';
|
||||
}
|
||||
$s = trim((string) $value);
|
||||
if ($s === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$maxLength = max(1, min($maxLength, 10000));
|
||||
$s = mb_substr($s, 0, $maxLength);
|
||||
|
||||
// Control characters (keep tab/newline for multiline answers).
|
||||
$s = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/u', '', $s) ?? '';
|
||||
|
||||
$s = str_replace(["\0", '--', '/*', '*/', ';'], '', $s);
|
||||
|
||||
$patterns = [
|
||||
'/\bunion\s+select\b/i',
|
||||
'/\bselect\s+.+\s+from\b/i',
|
||||
'/\binsert\s+into\b/i',
|
||||
'/\bupdate\s+.+\s+set\b/i',
|
||||
'/\bdelete\s+from\b/i',
|
||||
'/\bdrop\s+(table|database)\b/i',
|
||||
'/\bexec(\s|\()/i',
|
||||
'/\bxp_\w+/i',
|
||||
'/\bor\s+1\s*=\s*1\b/i',
|
||||
'/\band\s+1\s*=\s*1\b/i',
|
||||
"/'\s*or\s+'/i",
|
||||
'/"\s*or\s+"/i',
|
||||
'/\bchar\s*\(/i',
|
||||
'/\bconcat\s*\(/i',
|
||||
'/\bsleep\s*\(/i',
|
||||
'/\bbenchmark\s*\(/i',
|
||||
];
|
||||
foreach ($patterns as $pattern) {
|
||||
$s = preg_replace($pattern, '', $s) ?? $s;
|
||||
}
|
||||
|
||||
return trim(preg_replace('/\s{2,}/u', ' ', $s) ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns sanitized text or calls json_error when nothing safe remains.
|
||||
*/
|
||||
function require_safe_free_text(mixed $value, string $fieldName, int $maxLength = 2000): string {
|
||||
$raw = is_string($value) || is_numeric($value) ? trim((string) $value) : '';
|
||||
if ($raw === '') {
|
||||
json_error('INVALID_FIELD', "$fieldName is required", 400);
|
||||
}
|
||||
$clean = sanitize_free_text($raw, $maxLength);
|
||||
if ($clean === '') {
|
||||
json_error('INVALID_FIELD', "$fieldName contains disallowed content", 400);
|
||||
}
|
||||
return $clean;
|
||||
}
|
||||
Reference in New Issue
Block a user