Чи повинні обмеження безпеки спричиняти повернення сервісу до нуля або викидання виключення? [зачинено]


11

Я трохи не погоджуюся з більш досвідченим розробником з цього питання, і мені цікаво, що про це думають інші; наше середовище - Java, EJB 3, послуги тощо.

Код, який я написав, закликає службу отримати речі та створити речі. Проблема, з якою я зіткнувся, полягала в тому, що я отримав нульові виключення вказівника, які не мали сенсу. Наприклад, коли я прошу службу створити об'єкт, я повертаюсь до нуля; коли я намагаюся шукати об’єкт із відомим дійсним ідентифікатором, я повертаюсь до нуля. Я витратив деякий час, намагаючись з’ясувати, що не так у моєму коді; оскільки я менш досвідчений, я зазвичай припускаю, що я щось зробив не так, але виявляється, що причиною нульового повернення стала безпека. Якщо головний користувач, який користується моєю службою, не мав правильних дозволів для цільової служби, він просто повертає нуль. Більшість інших сервісів тут не дуже добре задокументовані, тому, мабуть, це просто те, що ви повинні знати.

Це досить заплутано як код написання розробника, який взаємодіє зі службою. Для мене було б набагато більше сенсу, якби служба мала виняток, який міг би сказати мені, що користувач не мав належних дозволів завантажувати цю річ або створювати її; Тоді я одразу б зрозумів, чому моя служба працює не так, як очікувалося.

Досвідченіший розробник, який написав сервіс, стверджував, що запит на дані не є умовою помилки, і що винятки слід кидати лише в стані помилки, а не тоді, коли користувач не має доступу до даних. Ці дані часто шукають у графічному інтерфейсі, і для тих користувачів, які не мають потрібних дозволів, ці речі просто "не існують". Отже, коротше: просити не неправильно, отже, не виняток. Отримати методи повернення нульовими, оскільки для тих користувачів ці речі "не існують". Методи створення створюють нульові значення, коли користувачеві не було дозволено створити цю річ.

Це нормальна та / або хороша практика? Я вважаю за краще використовувати винятки, бо мені набагато легше знати, що відбувається. Тому я, наприклад, також вважаю за краще кинути NotFoundException, якщо ви попросили об'єкт з недійсним ідентифікатором, а не повернути null.



@ChrisF: 1) стосується людей, які уникають нульових посилань, яких я не знаю. У багатьох випадках вони доречні, я просто не думаю, що вони в цьому. 2) стосується перевірки параметрів, і чи не стверджуватиме такий результат як те, що кидати виняток? 3) Винятки та коди помилок - це також інша проблема, оскільки вони обидва способи "показати", що пішло не так. Коди помилок підходять, якщо, наприклад, потрібно повідомити систему, яка не підтримує винятки, або якщо ви не хочете, щоб кінцевий користувач бачив щось інше, ніж код.
Свиш

Питання, про яке я питаю тут, полягає в тому, щоб "зробити вигляд, що щось не існує або не сталося" проти "сказати, чому щось не існує або не сталося".
Свиш

3
Я не припускав, що це дублікати - просто, щоб вони мали корисну інформацію для вас.
ChrisF

Правда, вибач за це! Прийняв це як "можливий дублікат" коментар чомусь ... напевно, через недосипання, хе-хе.
Свиш

Відповіді:


19

Винятки слід кидати лише тоді, коли є помилка, а запитання про річ не є помилкою.

Просити щось може не помилка, але відсутність дозволів на те, про що ви просили, - це, безумовно, якась помилка. Винятки - це альтернативний спосіб повідомлення про виняткові умови, який слід використовувати замість спеціальних повернутих значень (таких як null, як ви писали, абсолютно не допомагає, якщо є> 1 можлива причина, чому все може піти не так (навіть якщо є Точно 1 можлива причина зараз, у наступній версії можуть бути 2 можливі причини, тому використання nullяк зворотного значення, що вказує на невдачу, буде малювати себе у кут)) Якщо служба жодним чином не повідомляє, чому вона не зробить те, про що ви просили, то це, безумовно, поганий дизайн.

Чи слід використовувати спеціальне повернене значення (наприклад, негативні цілі числа корисні для функцій, які зазвичай повертають негативне ціле число), виняток, глобальний обробник помилок або реєстратор тощо, - це зрештою деталь реалізації. Вибір залежить від мови, від ситуації, умовності, а також питання смаку. Основний момент полягає в тому, що має бути якийсь прямий спосіб з'ясувати, чому щось не працює. В іншому випадку ваш єдиний варіант - балаканитися з різними варіантами і що б там не з'ясувати, що співвідноситься з поведінкою чорної скриньки, і це марно витрачайте час.

String.substring()кидає, IndexOutOfBoundsExceptionякщо індекс не виходить за межі. Я не можу придумати жодних переваг для повернення nullзамість цього, хоча - по-філософськи - можна стверджувати, що те, Stringщо не містить нічого поза його межами, nullбуло б тоді логічним значенням повернення. Будучи логічно-філософськими та практичними - це, очевидно, дві різні тварини.


Якщо substring () поверне значення для індексів поза межами, він повинен повернути частину рядка між індексами, можливо, порожньою. Це може зберегти тест у деякому коді виклику.
кевін клайн

2
Так, є це нескінченне "порожнє значення" проти нульового-обговорення: чи має підрядок для невизначених індексів бути нульовим чи порожній рядок? Я не знаю, обидва фактично "нічого" (ну, може, нуль - це "більше нічого", ніж порожня рядок?), Але жоден з них не дає кількість інформації, яку робить виняток.
Joonas Pulakaka

@kevincline: Якщо ви не використовуєте рамку, де нульова посилання є ідіоматичним засобом вказівки порожнього рядка, я не бачу жодної основи для substringповернення нульової посилання. ІМХО, має бути дві окремі функції - одна з яких обіцяє повернути потрібну кількість символів або викинути виняток, а одна поверне стільки, скільки зможе. Кожен з методів був би суттєво кращим за інший у деяких контекстах.
supercat

@supercat: Я нічого не сказав про повернення нуля. Я сказав: "поверніться ... частина ... можливо, порожня". Порожній рядок не є нульовим, за винятком Oracle.
кевін клайн

@JoonasPulakka: Я мав би поскакав тебе на мій попередній коментар.
supercat

5

Це зводиться до того, яким є договір. Якщо у вашому договорі сказано, що ви можете запитати щось, що не існує, він повинен сказати, що відбувається (null або null object).

З іншого боку, якщо у вашому контракті сказано, що ви повинні спершу зателефонувати іншим методом ( DoesSomethingExist()), а потім викликати Getметод, тоді ваш контракт може сказати, що ви можете отримати лише ті речі, які існують, і викинути виняток, якщо цього немає. Повідомлення про виняток може сказати щось на зразок "Переконайтесь, щоб зателефонувати DoesSomethingExist()спочатку", що є корисним повідомленням про помилку.


У цьому випадку я б сказав, що не нормально просити те, чого не існує, так як ви, ймовірно, не просили б ідентифікатора, який не існує. Зазвичай ви б спершу ознайомилися зі списком речей, а потім шукаєте певну деталь для отримання більш детальної інформації. Отже, якщо був findAllThingsметод, то я б сказав, що доречно повернути порожній список або підмножину, якщо є деякі або всі речі, які ви не можете бачити. Так само я можу в блозі перелічити лише публікації для редагування, що належать поточному користувачеві. Але якщо той користувач потім спробував налаштувати URL-адресу та відредагувати інший пост ...
Свиш

4

На питання не існує однозначної відповіді. Буде використовувати винятки чи повернути нульове значення, залежить від ситуації.

Замість того, щоб дивитися на це суто з догматичної точки зору, дивіться на інтерфейс як на інтерфейс користувача . Користувацькі інтерфейси повинні бути корисними . Тож незалежно від вашої власної думки щодо «правильного» способу зробити щось, виберіть метод, який є найбільш корисним з точки зору того, хто використовує ваш інтерфейс.

Якщо абонент повинен знати, чому об’єкт не повертається, винятком є ​​виняток. Якщо, однак, загальне поняття "якщо ви не маєте дозволу, воно не існує", нуль є прийнятним.

Зокрема, у вашому випадку я б сказав, що нулі цілком прийнятні для пошуку елемента, якщо спочатку абоненту потрібно ввійти або підключитися до сервера. Саме тоді вам скажуть, що ви робите чи не маєте дозволу. Після того, як ви пройдете повз ворота, розумно, що під час пошуку чогось, у вас немає дозволу бачити (або навіть знати, що воно існує), вам слід отримати нуль.

Якщо, з іншого боку, у вас немає початкового кроку підключення чи входу, виняток має сенс. Якщо абонент знає, що елемент існує, і він не отримує його назад, API не допомагає просто повернути нуль.

Однак для створення елемента це вже інша історія. Імовірно, для цього не може бути багато причин - немає дозволів, поганих параметрів, сервера від пам'яті тощо. Якщо розробнику надано нуль для всіх цих умов, вони не мають змоги визначити правильний хід дій .

Отже, щоб відповісти на запитання, запитайте себе, яке найбільш корисне рішення з точки зору того, хто користується послугою. Можливо, спосіб, яким ви користуєтесь нею, є нетиповим, а для найпоширенішого випадку нуль - правильна відповідь.

Отже, не вступайте в релігійну війну через це, вирішіть, що правильно для цієї проблеми.


Не плануючи надягати бойове спорядження над цим, хе-хе. Було просто цікаво дізнатися, чи я зовсім помиляюся, думаючи, що я думаю чи ні. Я хочу вчитися, але мені не подобається стрибати на щось лише тому, що так говорить одна людина. А особливо не, якщо це суперечить моєму власному досвіду та логіці (як би мало було). У будь-якому разі я повністю згоден, що якщо це був інтерфейс для кінцевих користувачів, то це дійсно могло б мати сенс. Однак, оскільки це боб, до якого, наскільки я знаю, можна отримати доступ лише за кодом, я б сказав, що я як розробник є користувачем.
Свиш

1
І як розробник мені все одно, чому щось не так, незалежно від того, що кінцевий користувач повинен дізнатися про це.
Свиш

Повністю згоден з Брайаном. Навіть розробники - користувачі, тобто споживають якийсь інший код розробника. Рішення кидання або null - це свого роду інтерфейс / gui, який повинен бути корисним для конкретного завдання. Не лише загальним терміном логіки чи філософії.
Незалежний

3

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

Якщо користувач намагається підключити послугу без належного облікового запису, я повинен відповісти чіткою і стислою відповіддю. Відповідь може бути винятком або спеціальним об'єктом, але не нульовим.

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

Крім того, час, який ви витрачаєте на розуміння того, чому ви отримали нуль, є вагомим аргументом. Будь-який фрагмент коду повинен бути легким для розуміння та використання. Мати нульове значення - це не так.


Під своїм останнім реченням ви маєте на увазі "Ви повинні повернути нуль лише тоді, коли мережеве посилання розірвано тощо". або "Ви повинні зупинити повернення нуля, коли мережеве посилання розірвано тощо". ?
Péter Török

@ Péter Török: Я не рекомендую явного використання "return null;". Однак, коли трапляється велика поломка, для деяких служб допустимо повернути нуль.
Амін

Хіба виняток не був би більш підходящим, якщо сталася несподівана критична несправність?
Свиш

2
@Amine: Я б сказав, що це найменш підходящий випадок, коли потрібно повернути null.
Майкл Боргвардт

@Svish: якщо ви зможете виявити велику поломку, звичайно, виняток буде чудовим.
Амін

3

Маючи на увазі хороший дизайн програмного забезпечення, слід подумати про життя свого проекту.
Повертаючись null, як уже було сказано, ви не даєте клієнту ніякої інформації. Подивіться, що сталося з вами, спочатку ви не зрозуміли, де проблема. Більше того, якщо ніякої документації не подано, це безлад.

Кинувши виняток, ви можете сказати, що пішло не так. Ви навіть можете налаштувати відображений текст, щоб він був більш конкретним, якщо хочете.

З іншого боку, повертаючись, nullви змушуєте клієнта досліджувати, що відбувається.

Крім того, ви зрозуміли, що виникла проблема, тому що ви потрапили в інше місце NullPointerException. Тепер уявіть, що ви не зберігаєте повернення цієї функції ... Ви будете змушені оточувати кожен виклик цієї функції if elseблоком ...

З моєї точки зору, повернення null- погана практика.


2

Досвідченіший розробник, який написав сервіс, стверджував, що запит на дані не є умовою помилки, і що винятки слід кидати лише в стані помилки, а не тоді, коли користувач не має доступу до даних.

З моєї точки зору, це не має сенсу.

Запит на дані без дозволу повинен спричинити виняток, оскільки це несподіваний результат - без результату - без належного доступу.

Аналогія : Відповідь на GETавторизацію без авторизації не 200 okмає даних, це насправді 401 Unauthorized.


1

Повернення нуля не велике. Це нічого не говорить вам. Для прикладу, якщо програма намагається щось шукати, і відповідь є нульовою для обох проблем із безпекою, а якщо елемента не існує, то як ви можете сказати різницю між ними?

Змістовна відповідь може дозволити додатку робити логічний вибір щодо того, що робити далі або як вирішити проблеми.


Ви запитуєте, як ви розберете різницю між об'єктом, який там не знаходиться, і вам не вистачає дозволу на його перегляд. Можливо, дизайн системи вимагає того, щоб ви не знали. Я не думаю, що у нас є достатньо інформації, щоб відповісти в цьому конкретному випадку, і немає відповіді, яка працює у всіх випадках. Є цілком справедливі випадки використання, коли, якщо ви не бачите цього, його фактично немає. І є випадки використання, коли, якщо ви не бачите цього, вам слід надати виняток, щоб сказати, чому ви не можете.
Брайан Оуклі

Що ви маєте на увазі під "дизайн системи вимагає, щоб ви не знали"? Що це за дизайн може бути?
Свиш

2
Якщо політика безпеки говорить, що вам заборонено бачити її, то в більшості випадків ви також не можете знати, що вона існує. Це робить повернення "не знайденого" цілком прийнятним.
Blrfl

1

Якщо першопричиною є неаутентифікований користувач, то я віддаю перевагу жорсткій відповіді HTTP 401, можливо, з перенаправленням на сторінку з симпатичними повідомленнями (та повідомлення для когось, кого це хвилює). Причини, пов’язані з авторизацією, є більш індивідуальними; є аргументи для повернення помилок HTTP (403, скажімо) та аргументи для повернення спеціальних добре сформованих кодів / повідомлень у відповіді служби.

Винятки слід використовувати лише у виняткових обставинах і означати, що щось пішло не так. Я не погоджуюся, що їх слід перевантажувати, щоб вони означали "не дозволено". (Те саме стосується нульового значення повернення: я не погоджуюся, що його слід використовувати для значення "не дозволено".)


Ну, у графічному інтерфейсі ви могли це зробити, але що стосується бобів, що реалізують послугу, яка робить речі поза кадром, у вас є лише винятки та спеціальні повернені значення. Я, звичайно, не означаю, що користувач повинен отримати виняток, але виняток можна, наприклад, потрапити у веб-сервіс / сервлет / все, а потім робити те, що підходить. Перенаправлення на куди-небудь, жорстку сторінку 4xx або щось інше.
Свиш

Добре, але ви можете використовувати парадигму на зразок AOP для фіксації цих випадків. Аспект може перевірити наявність привілеїв викликати певну операцію та перенаправляти / дозволяти обробці продовжуватися, як це доречно.
Марк

0

Щоб грати в захисника чортів, я спробую стати на бік повернення нуля.

На мою думку, є лише одна ситуація, коли такий вид реагування майже прийнятний, і це, як у цьому випадку, коли йдеться про безпеку.

Дуже легко випадково роздати деталі вашої системи, про які сторонні люди не повинні знати. Цього слід уникати.

Візьмемо, наприклад, перевірку імені користувача та пароля. Повернення помилки "Ім'я користувача не знайдено" та "Неправильний пароль", оскільки окремі коди помилок очевидно відкриють вас до серйозних проблем безпеки, оскільки хтось може спочатку шукати дійсне ім'я користувача, а потім шукати пароль. Повернення загального "Недійсне ім'я користувача / пароль" було б кращим варіантом.

Таким чином, у цьому конкретному випадку я б сказав, що повернутись майже нормально, nullале я згоден, працювати було б дуже неприємно.


Так, я б не погодився. Відповідна відповідь, на мою думку, буде винятком, але однакова як для не знайденого імені користувача, так і для неправильного пароля. FailedToLogin, InvalidCredentials, що завгодно.
Свиш

@Svish - Але якщо ви намагаєтеся взагалі не натякати на причину невдачі, то повернення null- це найменш корисна відповідь. Майже все інше потенційно може бути використане для виявлення чогось про систему. Причина, на яку скаржився ОП, полягала в тому, що не тільки nullповернення нічого не пояснило, але навіть було не корисно. Це свідома мета ... говорити абсолютно нічого і бути безкорисним. Місія, здійснена на мій погляд.
OldCurmudgeon

Що ж, це може бути так, але я все одно скажу, що робити це погано. Принаймні всередині системи. На краях, де кінцевий користувач бачить речі, то впевнений, я можу погодитися. Але всередині системи ми, розробники, є користувачами, і чому в світі ми б хотіли зробити щось більш заплутаним для себе? Ніби розробити програмне забезпечення вже недостатньо важко ...
Svish

1
І на прикладі входу я б сказав, що погано, щоб користувальницький досвід хоча б не сказав щось про те, чому, здавалося, нічого не сталося, коли вони (думали, що вони) ввели свої облікові дані. Якщо сторінка просто оновлюється і здавалося, що вона просто проігнорувала мою спробу входу, я припускаю, що з системою щось не так, а не те, що я ввів, було неправильним.
Свиш

-2

Я думаю, що return null є недружнім, коли клієнт викликає цей метод і повертає null, клієнт не знає, що сталося і чому він повернув null. Таким чином, нам слід кинути виконання, яке має сенс, і надати документацію для опису цього виконання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.