У меня есть веб-сайт Pastebin , это минималистичная версия оригинального Pastebin, но у меня возникли проблемы с вставкой кода. Мой сервер его не примет.
Я попробовал закодировать его в base64, и это сработало, и сохранил данные как base64, и когда я приступил к декодированию с помощью инструмента, он декодировался идеально, но когда я просматриваю его по сгенерированной ссылке на вставку, он отображается как �������Y� ��T��T��ԑTUQT, и я не могу разберись. У меня есть в основном рабочая версия, которая прекрасно кодируется и декодируется, но она не просто отображает код, а отображает его с HTML-кодом. Поэтому, если бы в моем коде был <h1>Test</h1>, он отображал бы его как заголовок, а не как простой код. Я попытался найти это снова, но в моих редакциях оно потерялось. Ниже у меня есть текущий (не работающий) код с ошибками кодирования/декодирования/отображения base64, я не могу понять, какие именно.
JS
window.onload = function() {
document.querySelector('#pasteForm').addEventListener('submit', function(e) {
e.preventDefault();
var textArea = document.querySelector('#textToPaste');
var formData = new FormData(e.target);
var text = formData.get('text').replace(/\n/g, '<br>').replace(/^ /gm, ' ').replace(/^\t/gm, ' ');
var encodedText = btoa(text); // Encode the text in base64
formData.set('text', '<pre>' + encodedText + '</pre>'); // Use the encoded text
var xhr = new XMLHttpRequest();
xhr.open('POST', 'create.php', true);
xhr.onload = function() {
if (xhr.status === 200) {
var password = formData.get('password');
if (password) {
document.querySelector('#linkBox').value = xhr.responseURL + '?password=' + encodeURIComponent(password);
} else {
document.querySelector('#linkBox').value = xhr.responseURL;
}
document.querySelector('#overlay').style.display = 'block';
document.querySelector('#popup').style.display = 'block';
} else {
console.error('An error occurred');
}
};
xhr.send(formData);
});
document.querySelector('#closeButton').addEventListener('click', function() {
document.querySelector('#overlay').style.display = 'none';
document.querySelector('#popup').style.display = 'none';
});
document.querySelector('#copyButton').addEventListener('click', function() {
var linkBox = document.querySelector('#linkBox');
linkBox.select();
document.execCommand('copy');
var copyButtonIcon = document.querySelector('#copyButton img');
var originalIconSrc = copyButtonIcon.src;
copyButtonIcon.src = 'https://cdn.cirrus.center/main/icons/check.png';
setTimeout(function() {
copyButtonIcon.src = originalIconSrc;
}, 2000);
});
};
PHP
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!file_exists('paste')) {
mkdir('paste');
$redirectIndex = '<?php' . PHP_EOL;
$redirectIndex .= 'header("Location: ..");' . PHP_EOL;
$redirectIndex .= 'exit;' . PHP_EOL;
file_put_contents('paste/index.php', $redirectIndex);
}
$dir = uniqid();
mkdir("paste/$dir");
$decodedText = '';
if (isset($_POST['text']) && $_POST['text'] !== '') {
$decodedText = base64_decode($_POST['text']); // Decode the base64 text
$decodedText = mb_convert_encoding($decodedText, 'UTF-8', 'auto'); // Convert the encoding to UTF-8
}
$index = '<?php' . PHP_EOL;
if (isset($_POST['password']) && $_POST['password'] !== '') {
$index .= 'if (!isset($_GET["password"]) || $_GET["password"] !== "' . $_POST['password'] . '") {' . PHP_EOL;
$index .= ' echo "<h1>Incorrect password</h1>";' . PHP_EOL;
$index .= ' exit;' . PHP_EOL;
$index .= '}' . PHP_EOL;
}
$index .= 'echo <<<EOT' . PHP_EOL; // Use the decoded text
$index .= $decodedText . PHP_EOL;
$index .= 'EOT;' . PHP_EOL;
if (isset($_POST['burn'])) {
$index .= 'file_put_contents(__FILE__, "<h1>This paste has been deleted</h1>");' . PHP_EOL;
$index .= 'exit;' . PHP_EOL;
}
$index .= '?>' . PHP_EOL;
$index .= '<!DOCTYPE html>' . PHP_EOL;
$index .= '<html>' . PHP_EOL;
$index .= '<head>' . PHP_EOL;
$index .= ' <title>' . ($_POST['title'] ?? 'Pastebin') . '</title>' . PHP_EOL;
$index .= '</head>' . PHP_EOL;
$index .= '<body>' . PHP_EOL;
$index .= '' . PHP_EOL;
$index .= '</body>' . PHP_EOL;
$index .= '</html>';
file_put_contents("paste/$dir/index.php", $index);
header("Location: /paste/$dir");
echo "/paste/$dir";
}
Люди оставляли отзывы о том, что при вставке кода они получают ошибку 418 (странно, потому что 418 был добавлен как первоапрельская шутка, поэтому я предполагаю, что он пытается помешать людям выполнить вредоносный код на сервере), но сохраняет его как base64 устранит эту ошибку. Единственная проблема, с которой я столкнулся, это правильное отображение.
Хорошо, это имеет смысл, спасибо за разъяснения. Я пытаюсь следовать вашей логике, но все равно немного запутался. В JS вы считаете ошибкой все, что не имеет статуса 200, но в PHP вы вызываете header() с директивой Location, которая по умолчанию имеет значение 302. Кроме того, когда вы вручную проверяете сгенерированный PHP, выглядит ли он правильно? И я игнорирую визуализированный вывод и сосредотачиваюсь только на серверной части.
Кроме того, вы разрешаете публичную отправку текста, который интерпретируется как чистый PHP, и его очень легко использовать. Пример смотрите в файле, который начинается с 663e. Задумывались ли вы о последствиях этого для безопасности? Нужно ли его выполнять? Можно ли его просто записать в файловую систему?
Что касается вашего первого ответа, я получил только 200 и 418. Думаю, тогда да, пока что все, кроме 200, является ошибкой, но опять же, оно ограничено 418. Да, в целом PHP выглядит правильно. Он работает для всего, кроме кода. Что касается вашего второго ответа, то на самом деле это была одна из главных вещей, о которых я думал при его создании.
Вы видели мой образец и что я сделал? Кроме того, бороться с этим в JS, вероятно, не очень хорошая идея, потому что злые люди просто будут обходить JS и POST напрямую.
Я не видел вашего примера, но код не является исполняемым.
Это хорошо, значит, приведенный выше пример кода необходимо обновить? Потому что раньше мне точно приходилось phpinfo() бегать. Кроме того, не забудьте сохранить заголовок, потому что я могу заставить PHP выполняться там.
И... пока я здесь, также храните свой пароль, который также разрешает использование PHP. Мне только что phpinfo() снова пришлось работать. Linux baroness-blood 5.4.32-grsec-grsec-plus+ #1 SMP Sat Apr 18 03:13:45 UTC 2020 x86_64
Строки JavaScript хранятся в кодировке UTF-16. Чтобы получить UTF-8, вам придется преобразовать строку самостоятельно, например. как в ecmanaut.blogspot.com/2006/07/… . Попробуйте var encodedText = btoa( unescape( encodeURIComponent( text)));
Отметил благодарности. Буду реализовывать это для моего следующего коммита.
@CaelenCater, просто предупреждение: использование htmlspecialchars, как это сейчас делает ваш код, все еще недостаточно. Все три месторождения по-прежнему пригодны для эксплуатации. На самом деле я бы рекомендовал записать необработанный текст в специальный файл и вызвать file_get_contents с помощью echo. В качестве пароля используйте OpenSSL или Sodium для шифрования полезных данных, не сохраняйте пароль. Если расшифровка не удалась, то показать «неверный пароль».
Я рассмотрю этот вопрос подробнее, но некоторые вещи могут оказаться невозможными на моем общем сервере. Спасибо за все ваши отзывы!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вот что я вижу, попробуйте и дайте мне знать. Я могу пересмотреть этот ответ по мере необходимости.
В javascript вы, кажется, передаете поле формы следующим образом:
formData.set('text', '<pre>' + encodedText + '</pre>'); // Use the encoded text
Затем он отправляет форму на серверный PHP-код, и поле формы «текст» декодируется следующим образом:
$decodedText = base64_decode($_POST['text']); // Decode the base64 text
$decodedText = mb_convert_encoding($decodedText, 'UTF-8', 'auto'); // Convert the encoding to UTF-8
Итак, несколько потенциальных проблем:
1-Я думаю, вам нужно удалить теги «pre» при кодировании, поэтому:
formData.set('text', encodedText); // Use the encoded text
Вы можете поместить теги pre в PHP, чтобы текст отображался правильно:
$index .= '<pre>' . $decodedText . '</pre>' . PHP_EOL;
2-На стороне JavaScript вы используете btoa, но на стороне PHP вы используете base64_decode. Эти две команды, возможно, могут быть несовместимы, поэтому вы можете использовать инструмент, чтобы убедиться, что PHP base64_decode правильно декодирует btoa javascript. Вы упоминаете использование инструмента для проверки, но могут быть случаи, когда он иногда декодируется правильно, а иногда нет из-за тонких проблем несовместимости, поэтому полезно иметь это в виду.
3-Не уверен, что есть необходимость использовать mb_convert_encoding. Попробуйте удалить его.
Дайте мне знать, что работает для вас.
*** Обновлять: Смотрите комментарии. Теги Pre в javascript вызывали искажение текста, их просто нужно было удалить. После этого сервер генерировал ошибку 418, поскольку помечал строку PHP, выполняющую декодирование, обнаруживая уязвимость безопасности. Они обращаются к своему провайдеру серверов, чтобы решить эту проблему.
Я думаю, что его нужно сохранить в конечном файле как base64, потому что в противном случае я получаю ошибку 418 «Я чайник». Спасибо, что нашли время помочь мне с этим!
Однако проблема здесь в том, что base64 должна быть идеальной кодировкой для использования в сообщениях форм и даже в параметрах запроса URL, поэтому не уверен, почему сервер генерирует такую странную ошибку. Я бы поискал другую причину ошибки 418. Если вы просто удалите эти теги и больше ничего не сделаете, возникнет ли ошибка? Проблема, которую я вижу при размещении предварительных тегов в поле, заключается в том, что я думаю, что он попытается декодировать текст тега в базе 64 вместе с закодированным текстом, и поэтому он всегда будет декодировать неправильно.
Я не знаю точно, в чем ошибка. Насколько я могу судить, когда я делаю вставку без какой-либо дополнительной кодировки, она просто возвращает ошибку 418, независимо от того, какой это был код. Когда я начал вставлять его, завернутый в теги pre и закодированный в Base 64, это позволяло мне вставлять большинство типов кода, и тогда единственной проблемой было его правильное отображение, чтобы он мог декодироваться и отображаться при загрузке. С учетом предложенных вами изменений он вернет ошибку 418, когда я вставлю код (даже в base64) и сохраню его как обычный текст. Полный код находится на github, если вы хотите немного поэкспериментировать.
Хорошо спасибо. Я просто возьму ваши фрагменты, настрою свою собственную маленькую песочницу и посмотрю, что получится. Я сообщу вам, что найду сегодня чуть позже
Мне удалось воспроизвести вашу проблему с искаженным текстом. Это действительно теги Pre. Избавьтесь от них из javascript, и на другом конце он должен правильно декодироваться. Как уже упоминалось, вы можете поместить теги Pre на конец PHP, чтобы текст HTML, представленный в поле, отображался на выходе как необработанные теги HTML. В моих тестах base64_decode и btoa не выявили проблем, так что, вероятно, это не проблема. Кажется, mb_convert_encoding не нужен и не повредит, когда я пробовал с ним и без него. Итак, попробуйте внести изменения в тег Pre, как я предлагаю здесь, и пойдем дальше.
Это не сильно изменилось, я все еще получаю ошибку 418 при вставке кода.
Да, но теперь мы можем сосредоточиться на 418. Искаженный текст вызван тегами Pre, так что теперь давайте поработаем над этим 418. Можете ли вы точно увидеть, в какой момент происходит 418?
Одна вещь, которую вы можете сделать, — это временно изменить свои данные, чтобы просто использовать оператор предупреждения, чтобы выгружать результат обратно на экран, когда вы нажимаете кнопку «Отправить». Я сделал это, как показано ниже. Если у вас это заработает, просто начните медленно переделывать другой код, и вы увидите, где именно генерируется ошибка.
Вставьте это после вызова xhr.open, чтобы просто отображать результаты, и измените php, чтобы просто распечатать данные. Это поможет лучше понять, что вызывает ошибку. xhr.onreadystatechange = () => { if (xhr.readyState === 4) { alert(xhr.response); } };
Это не дало мне никакой ценной информации, но я нашел это в своем журнале ошибок: [Пт, 10 мая 12:55:34.551050 2024] [:error] [клиент 185.246.209.56:49102] [клиент 185.246.209.56] ModSecurity : Доступ запрещен с кодом 418 (этап 2). Соответствующая фраза «base64_decode» в ARGS:text. [файл "/etc/modsecurity/mod_sec3_CRS/99_dreamhost_rules.conf"] [строка "126"] [id "1990070"] [msg "Общие известные аргументы для оболочки бэкдора, присутствующие в ARGS:text"] [имя хоста "paste-bin. us"] [uri "/create.php"], реферер: Paste-bin.us
Ах-ха! Итак, ваш провайдер сервера сканирует ваш код и, похоже, помечает эту строку: $decodedText = base64_decode($_POST['text']); Попробуйте извлечь ссылку _POST из этой строки и использовать вместо нее переменную и передать ее, т. е. $formVar = $_POST['text'] и $decodedText = base64_decode($formVar); Возможно, вам придется обратиться к администратору вашего сервера, чтобы решить эту проблему.
Вот ссылка, по которой, похоже, другие сталкиваются с такой же проблемой: securitycheck.protegetuordenador.com/forum/9-newbies-area/…
Я также настоятельно рекомендую после того, как вы поймете, что нарушает ваш текущий код, изменить его в соответствии с советами других комментаторов, чтобы решить проблемы безопасности и передового опыта.
Мне неясна причина использования кодировки base64, но, возможно, я что-то упускаю. Я не вижу никаких преимуществ в этом. Кроме того, это не имеет отношения к делу, но я редко вижу хорошее использование
mb_convert_encoding, и я не думаю, что это тоже так.