Статьи

Ты не знаешь валетов: научись делать свой код более безопасным

Эта статья была спонсирована Codiscope . Спасибо за поддержку спонсоров, которые делают возможным использование SitePoint.

Я играл в игру под названием « Ты не знаешь, Джек» . Это пустяковая игра, заданная как игровое шоу, в котором весело проиграть. При неправильном ответе игрок получает остроумный и непочтительный выговор от хозяина игры.

Это также урок того, как мелкие детали означают разницу между пониманием чего-то правильного и ужасно неправильным.

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

В отличие от викторины, она более прощающая. Здорово, когда вы действительно не знаете, что делаете – как я узнал, когда решил изучить новую веб-среду.

Большую часть кода для этого поста можно найти на Github . Я проверил это в Node 7.0.0 на macOS Sierra 10.12.1 .

Получение хапи

Я написал много небольших приложений для NodeJS и часто обнаруживал, что Express достаточно для нужд моего веб-приложения. Но я также задавался вопросом, как лучше структурировать гораздо большее приложение. Есть варианты самоуверенного, как у Адониса , но я с ним уже хорошо знаком. Что нового я мог бы узнать, в то же время пинать шины Джека?

А потом я увидел упоминание о Хапи на домашней странице Джека .

Я открыл свой терминал, сделал новую папку проекта и установил Hapi:

 yarn add hapi 

Вы также можете установить Hapi, используя NPM . Я просто любитель тенденций, а пряжа чертовски быстро!

Согласно документам, сделать приложение Hapi так же просто, как:

 "use strict" const hapi = require("hapi") const server = new hapi.Server() server.connection({ "port": 3000, }) server.route({ "method": "get", "path": "/", handler: function (request, reply) { reply("hello world") }, }) server.start(err => { if (err) { throw err } console.log("server at " + server.info.uri) }) 

Это из index.js .

Если вы использовали Express, это должно показаться вам знакомым. Я создал новый HTTP-сервер с одним маршрутом. Когда браузер запрашивает / , этот маршрут ответит hello world :

Привет, мир

Подключить

Следующим шагом было подключение моей учетной записи Github к Джеку. Создать учетную запись Jacks было довольно легко и бесплатно. Сначала я создал новый проект:

Создание нового проекта

… А затем я подключил свою учетную запись Github (и репозиторий проекта) к Jacks:

Подключите к гнездам

Все это заняло около 2 минут, от начала до конца.

Ошибаясь

Теперь пришло время посмотреть, насколько полезным может быть Джек. Я собрал список распространенных ошибок безопасности веб-приложения и решил попробовать несколько, чтобы посмотреть, что скажет Джекс (и как это может научить меня быть лучше на работе).

Политика безопасности контента

На данный момент я не ожидал, что у Джека пока что есть какие-либо рекомендации для меня. Но когда я вернулся к интерфейсу, я увидел первый совет, который он мог мне предложить:

Рекомендация CSP

Потребовалось немного времени для поиска хорошего объяснения, но я наконец нашел его в Справочнике и примерах политики безопасности контента CSP . CSP – это, по сути, способ ограничения места загрузки ресурсов HTTP. Это замечательно, потому что злоумышленники, которые могли бы внедрить пользовательские сценарии и / или изображения, не смогли бы использовать эти уязвимости так же легко.

Джекс также предоставил пример кода для того, как добавить Blankie в мой серверный скрипт:

 "use strict" const hapi = require("hapi") const blankie = require("blankie") const scooter = require("scooter") const server = new hapi.Server() // ...create server + connection + routes server.register([scooter, { "register": blankie, "options": { // ..CSP directives here "defaultSrc": "self", } }], err => { // ...start server }) 

Это из index.js .

Чтобы этот код работал, мне нужно было установить Blankie и Scooter с yarn add blankie и yarn add scooter yarn add blankie . Они добавляют заголовки CSP к каждому запросу:

Заголовки CSP

Конечно же, как только я передал этот код в проект, Джекс заметил это и отметил рекомендацию как решенную.

Отключение списков каталогов

Распространенной ошибкой безопасности является включение (или, скорее, неправильное отключение) списков каталогов в веб-приложениях. Существует популярный плагин Hapi, который называется Inert, который обеспечивает статическое обслуживание файлов и списки каталогов. Это не редкость, чтобы включить эти функции, вот что я пытался сделать:

 "use strict" const hapi = require("hapi") const blankie = require("blankie") const scooter = require("scooter") const inert = require("inert") // ...create server + connection server.register([inert, scooter, { "register": blankie, "options": { // ..CSP directives here "defaultSrc": "self", } }], err => { // ...create other routes server.route({ "method": "GET", "path": "/{params*}", "handler": { "directory": { "path": "public", "listing": true, }, }, }) // ...start server }) 

Это из index.js .

Мне нужно было установить yarn add inert , с yarn add inert , чтобы этот код работал. После этого я смог увидеть списки каталогов в вашем веб-приложении:

Список каталогов

Я отправил этот код в хранилище и прыгнул к Джеку для анализа. Как и ожидалось, он предупредил против включения списков каталогов:

Предупреждение о списке каталогов

Более того, он предоставил мне информацию о патче, чтобы отключить списки каталогов:

Патч листинга каталога

Это очень хорошо для начинающих хапи, как я. Как только я последовал этому совету, Джекс перестал предупреждать меня об этой конкретной проблеме.

Небезопасные файлы cookie

Последней дырой в безопасности, которую я хотел проверить, было небезопасное управление сессиями / состоянием. Документы Hapi показывают, как создавать куки, чтобы сохранить состояние сеанса. Они упоминают различные настройки, которые вы можете использовать, и их значения по умолчанию. Чего они не упоминают, так это как вы можете испортить безопасность сеанса, используя неправильные настройки:

 "use strict" const hapi = require("hapi") const blankie = require("blankie") const scooter = require("scooter") const inert = require("inert") // ...create server + connection server.register([inert, scooter, { "register": blankie, "options": { // ..CSP directives here "defaultSrc": "self", } }], err => { server.state("session", { "ttl": 24 * 60 * 60 * 1000, "isSecure": false, "isHttpOnly": false, "path": "/", "encoding": "base64json", }) server.route({ "method": "get", "path": "/", handler: function (request, reply) { let session = request.state.session if (!session) { session = { "returning": true } } session.date = Date.now() return reply("hello world") .state("session", session) }, }) // ...create other routes // ...start server }) 

Это из index.js .

В этот момент я ожидал, что Джекс укажет на оскорбительные строки кода:

 "isSecure": false, "isHttpOnly": false, 

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

Другие вещи, которые Джек защищает от

Я связался с разработчиками Jacks, и они рассказали мне о многих других вещах, которые рекомендует Jacks:

  • Использование адаптивных односторонних функций хеширования для хранения паролей
  • Использование методов, отличных от базовой аутентификации HTTP (через HTTPS)
  • Использование соответствующих факторов работы с PBKDF2 и Scrypt
  • Использование CSPRNG надлежащим образом
  • Включение белого списка CORS
  • Как избежать уязвимости JSONP Rosetta Flash

… И это только некоторые из рекомендаций, характерных для хапи. Джек также может анализировать код MongoDB и Express. Недавно они также добавили поддержку Java, начиная с Spring и Struts .

Вывод

Я определенно стремлюсь продолжать использовать Джекса, поскольку я узнаю больше о Хапи. Это просто та помощь, которая мне нужна, когда я пишу код. И когда я застреваю, я всегда могу использовать функцию обмена мгновенными сообщениями поддержки, чтобы поговорить с одним из их разработчиков. Лучше всего, это бесплатно.