Статьи

Ведение журнала ошибок и отслеживание их правильности с Raygun.io

Вот уже несколько лет одной из первых вещей, которую я бросил в новый проект, была ELMAH . Возьмите его из NuGet, предоставьте себе таблицу базы данных SQL и наблюдайте, как происходит волшебство, поскольку каждая необработанная ошибка сбрасывается в БД и доступна для просмотра через обработчик, который предоставляет исходную трассировку стека среди другой информации, такой как переменные сервера и данные POST. Теоретически, вы также обеспечили это. На практике многие люди этого не делают .

Чтобы получить представление о том, что делает ELMAH, проверьте это на моем образце небезопасного сайта «Supercar Showdown». Это аккуратные вещи, но это также абсолютный пожарный исключений. Одно и то же есть снова и снова; здесь нет сортировки или пометки исключений, а просто страница за страницей с теми же проблемами. В определенные периоды жизненного цикла определенных проектов я использовал автоматическое уведомление по электронной почте, чтобы сообщить, когда возникает исключение, а затем затопляется шумом. О — и запись в БД не будет работать, если исключение, которое она пытается записать, это то, что БД не может быть достигнута!

Но это не предназначено для того, чтобы быть сеансом ELMAH, поскольку он действительно очень хорошо служил мне в течение многих лет, а скорее для того, чтобы взглянуть на следующую эволюцию регистрации ошибок, и вот что приводит нас к Raygun.io :

Raygun.io брендинг

С таким брендингом это должно быть круто, правда ?! На самом деле да, это так. Позвольте мне объяснить, как это работает для меня и проблемы, которые он решает.

Ошибки случаются. Смирись с этим!

Прежде всего, давайте проясним, что необработанные исключения всегда будут происходить. Да, вы тестируете как сумасшедший, и да, вы исключение обрабатываете все, на что вы способны, но в Интернете неизбежно случатся забавные вещи. Вот пример: на меня напали? (сайт, на котором я буду реализовывать Raygun.io для этого поста, часто называемого HIBP), у меня есть средство для поиска всех взломанных учетных записей в домене. Это выглядит так:

Поиск по домену в HIBP

Теперь, что, по вашему мнению, является допустимым значением для поля «Подписаться на меня»? Если это проверено, это должно быть «верно», верно? Тогда с какой стати я просто получил десятки запросов со значением «on», что впоследствии вызвало исключение 500, потому что строка не может быть приведена как логическое значение? Это заставило мой ELMAH записать беспорядок и снова и снова заполнять его одним и тем же мусором:

Повторный журнал ELMAH барахла

И когда мы заглянем внутрь данных формы, отправленных с запросом, вот что мы видим:

ELMAH форма POST данных

Да, я не думаю, что «Joey» является действительным доменным именем! Это всего лишь разновидность спам-бота, отправляющего случайный мусор. (Интересно, что на самом деле он извлекает из формы то, что выглядит как действительный токен подтверждения запроса, поэтому он, вероятно, сначала запрашивает страницу.) Очевидно, что он все равно не прошел бы CAPTCHA (см. Почему у меня это сейчас?), Но смысл в том, что странные вещи будут происходить с вашим приложением способами, которые вы никогда не планировали, либо из-за того, что пользователи были случайными существами, либо из-за автоматизации вашего сайта.

Да, и на тот случай, если вам интересно, почему для флажка «SubscribeToNotifications» есть два значения, вспомогательный флажок ASP.NET MVC делает это сам по себе . И да, действие контроллера действительно проверяет, что модель действительна, но (попытка) преобразования в логическое значение происходит выше по потоку, когда данные формы приводятся к типу модели для действия.

Попытка сортировать пшеницу из соломы (АКА «Бритья яка»)

В прошедшие времена я добавлял правила перезаписи URL, чтобы перехватывать нечетные запросы и отправлять их в разных направлениях, чтобы они не вызывали исключений. Например, я продолжал получать запросы на «умную цитату» в корне домена, которая вызвала бы 404, поэтому я бы сделал постоянное перенаправление обратно в корень. Это ваше общеизвестное бритье яков, которое, по сути, не имеет никакой реальной ценности (если, конечно, они не являются законными запросами пользователей). В действительности, вероятно, лучше, чтобы эти запросы вызывали исключения, но не позволяли им заполнять мой журнал ошибок шумом.

Когда мы думаем об этом, исключения делятся на две основные категории:

  1. Вещи, которые пошли не так, и я действительно должен исправить. Это могут быть подлинные ошибки в результате законного использования сайта, и я буду оказывать пользователям услугу, разрешая их, или они могут быть неожиданным способом, который в любом случае не должен работать, но было бы хорошо, чтобы исключения не возникали, поскольку результат.
  2. Вещи, которые пошли не так, и мне просто все равно. Это очень много сценариев, описанных выше, где они выходят за пределы правильного использования, но я не обязательно хочу использовать обходной путь только для того, чтобы уменьшить шум ошибки. Я бы хотел, чтобы это было записано, я просто не хочу, чтобы это мешало мне сосредоточиться на действительно важных ошибках.

Конечно, нет никакой возможности точно автоматизировать классификацию этих исключений, нам нужны средства для их сортировки. Мы также хотим иметь возможность взять случай, подобный недействительному логическому значению, ранее, и сказать: «Это исключение, и я рад его записать, но для всех намерений и целей его следует игнорировать».

Так что это фон, давайте перейдем к тому, чтобы заставить Raygun.io работать на HIBP.

Монтаж

Еще одно важное замечание перед подробностью: Raygun.io — это не просто служба регистрации исключений веб-сервера, но и отличные вещи в клиентских приложениях, таких как iOS и Android. В этих средах возникают всевозможные проблемы из-за часто отключенного характера приложения, поэтому иметь такой инструмент, как этот, можно в качестве простого сервиса и запускать его на нескольких серверах и клиентских стеках — довольно круто. Послушайте Джона-Даниэля Траска (соучредителя и генерального директора) на Hanselminutes для действительно хорошего изложения этого.

Продолжая, HIBP — это все ASP.NET MVC в Azure, и получить бит Raygun.io от NuGet очень просто . Вставьте пакет, установите свой ключ API из того, который вы найдете под своей учетной записью на веб-сайте, и все, работа выполнена. Кажется, это слишком просто, но это было все, что нужно. Затем я добавил действие контроллера на сайт, которое намеренно вызвало исключение (попытка создать GUID пустой строки сделает это!) Просто для проверки работоспособности. И это сделал. Сначала иди.

Откуда я знаю, что это сработало? Это подводит нас к приборной панели.

Панель приборов Raygun.io

Давайте просто прыгнем прямо в это:

Панель приборов Raygun.io

Это меньше, чем за неделю данных на сайте, который был очень тщательно проверен и уточнен, поэтому я не ожидаю увидеть там много исключений (по крайней мере, не подлинных, вызванных законным использованием сайта), но есть немногие мы можем посмотреть здесь. Исключения сгруппированы , которые аккуратно , потому что если что — то пойдет не так , и вы внезапно заканчивается с тысячами тех же вещей , которые вы будете видеть его, но он не заглушит все другие исключения , как это было бы в модели Elmah.

Вторая ось позволяет вам выбрать отрезок времени для увеличения, который затем фокусирует график на определенной области интереса:

Увеличение на период времени

Каждая точка на графике также «активна», поэтому вы можете сразу получить информацию:

образ

Это ваши основные функции, давайте углубимся в детали и выясним, что происходит с этими исключениями.

Оценивая исключение

Давайте посмотрим на один из них более подробно, и я собираюсь выбрать последний из приведенного выше списка, который является исключением проверки запроса. Помните, что в ASP.NET встроена защита XSS, и HttpRequestValidationException будет вызываться, если запрос содержит потенциальную полезную нагрузку межсайтового скриптинга, что преимущественно означает, что он имеет угловые скобки, которые выглядят как возможный тег HTML. Давайте углубимся в это:

Подробности возникновения исключений

Просмотр данных, представленных таким образом, дает нам действительно хорошее представление о том, что происходит. Исключения распределяются по дням, а не объединяются, поэтому это явно не временная проблема. С другой стороны, похоже, что он влияет только на одного пользователя, и они используют IE, поэтому он может быть ограничен только им или только браузером Microsoft. Нам понадобится больше информации, чтобы докопаться до сути этого, поэтому давайте прокрутим немного вниз и посмотрим на исключение:

Экран сведений об исключениях с дополнительной информацией

Это довольно очевидно, хотя было бы неплохо увидеть, что IP-адрес транслируется в физическое местоположение и имя сети, поскольку это может быть довольно полезно время от времени (кстати, этот из Китая ). Трассировка стека показывает, в точности то, что вы ожидаете, поэтому я не буду воспроизводить это полностью здесь. Если я нажму «Следующий экземпляр», то мы увидим, что предыдущее исключение (в хронологическом порядке по убыванию) было с другого IP-адреса ( другое место в Китае ), хотя и с тем же сообщением:

То же сообщение HttpRequestValidationException

Подождите — почему только один пользователь затронут, когда мы видим исключения с разных IP-адресов? Поскольку они оба имеют одинаковую аутентифицированную личность, которая в данном случае является анонимной — на сайте нет функции входа в систему. Если бы пользователи действительно могли проходить аутентификацию, тогда была бы возможность точно сообщить о количестве уникальных идентификаторов, на которые повлияло исключение, что довольно полезно для оценки области действия. Больше информации об этом в документации .

Далее, ценные данные с точки зрения того, как добраться до сути, находятся на вкладке «Запрос», и в ней есть почти все мыслимое с точки зрения как состояния клиента (заголовок и тело запроса, включая файлы cookie и данные формы), так и состояния сервера. (а именно переменные сервера). Это слишком много, чтобы воспроизвести полностью здесь, но я поделюсь данными формы, поскольку именно там действительно полезная информация:

Данные формы размещены в ошибочном запросе

Ах, да, так что мы смотрим на спам-бота, который подключает дизайнерские солнцезащитные очки и явно не знает, как обойти CAPTCHA (сказал, что вы служите цели)! Возникает исключение проверки запроса, потому что он пытается разместить гиперссылку в поле CAPTCHA, а угловые скобки расстраивают вещи.

С одной стороны, это спам, поэтому он явно не оказывает негативного влияния на пользователей и не должен беспокоить меня. С другой стороны, мне не нравятся необработанные исключения любого рода, и это также поднимает интересный вопрос — что, если CAPTCHA когда-либо законно имеет угловую скобку? Хотя я не могу сказать, что я когда-либо видел, это кажется осуществимой возможностью. Это поле никогда не перерисовано в любом месте , так что нет никакого риска XSS (и он будет автоматически кодируется HTML помощник в MVC , даже если он был), так запрошено подтверждение действительно необходимо здесь? Наверное, нет, давайте отключим его для атрибутов модели:

[AllowHtml]
public string recaptcha_challenge_field { get; set; }

[AllowHtml]
[Required(ErrorMessage = "The puzzle must be solved")]
public string recaptcha_response_field { get; set; }

Теперь, почему я украсил два поля AllowHtml? Задача — та, которая вызывает исключение — генерируется CAPTCHA и является токеном, который ее идентифицирует. При нормальной работе он передается в скрытом поле и фактически никогда не виден пользователю . При всей своей мудрости это то, чем манипулирует спам-бот (обратите внимание, ребята — скрытые поля часто содержат то, чего вы никогда не ожидаете!), И поле ответа — это то, в которое пользователь обычно вводил бы. Я бы почти подумал просто отключить проверку запросов на сайте, учитывая ее природу (и другие причины, о которых я напишу в другой раз), но сейчас это не позволяет запускать только эти два поля.

Теперь, когда я реализовал это изменение, протестировал его и «исправил» это необработанное исключение, я собираюсь «разрешить» его:

Пометка исключения как «Разрешено»

Теперь это выпрыгивает из моего списка активных исключений и переходит на вкладку «Решено»:

Все исключения одного типа сгруппированы и «разрешены»

Мне нравится такой подход по нескольким причинам: во-первых, я не теряю информацию об исключениях, с которыми я сталкивался в прошлом. Мне нравится иметь под рукой данные и, за некоторыми исключениями, возможность вернуться к ним позже может быть очень полезной. Во-вторых, обработка исключений таким способом позволяет мне использовать эту вкладку «Активные» в качестве списка дел; все, что есть, есть что-то, с чем нужно так или иначе иметь дело, чтобы оно в конечном итоге сводилось к нулю.

игнорирование

Время от времени вы обязаны получать ошибки, которые на самом деле не требуют каких-либо действий, хотя, строго говоря, они все еще остаются необработанными исключениями. Хорошим примером является отсутствующий файл cookie для защиты от подделки для защиты от CSRF. Большинство реализаций защиты от подделки зависят как от скрытого поля, так и от файла cookie, которые соединены вместе, чтобы не дать злоумышленникам обманом заставить браузер сделать запрос. Если нет файла cookie, мы увидим исключение, похожее на это:

Исключение из-за отсутствия анти-подделки cookie

Мы можем легко выяснить, что здесь происходит, проверив детали запроса и посмотрев файлы cookie, отправленные браузером при возникновении исключения:

В запросе не было отправлено куки

Ах, хорошо, так что без печенья. Нет cookie-файлов Google Analytics, нет файлов cookie, связанных с Azure, и, конечно, нет cookie-файлов с маркерами защиты от подделки. У этого клиента почти наверняка отключены файлы cookie, что означает, что они не будут отправлять формы с токенами против подделки. Теперь есть способы взломать зависимость от cookie, и, возможно, вы могли бы спросить, нужно ли это вообще на неаутентифицированном ресурсе, таком как функция поиска в домене, где это происходит, но ради этого упражнения я действительно просто хочу игнорировать эти ошибки. , На самом деле я хочу навсегда игнорировать их

Навсегда игнорируя ошибки

Это исключит их из списка активных исключений и не будет отправлять мне никаких уведомлений, и это будет более всеобъемлющим, чем просто «игнорирование» одного исключения (подробнее о семантике здесь ). Я сказал уведомления? Давайте рассмотрим это сейчас.

Уведомления по электронной почте

Прямо на открытии этого поста я упомянул, как я был залит электронными уведомлениями ELMAH в прошлом. Они отлично подходят для того, чтобы сразу сказать, что что-то идет не так, но вы должны быть осторожны с этим. Я не хочу, чтобы 50 писем об одной и той же вещи, я хочу одну, когда она сначала сломается, потом я пойду и разберусь. Если после этого это случится снова, тогда да, я хочу, чтобы мне снова сказали. Это требует некоторых умов, но это именно то, что делает Raygun.io.

Когда возникает ошибка, которой не должно быть (то есть вы не слышали об этом раньше, и она не игнорируется навсегда), вы сразу получаете сообщение, подобное этому:

Уведомление по электронной почте о новом исключении

Это именно то исключение, которое я не хочу видеть — Entity Framework испытывает проблемы с подключением к базе данных. Я хочу знать о таких вещах как можно скорее, так как это может быть то, что БД находится в автономном режиме или если это только после публикации, я мог что-то сломать на стороне приложения. Вы можете сразу перейти к исключению и просмотреть детали с помощью трассировки стека, которая быстро раскрывает причину проблемы:

Произошла ошибка транспортного уровня

Хорошо, «ошибка на транспортном уровне», я ничего не могу с этим поделать. Как вы уже видели, я также могу посмотреть на другие исключения того же типа, и оказывается, что это очень необычно:

Только две ошибки транспортного уровня в истории исключений

Я мог бы хотеть взглянуть на то, что является причиной этого более близко, но это также может быть вне моего контроля (то есть SQL Azure просто недоступен в очень странном случае). Я просто пока проигнорирую обе эти ошибки, что означает, что я все равно получу уведомление по электронной почте, если это произойдет снова, но я удалил их из активных исключений на моей панели инструментов.

Ручная регистрация исключений

Все автоматическое обнаружение и регистрация необработанных исключений — это здорово, и это определенно является основной ценностью сервиса так же, как и для ELMAH. Но также как и в случае с ELMAH, бывают случаи, когда вы хотите явно регистрировать свои собственные исключения, и оказывается, что это принципиально просто:

try
{

}
catch (Exception ex)
{
  new RaygunClient().Send(ex);
}

Или, конечно, вы можете просто поднять свой собственный тип исключения. Несмотря на это, дело в том, что у вас есть программный контроль над процессом, который действительно аккуратен.

Между прочим, это работает очень хорошо в HIBP, когда я подключаюсь к сторонней службе, где куча вещей может работать неправильно (соединение разорвано, ключ API недействителен, они изменяют свою модель данных и т. Д.)

Сохранение ошибок вне сред разработки с помощью конфигурационных преобразований

Простота добавления Raygun.io через web.config потрясающая, но у вас также есть эта проблема:

Исключение зарегистрировано из моей локальной среды разработки

Я не хочу регистрировать исключения из моей среды разработки, просто нет смысла. Я ожидаю, что что-то сломается, пока я его строю, и я не хочу, чтобы это запачкало воду и скрыло законные ошибки.

Поскольку конфигурация Raygun.io находится в web.config, просто применить преобразования конфигурации так, чтобы они добавлялись только при публикации с использованием профиля сборки «Release». Вот как теперь выглядит мое конфигурационное преобразование:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <configSections>
    <section name="RaygunSettings" type="Mindscape.Raygun4Net.RaygunSettings, Mindscape.Raygun4Net" xdt:Transform="Insert" />
  </configSections>
  <system.web>
    <httpModules>
      <add name="RaygunErrorModule" type="Mindscape.Raygun4Net.RaygunHttpModule" xdt:Transform="Insert" />
    </httpModules>
  </system.web>
  <system.webServer>
    <modules>
      <add name="RaygunErrorModule" type="Mindscape.Raygun4Net.RaygunHttpModule" xdt:Transform="Insert" />
    </modules>
  </system.webServer>
  <RaygunSettings apikey="[my API key]" xdt:Transform="Insert" />
</configuration>

Очистите web.config в dev, исправьте web.config в prod и не допускайте ошибок Raygun.io там, где они мне не нужны.

Кстати, если исключение , как это делает проникнуть в Railgun.io, вы можете разбомбить его полностью, нажав на значок шестеренки:

Навсегда удалить исключение

Это навсегда убьет его из системы, а это именно то, что вы хотите в таком случае.

Когда материал не найден — AKA HTTP 404 — (и почему вы хотите знать об этом)

Один из самых болезненных моментов фильтрации по журналам ELMAH — 404 с. Да, я хочу знать, когда какой-нибудь неприятный бот продолжает запрашивать admin.php, но нет, я не хочу продолжать слышать об этом! С точки зрения безопасности, куча векторов атак приводит к 404-м годам, и идеальным примером является автоматическая очистка страниц PHP. Я хочу знать, когда происходит что-то новое , и мне нужна история повторных попыток на тот случай, если мне понадобится вернуться назад и рассмотреть вещи в какой-то момент.

Это также важно для удобства использования; рано или поздно вы собираетесь переименовать или переместить что-то, от чего кто-то зависит, и вы узнаете только о том, когда возникло исключение — или когда они жалуются на это! Или вот еще одна — статья о HIBP, связанная со страницей часто задаваемых вопросов, но по какой-то причине они ссылаются на / FAQ (в единственном числе) вместо / FAQ (во множественном числе). Я знал это только потому, что пробежал по журналам ELMAH и нашел 404-е. Как только я поднял его, это было легко исправить с помощью правила перезаписи URL (хорошо, они должны были исправить это в конце, но удачи в достижении такого прогресса с прессой!), Но суть в том, что я только взял это потому что я поймал в ловушку исключение. Конечно, с Raygun.io я также заблаговременно уведомляю об этом типе исключения по электронной почте, поэтому, когда что-то вроде этого идет не так (даже если это не моя вина),Я могу справиться с этим быстро, умно.

Понятно, что я был в восторге от этой функции в Raygun.io, но когда я пошел ее тестировать… Нада. Нет 404 отслеживания. Я поделился этим с ребятами и получил очень хорошую поддержку, которая в основном сводилась к «ASP.NET MVC, прикольной обработке семантики ошибок», но это было то, что они быстро исправляли. Это было только на прошлой неделе, и сегодня они выпустили версию 2.2.1 с обещанным исправлением. Обновитесь с NuGet, нажмите на GitHub, позвольте Azure творить чудеса и…

404-е захвачены Raygun.io

Там мы идем, 404s теперь вошли! На самом деле это прекрасный пример того, зачем это нужно, поскольку я сгенерировал их из сканирования ASafaWeb . Для непосвященных это мой маленький бесплатный сервис для удаленной оценки неправильной конфигурации безопасности ASP.NET на живых веб-сайтах, который всегда приводит к куче 404 или другим внутренним исключениям на целевом сайте. В таком случае, возможность легко извлекать заголовки запросов, упрощает понимание такого рода вещей:

Запрос ASafaWeb, вызвавший исключение

Конечно, в таком случае я просто сортировал исключения как «Игнорировать все», чтобы они не выпали в будущем, но они все равно будут собраны, и я смогу просмотреть их позже. Это, ИМХО, просто идеальный баланс.

Потому что ваша собственная база данных не там, где вы хотите регистрировать ошибки

Одна из основных причин, по которой такой сервис, как Raygun.io, имеет смысл для веб-сайта, заключается в следующем: когда возникают необработанные исключения, обычно это происходит из-за того, что что-то идет не так. Ожидание, что сбойное приложение надежно зарегистрирует их в своем собственном хранилище, как я делал ранее с ELMAH, рано или поздно вызовет проблемы. Я видел, как это произошло — «Эй, в журнале нет исключений!» — да, это потому, что БД достигла емкости, и они не могли быть зарегистрированы! Это вполне могло иметь место в том ранее исключении транспортного уровня, о котором я говорил.

Чтобы быть справедливым, есть услуги ELMAH, которые доступны в аналогичной модели, например, TraceAgent и elmah.io . Все они имеют несколько разные модели ценообразования, которые делают некоторые структуры более привлекательными, чем другие, но ни одна из них не поддерживает широкую платформу Raygun.io не только на сервере, но и для клиентских приложений. Плюс это из-под Down Under, и хотя они новозеландцы, когда дело доходит до того, что они делают что-то удивительное, мы обычно считаем их почетными австралийцами 🙂

Другие вещи и подведение итогов

Все вышеперечисленные фрагменты являются фундаментальными для понимания как захвата исключений в целом, так и реализации Raygun.io в частности. Но это еще не вся история — это еще не все!

Например, есть экосистема плагинов. Используйте FogBugz для отслеживания проблем и хотите создавать элементы для своих исключений там? Для этого есть плагин. Вместо этого использовать систему отслеживания проблем GitHub? Да, плагин для этого тоже. На самом деле существует куча плагинов для различных целей:

Экосистема плагина Raygun.io

Тогда есть аспект безопасности вещей; как я уже упоминал во вступительном абзаце, вы должны быть довольно осторожны с регистрацией исключений, иначе могут случиться плохие вещи . Вы доверяете Raygun.io, чтобы получить правильное приложение, и пока, похоже, они проделали довольно хорошую работу. Они также дают вам возможность настраивать классы данных, которые вы собираете и храните вместе с ними. Последнее, что вам нужно, — это совместить все PCI DSS, а затем отправить исключение в Raygun.io вместе с информацией о кредитных картах, отправленных в неудавшемся запросе, это не очень хорошо. К счастью, определение переменных формы, которые вы не хотите перехватывать, очень просто, и все идет прямо в web.config:

<RaygunSettings apikey="your_apikey" ignoreFormDataNames="password,creditcard,cv2" />

И, наконец, об обязательном раскрытии — я написал о Raygun.io не потому, что мне заплатили (я не был), а потому, что, честно говоря, инструмент качается. Написание подобных сообщений заставляет меня понять, что происходит, и гарантирует, что я могу четко выразить это другим людям. Этот пост также является частью текущей живой документации HIBP, так что вы можете увидеть, что стоит за служением такого рода. Теперь ребята в Raygun.io сделали фильм меня к бесплатной учетной записи, я полагаю , что как долго длится все зависит от того, насколько хорошо работы , которую я сделал из закрепляющей преимуществы сервиса 🙂