Ремонтируем онлайн-банкинг

от автора


На днях у меня перестал работать онлайн-банкинг моего банка. Нет, не то чтобы совсем перестал — вроде бы можно зайти и даже кое-что сделать, но вот одна из самых важных вещей (просмотр архива платежей) — просто намертво отказалась работать (а как раз было очень нужно). Выглядит это так: при открытии страницы со списком платежей браузер съедает всю доступную оперативную память и падает. В Chrome падает только текущая вкладка, а вот Firefox и IE умирают совсем. Баг воспроизводится на трёх разных PC, айпаде, в Safari под Mac OS и в Firefox под Linux. Ну это я просто так рассказываю, для того чтобы показать наивность советов техподдержки «поставить антивирус» и «перезагрузиться и зайти ещё раз». Давайте подумаем — можем ли мы что-нибудь в этой ситуации сделать?

Кто виноват?

Первым делом нужно понять, кто именно виноват в поглощении памяти — браузер или какая-нибудь сторонняя компонента. Идём в настройки Chrome и отключаем все установленные расширения. Открываем страничку chrome://plugins/ и отключаем Java, Flash, Silverlight и вообще всё что там есть. Перезапускаем на всякий случай браузер, опять идём на страницу архива платежей — и снова крэш из-за съедания всей доступной памяти.

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

Так кто же виноват?

«Инструменты разработчика» (Ctrl+Shift+I) в Chrome показали, что страничка грузит примерно десяток js-файлов. При этом после окончания загрузки всех файлов и до момента крэша вкладки проходит секунды 3-4. Первое, что приходит в голову, это то, что с такой скоростью кушать память может только бесконечный цикл, в котором непрерывно выделяется память под что-то. Нужно только его найти и обезвредить. Хорошо, что в Chrome есть встроенный отладчик и возможность прервать выполнение Javascript-кода, увидев call-стек и значения переменных в момент остановки. Плохо, что на это есть всего те самые 3-4 секунды до крэша вкладки — после этого отладчик уже бесполезен. После двух-трёх тренировок мне наконец удаётся вовремя остановить работу кода. И я вижу что находимся мы в функции, имеющей вот такой код:

function(b,d) { var val=""; var a=b-this.count*2; while(a--) {val+="*"} ... } 

Выше по call-стеку около 40 вызовов других функций, а вообще мы находимся в файле, код которого сжат и даже в таком виде занимает ну слишком большой объём, чтобы его весь разбирать. Но мы ведь помним, на что ещё в самом начале были подозрения — «бесконечный цикл, внутри которого выделяется память». Цикл while(a—) имеет всего шансы им быть. Хорошо если а будет небольшим положительным числом. А если оно будет пару равно паре миллиардов? А если оно будет отрицательным? Может быть вы видите где-нибудь проверки на это? И я не вижу. Скорее всего, вот она ошибка и есть.

Что делать?

Попробуем для начала просто пропустить этот цикл. Понятия не имею к чему это может привести, но вряд ли на странице с архивом платежей я вдруг совершу какую-то непоправимую операцию (тем более, что все непоправимые операции требуют подтверждения). Минимальным изменением кода мне показалось заменить while(a—) на while (0). Теперь нужно как-то поправленный скрипт подсунуть браузеру. В этом месте самое время признаться, что я ни разу не веб-разработчик, а поэтому понятия не имею как у них там, в Web-деве принято это делать. Но я чуть-чуть разбираюсь во всяких полезных инструментах и один из самых полезных в деле изучения\модификации HTTP-траффика — это Fiddler2. Он, во-первых, является прокси-сервером, пропуская через себя весь трафик от сервера к браузеру, а во-вторых позволяет в ответ на определённые запросы отдать заранее заданный текст или файл. Дальше — дело техники. Сохраняем бажный скрипт на диск, правим цикл, включаем Fiddler2 и настраиваем в нём правила перенаправления.

Вуаля!

Открываем браузер, идём на страницу платежей и вот сюрприз — всё работает нормально! Вот уж не знаю, что там эта функция должна была звёздочками декорировать, но и без неё всё хорошо, а главное — больше не бесконечно. Мораль сей басни — никогда не сдавайтесь, всегда можно что-то придумать и найти выход.

P.S. Адреса страниц и названия переменных на всякий случай изменены (без изменения сути). Банк уведомлен о баге.

ссылка на оригинал статьи http://habrahabr.ru/post/179915/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *