10 ошибок переплетены, сколько вы можете решить?

Java облачный носитель
10 ошибок переплетены, сколько вы можете решить?

​**Введение.** Завершился третий конкурс 83-строчного кода 2021 года, организованный Alibaba Cloud Cloud Effect. Смотрели более 20 000 человек, участвовало почти 4 000 человек, а драться пришли 85 команд. Соревнование использует игровой метод и объединяет элементы метавселенной научной фантастики и уничтожения сценариев, так что все разработчики получат массу удовольствия.

Сегодня я приглашаю Ду Вана, дизайнера финальной конкурсной задачи, поделиться с вами идеями дизайна и решения задач.

С «Убить скрипт игры с помощью кода? Официальный анализ сюжета 3-го конкурса "83-строчный код" лучше.

Четвертый вопрос в целом - это архитектура C/S, клиент-клиент - это скомпилированная программа командной строки, которую нельзя модифицировать, а сервер - это веб-приложение Spring Boot, игра требует, чтобы ошибки в серверной программе были найдены и устранены. исправлено ; У клиента две обязанности: одна — отправить обычный HTTP-запрос на сервер, чтобы участник мог найти ошибку.

Другой — проверка исправлений ошибок и отправка их в удаленную программу оценки для оценки. Весь вопрос в работе на нашей Alibaba Cloud DevStudio, в DevStudio запускаем комьюнити версию Intellij IDEA со встроенным плагином AppObserver.

Ошибка 1: исправить регулярное выражение

Давайте посмотрим, как исправить первую ошибку. Запуск mvn test, 9 ошибок из 10 тестов.

​Здесь есть несколько ошибок. Давайте сначала рассмотрим регулярные выражения. Давайте сначала исправим ExtractHtmlTest, прочитаем исходный код и быстро найдем метод Utils.stripHtmlTag. Название метода означает удаление тега HTML Tag, а затем тщательную проверку. журнал, и вы найдете .

Содержимое удаленного тега включает > и , что означает наличие проблемы с регуляризацией.На следующем рисунке представлен анализ регуляризации.

Таким образом, вышеуказанные два метода ремонта для этой ОШИБКИ в порядке.

Решение: измените регулярное выражение `` в Utils.java на `]*)>`.

Ошибка 2: исправить отсутствующую хвостовую строку

Выполните mvn test еще раз и обнаружите, что все еще есть одиночные тесты, которые не пройдены, и мы обнаружим, что строка немного отсутствует.

Снова проверьте метод Utils.stripHtmlTag и найдите метод matcher.appendReplacement.Если вы не знакомы с этим методом, вы обнаружите, что matcher.appendReplacement и matcher.appendTail появляются парами после проверки комментариев JDK. Поэтому добавьте matcher.appendTail(builder) вне цикла.

​Глядя на картинку, это рабочий механизм matcher.appendReplacement и matcher.appendTail, умело используя этот метод, удобнее заменять строки.

Ошибка 3: исправить исключение EOFException

Выполните тест mvn еще раз, останется только ошибка EOFException, и метод, который может быстро найти ошибку, — это Utils.decodeMessage.

Анализируя комментарии заголовка ReactiveWebSocketHandler и метод Utils.encodeMessage, мы понимаем структуру бинарного пакета:

/**
 * 二进制包格式
 * byte 字符集长度; n1
 * byte[n1] 字符集数据;n1 = 字符集长度
 * byte[n2] 有效数据;n2 = 包总长度 - n1 - 1
 */
@Component("ReactiveWebSocketHandler")
public class ReactiveWebSocketHandler implements WebSocketHandler {

public static byte[] encodeMessage(String message, Charset charset) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(out);
byte[] charsetNameBytes = charset.toString().getBytes(ISO_8859_1);

try {
            dos.write((byte) charsetNameBytes.length);  
            dos.write(charsetNameBytes);
            dos.write(message.getBytes(charset));
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

return out.toByteArray();
    }

Тогда при сравнении Utils.decodeMessage выясняется, что это проблема тайминга вызова, способ исправления следующий:

return new String(dis.readAllBytes(), charsetNameDecoder.apply(dis));

=>

String charsetName = charsetNameDecoder.apply(dis);
return new String(dis.readAllBytes(), charsetName);

Эта единственная тестовая ошибка была исправлена, давайте исправим ошибку состояния.

Настройка Наблюдателя за приложениями

Прежде всего настроим AppObserver, в DevStudio конкурса предустановлен AppObserver, здесь настроим лаунчер IDEA и добавим Application Observer Agent.

После настройки обозревателя приложений запустите процесс на стороне сервера через основную функцию Spring Boot.

Ошибка 4: исправить CSRF

Выполнить клиентскую программу корневого каталога проекта round4

$./round4

   ___          _       ___ _____
  / __\___   __| | ___ ( _ )___ /
 / /  / _ \ / _` |/ _ \/ _ \ |_ \
/ /___ (_) | (_| |  __/ (_) |__) |
\____/\___/ \__,_|\___|\___/____/

「第四关」    致命真相
当你直面致命的真相,你是否能面对这残酷的现实?

::  通关要求                ::  达到 60 分以上
::  获胜要求                ::  分数最高且用时最短


启动客户端程序....


=== Step 1 ====
成功获得数据通道: [
    "/ws/Codeup",
    "/ws/AppObserver",
    "/ws/DevStudio",
]

=== Step 2 ====
添加用户 reporter 失败!响应状态码: 403 Forbidden, 响应消息: "An expected CSRF token cannot be found", 请求头:"Authorization: Basic YWRtaW46YWRtaW4xMjM="

=== Step 3 ====
使用 reporter 用户无法连接到:ws://localhost:8080/ws/DevStudio, 响应状态码: 401 Unauthorized, 请求头: {"authorization": "Basic cmVwb3J0ZXI6cmVwb3J0ZXI="}

Шаг 2 Ошибка CSRF.Так как клиентскую программу нельзя модифицировать, эту проблему нужно решить на стороне сервера и отключить проверку CSRF.

Используйте приведенное выше ключевое слово ошибки в Google, и вы сможете быстро найти метод модификации Spring Security.

Затем измените его в соответствии с днем, снова проверьте его и обнаружите, что код ответа изменился с 403 на 401, поэтому изменение вступает в силу.

Ошибка 5: исправьте ошибку пароля пользователя администратора

Выполните ./round4 еще раз на предыдущем шаге, Шаг 2 возвращает 401 и запрашивает заголовок запроса: «Авторизация: Basic YWRtaW46YWRtaW4xMjM=", здесь мы видим, что используется метод аутентификации HTTP Basic, а затем 401 подсказывает, может быть, что имя пользователя и пароль неверны. , поэтому здесь вы можете использовать base64 для распаковки заголовка аутентификации и изменения имени пользователя и пароля сервера.

Ошибка 6: неправильная роль администратора

После повторного выполнения ./round4 мы обнаружили, что он снова изменился на 403, но возвращенная ошибка стала Access Denied. Вроде пароль правильный, но нет разрешения на доступ, открываем файл WebSecurityConfig, мы обнаружим, что роль admin имеет два варианта написания "ADMIN" и "admin", проблема кроется здесь, попробуем измените его на верхний регистр.

​Шаг 2, забудьте об этом, следующий шаг — это вопрос Шага 3.

Ошибка 7: отсутствует роль РЕПОРТЕР

Шаг 3 Сообщите об ошибке, пользователь-репортер не может подключиться к: ws://localhost:8080/ws/AppObserver, код состояния ответа: 403 Запрещено, заголовок запроса: {"авторизация": "Basic cmVwb3J0ZXI6cmVwb3J0ZXI="}.

Это еще одна проблема с разрешениями.Во-первых, разблокируйте авторизацию в кодировке base64 и обнаружите, что пароли пользователей - все репортеры. Затем вам нужно использовать наблюдатель приложения, чтобы добавить виртуальную точку останова в Round4Controller.addUser. Виртуальная точка останова может получать информацию о стеке потока и переменной контекста выполнения, как и обычные точки останова, но виртуальные точки останова не будут блокировать выполнение. очень полезно для производственных систем.

Конкретная операция показана на следующем рисунке.

Через виртуальную точку останова мы обнаружили, что роль пользователя-докладчика — REPORTER, а конечная точка «/ws/**» в настоящее время разрешает доступ только роли ADMIN, поэтому в конфигурации безопасности добавьте роль REPORTER в путь.

Проблема роли была решена, и были исправлены 4 ошибки, связанные с Spring Security. Перезапустите службу и выполните ./round4 Сначала мы отправим искаженные символы, а затем посмотрим, как исправить искаженные символы.

Ошибка 8: общий буфер

Путем анализа ряда мапперов в ReactiveWebSocketHandler мы обнаружим, что метод getBufferConverter возвращает буфер фиксированной длины, а за этим буфером будет ряд значений 0, что очень подозрительно. Внимательно изучив код, можно обнаружить, что один и тот же буфер совместно используется несколькими вызовами без его очистки. Решение тоже очень простое, достаточно каждый раз менять разделяемый буфер на новый. Как показано ниже:

​После исправления снова запустите ./round4, искаженного кода нет, но возвращаемый контент немного меньше, что указывает на наличие других проблем.

Ошибка 9: исправить NPE

После исправления вышеупомянутой искаженной проблемы в текущих выводах клиентского раунда 4 не видно очевидных ошибок. Это связано с тем, что содержимое немного короткое. Глядя на журнал на стороне сервера, вы увидите ошибку NPE:

NPE относительно легко исправить, а возвращаемый нуль можно быстро проверить.

Измените его, чтобы вернуть "";.

Ошибка 10: удалить ThreadLocal

Перезапустите сервер и снова выполните ./round4, контента много, но опять искажено.

Последний баг не очень легко отладить, нужно читать код с аутентификацией и понимать контекст, видно что там странная переменная ThreadLocal используется для кэширования charsetName.

Кодировка постоянна в потоке? Удаление оценки не повлияет на эффект, максимум производительность чуть хуже, попробуйте убрать.

Перезапустите сервер и снова выполните ./round4.

На этот раз все в норме.

Извлечь подсказки

Возвраты из трех вышеперечисленных каналов содержат подсказки к конкурсу, поэтому мы можем использовать инструмент grep, чтобы выбрать их.

Мы не будем здесь обсуждать сюжетный вопрос, вы можете прочитать другую расшифрованную статью.

резюме

Всего исправлено 10 ошибок

  • Регулярное выражение 2
  • Весенняя безопасность 4
  • 1 НПЭ
  • EOF 1
  • Общее состояние 2

Технология, участвующая в конкурсе

  • Spring Boot
  • Spring Security
  • Spring WebFlux
  • Java IO
  • JUnit 5
  • Regex
  • Websocket
  • CSRF
  • HTTP Basic Auth

инструмент

  • DevStudio (Intellij IDEA для Интернета)
  • AppObserver (плагин CloudToolkit)

Оригинальная ссылка

Эта статья является оригинальным контентом Alibaba Cloud и не может быть воспроизведена без разрешения.