Допустим, вы кодируете функцию, которая получает данные от внешнего API MyAPI
.
Этот внешний API MyAPI
имеет контракт, в котором говорится, что он возвратит a string
или a number
.
Является ли он рекомендовал , чтобы защититься от таких вещей , как null
, undefined
, boolean
и т.д. , даже если это не часть API из MyAPI
? В частности, поскольку у вас нет контроля над этим API, вы не можете получить гарантию с помощью статического анализа типов, поэтому лучше быть в безопасности, чем сожалеть?
Я думаю относительно принципа робастности .
design
api
api-design
web-services
functions
Адам Томпсон
источник
источник
<!doctype html><html><head><title>504 Gateway Timeout</title></head><body>The server was unable to process your request. Make sure you have typed the address correctly. If the problem persists, please try again later.</body></html>
Ответы:
Вы никогда не должны доверять входным данным для вашего программного обеспечения, независимо от источника. Важна не только проверка типов, но также диапазонов ввода и бизнес-логики. Согласно комментарию, это хорошо описано OWASP
Несоблюдение этого требования в лучшем случае оставит вас с мусорными данными, которые вам придется позже очистить, но в худшем случае вы оставите возможность для злонамеренных эксплойтов, если эта восходящая служба каким-то образом будет скомпрометирована (см. Целевой хак). Диапазон проблем между ними включает получение вашего приложения в неисправимом состоянии.
Из комментариев я вижу, что, возможно, мой ответ может быть немного расширен.
«Никогда не доверяйте входным данным», я просто имею в виду, что вы не можете предполагать, что вы всегда будете получать достоверную и заслуживающую доверия информацию из вышестоящих или нисходящих систем, и, следовательно, вы всегда должны дезинфицировать этот вход в меру своих возможностей или отклонить Это.
В комментариях я приведу один аргумент в качестве примера. В то время как да, вам нужно в какой-то степени доверять своей ОС, не исключено, например, отклонение результатов генератора случайных чисел, если вы попросите его ввести число от 1 до 10, и он ответит «bob».
Точно так же в случае OP вы должны убедиться, что ваше приложение принимает только действительные данные от вышестоящей службы. То, что вы делаете, когда это не в порядке, зависит от вас, и оно во многом зависит от фактической бизнес-функции, которую вы пытаетесь выполнить, но как минимум вы регистрируете ее для последующей отладки и в противном случае убедитесь, что ваше приложение не работает в неисправимое или небезопасное состояние.
Несмотря на то, что вы никогда не узнаете все возможные входные данные, которые кто-то / что-то может вам дать, вы, безусловно, можете ограничить то, что допустимо, исходя из бизнес-требований и сделать некоторую форму белого списка ввода на основе этого.
источник
Да , конечно. Но что заставляет вас думать, что ответ может быть другим?
Вы, конечно, не хотите, чтобы ваша программа работала непредсказуемым образом, если API не возвращает то, что говорит контракт, не так ли? Таким образом , по крайней мере , вы должны иметь дело с таким поведением как - то . Минимальная форма обработки ошибок всегда стоит (очень минимум!) Усилий, и нет абсолютно никакого оправдания тому, чтобы не реализовывать что-то подобное.
Тем не менее, сколько усилий вы должны потратить, чтобы разобраться с таким делом, в значительной степени зависит от конкретного случая, и на него можно ответить только в контексте вашей системы. Часто бывает достаточно короткой записи в журнале и постепенного завершения приложения. Иногда вам будет лучше реализовать некоторую детальную обработку исключений, имея дело с различными формами «неправильных» возвращаемых значений, и, возможно, вам придется реализовать некоторую резервную стратегию.
Но это чертовски важно, если вы пишете только какое-то собственное приложение для форматирования электронных таблиц, которое будет использоваться менее чем для 10 человек, и где финансовые последствия аварийного отказа приложения достаточно низки, или если вы создаете новое автономное вождение автомобиля система, в которой сбой приложения может стоить жизни.
Таким образом, нет никакой возможности избежать размышлений о том, что вы делаете , использование вашего здравого смысла всегда обязательно.
источник
Принцип робастности, в частности, «будь либеральным в том, что ты принимаешь», - это очень плохая идея в программном обеспечении. Первоначально он был разработан в контексте аппаратного обеспечения, где физические ограничения делают инженерные допуски очень важными, но в программном обеспечении, когда кто-то посылает вам искаженный или иным образом неправильный ввод, у вас есть два варианта. Вы можете либо отклонить это (предпочтительно с объяснением того, что пошло не так, либо), или вы можете попытаться выяснить, что это должно было означать.
Никогда, никогда, никогда не выбирайте этот второй вариант, если у вас нет ресурсов, эквивалентных поисковой команде Google, для реализации вашего проекта, потому что это то, что нужно, чтобы создать компьютерную программу, которая делает что-то похожее на достойную работу в этой конкретной проблемной области. (И даже в этом случае предложения Google выглядят так, будто они выходят из левого поля примерно половину времени.) Если вы попытаетесь это сделать, то в итоге вы получите огромную головную боль, которую ваша программа будет часто пытаться интерпретировать. неверный ввод как X, когда отправитель действительно имел в виду Y.
Это плохо по двум причинам. Очевидным является то, что в вашей системе плохие данные. Менее очевидным является то, что во многих случаях ни вы, ни отправитель не поймете, что что-то пошло не так, пока гораздо позже в будущем, когда что-то взорвется вам в лицо, и вдруг у вас будет большой, дорогой беспорядок, который нужно исправить, и вы не поймете что пошло не так, потому что заметный эффект так далек от основной причины.
Вот почему существует принцип Fail Fast; избавьте всех вовлеченных в головную боль, применив ее к своим API.
источник
В целом, код должен быть сконструирован так, чтобы поддерживать по крайней мере следующие ограничения, когда это практически возможно:
Когда дан правильный ввод, произведите правильный вывод.
Когда дан верный ввод (который может или не может быть правильным), выведите действительный вывод (аналогично).
Если задан неверный ввод, обработайте его без каких-либо побочных эффектов, кроме тех, которые вызваны нормальным вводом или тех, которые определены как сигнализация ошибки.
Во многих ситуациях программы будут по существу проходить через различные порции данных, не особенно заботясь о том, являются ли они действительными. Если такие блоки содержат недопустимые данные, выходные данные программы, скорее всего, будут содержать недопустимые данные. Если программа специально не предназначена для проверки всех данных и гарантии того, что она не будет выдавать недопустимый вывод, даже если задан неверный ввод , программы, обрабатывающие ее вывод, должны допускать возможность недопустимых данных в ней.
Хотя проверка данных на ранних этапах часто желательна, это не всегда особенно удобно. Среди прочего, если достоверность одного фрагмента данных зависит от содержимого других фрагментов, и если большая часть данных, переданных в некоторой последовательности шагов, будет отфильтрована по пути, ограничивая проверку данными, которые проходят через все этапы могут дать гораздо лучшую производительность, чем пытаться все проверить.
Кроме того, даже если ожидается, что программе будут предоставлены только предварительно проверенные данные, часто полезно, чтобы она в любом случае поддерживала вышеуказанные ограничения, когда это практически осуществимо. Повторение полной проверки на каждом этапе обработки часто приводит к значительному снижению производительности, но ограниченный объем проверки, необходимый для соблюдения вышеуказанных ограничений, может быть намного дешевле.
источник
Давайте сравним два сценария и попытаемся прийти к выводу.
Сценарий 1 Наше приложение предполагает, что внешний API будет работать в соответствии с соглашением.
Сценарий 2 В нашем приложении предполагается, что внешний API может работать некорректно, поэтому добавьте меры предосторожности.
В целом, любой API или программное обеспечение может нарушать соглашения; может быть связано с ошибкой или непредвиденными условиями. Даже у API могут быть проблемы во внутренних системах, приводящие к неожиданным результатам.
Если наша программа написана при условии, что внешний API будет придерживаться соглашений и избегать добавления каких-либо мер предосторожности; кто будет стороной, которая столкнется с проблемами? Это мы, те, кто написал код интеграции.
Например, пустые значения, которые вы выбрали. Скажем, согласно соглашению API ответ должен иметь ненулевые значения; но если она будет внезапно нарушена, наша программа приведет к появлению NPE.
Поэтому я считаю, что будет лучше убедиться, что в вашем приложении есть дополнительный код для решения непредвиденных ситуаций.
источник
Вы должны всегда проверять входящие данные - введенные пользователем или иным образом - поэтому у вас должен быть процесс, который обрабатывает, когда данные, полученные из этого внешнего API, недопустимы.
Вообще говоря, любой шов, где встречаются экстраорганизационные системы, должен требовать аутентификации, авторизации (если не определяется просто аутентификацией) и валидации.
источник
В общем, да, вы всегда должны защищаться от некорректных входных данных, но в зависимости от типа API «охрана» означает разные вещи.
Для внешнего API для сервера вы не хотите случайно создавать команду, которая аварийно завершает работу или ставит под угрозу состояние сервера, поэтому вы должны принять меры против этого.
Для такого API, как, например, класс контейнера (список, вектор и т. Д.), Выдача исключений является идеальным результатом, и в некоторой степени может быть скомпрометировано состояние экземпляра класса (например, отсортированный контейнер, снабженный ошибочным оператором сравнения, не будет быть отсортированным), даже сбой приложения может быть приемлемым, но компрометация состояния приложения - например, запись в произвольные области памяти, не связанные с экземпляром класса - скорее всего, нет.
источник
Несколько иное мнение: я думаю, что может быть приемлемо просто работать с данными, которые вы предоставляете, даже если они нарушают их контракт. Это зависит от использования: это то, что ДОЛЖНО быть для вас строкой, или это то, что вы просто отображаете / не используете и т. Д. В последнем случае просто примите это. У меня есть API, который просто нуждается в 1% данных, передаваемых другим API. Мне было все равно, какие данные в 99%, поэтому я никогда не проверю.
Должен быть баланс между «наличием ошибок, потому что я недостаточно проверяю свои входные данные» и «я отклоняю действительные данные, потому что я слишком строг».
источник
Я всегда должен проверять каждый вход в мою систему. Это означает, что каждый параметр, возвращаемый из API, должен быть проверен, даже если моя программа его не использует. Я также склонен проверять каждый параметр, который я посылаю в API, на правильность. Из этого правила есть только два исключения, см. Ниже.
Причиной тестирования является то, что если по какой-то причине API / ввод неверен, моя программа не может полагаться ни на что. Может быть, моя программа была связана со старой версией API, которая отличается от того, во что я верю? Может быть, моя программа наткнулась на ошибку во внешней программе, которая никогда не случалась раньше. Или, что еще хуже, происходит все время, но никому нет дела! Может быть, хакер вводит в заблуждение внешнюю программу, чтобы она возвратила вещи, которые могут навредить моей программе или системе?
Два исключения для тестирования всего в моем мире:
Производительность после тщательного измерения производительности:
Когда вы не знаете, что делать с ошибкой
Как тщательно проверить входные / возвращаемые значения - важный вопрос. Например, если говорят, что API возвращает строку, я бы проверил, что:
тип данных в действительности является строкой
и эта длина находится между минимальным и максимальным значениями. Всегда проверяйте строки на максимальный размер, который может ожидать моя программа (возврат слишком больших строк - классическая проблема безопасности в сетевых системах).
Некоторые строки должны быть проверены на наличие «недопустимых» символов или содержимого, когда это уместно. Если ваша программа может послать строку, чтобы сказать базу данных позже, это хорошая идея, чтобы проверить наличие атак на базу данных (поиск SQL-инъекций). Эти тесты лучше всего проводить на границах моей системы, где я могу точно определить, откуда взялась атака, и рано провалиться. Выполнение полного теста SQL-инъекции может быть затруднено, когда строки впоследствии объединяются, поэтому этот тест следует выполнить перед вызовом базы данных, но если вы можете обнаружить некоторые проблемы на раннем этапе, это может быть полезно.
Причина тестирования параметров, которые я отправляю в API, заключается в том, чтобы убедиться, что я получаю верный результат. Опять же, выполнение этих тестов перед вызовом API может показаться ненужным, но это требует очень мало производительности и может отлавливать ошибки в моей программе. Следовательно, тесты являются наиболее ценными при разработке системы (но в настоящее время каждая система, кажется, находится в постоянном развитии). В зависимости от параметров тесты могут быть более или менее тщательными, но я склонен обнаруживать, что вы часто можете устанавливать допустимые минимальные и максимальные значения для большинства параметров, которые может создать моя программа. Возможно, строка всегда должна содержать не менее 2 символов и иметь длину не более 2000 символов? Минимум и максимум должны быть внутри того, что позволяет API, поскольку я знаю, что моя программа никогда не будет использовать полный диапазон некоторых параметров.
источник