Обновить
7
0
Lazarev Boris@robzarel

Senior frontend engineer

Отправить сообщение

Такой бекенд можно использовать только на чтение? Если нужно записать, скажем поля форм, то уже не вариант ?

ага. Это просто файлы лежащие на гитхабе в определённой ветке.

По поводу безопасности.
Localstorage более уязвим к потере данных, так как при проведении успешной XSS атаки - данные будут легко угнаны. Это можно прочитать в любом месте, где сравниваются куки и локальное хранилище в разрезе хранения токена.
Но штука в том, что даже если мы используем httpOnly cookie, с атрибутами sameSite и прочими вещами - всё равно при успешной XSS атаке данные токена будут не в безопасности.

Есть потрясающая статья с Highload 2017 про уязвимость к CSRF атакам - https://habr.com/ru/companies/oleg-bunin/articles/412855/. Она всё ещё актуальна. Там в самом низу отличная табличка и наглядно видно, что если словили XSS то нас уже ничего не спасёт ))

Т.е. не важно какой способ хранения токена выбрали - если словили xss, то имеем большой риск потери токена.


В реальности, где атакеры понимают способы обхода угона токенов из кук через обход csrf защиты, основным и наиболее надёжным способом защиты токенов является защита от XSS атак и ограничение времени жизни токена. И кажется ещё двухфакторная аутентификация )))

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

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

thx)

PS:

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

PPS: для приложений, которые используют карточные данные есть целый набор рекомендаций по безопасности, который называется PCI DSS

спасибо за статью, очень интересный контент)

Недавно читал статью про выступление на хайлоад 2017 (достаточно старую, но кажется всё ещё актуальную статью), https://habr.com/ru/companies/oleg-bunin/articles/412855/, в которой описываются варианты обхода csrf защиты.

Судя по статье с хайлоада - если есть xss уязвимость, то использование cookie (равно как и localstorage), для хранения токенов, становится небезопасным (куки можно угнать обойдя csrf защиту). И вроде получается, что основная защита от угона токена это как раз защита от внедрения чужого кода в своё приложение - csp/cors. т.е. будто бы не важно какой способ хранения токена выбрали - если словили xss, то имеем большой риск потери токена (пока срок его хранения не истёк).
Если будет время/желание - было бы интересно услышать ваше мнение, актуальны ли данные проблемы с обходом csrf (и как следствие доступа к кукам) и сталкивались ли вы на практике с тем, что несмотря на защитные меры по csrf атакам, они не срабатывали

Заранее благодарю)

Для такого сценария достаточно будет менять контент внутри модалки по каким-то условиям. Т.е. не модалка пораждает другую модалку, а просто идёт смена контента внутри модального окна.

Например можно попробовать прикинуть на примере пошаговой формы (скажем 3 шага), с сабмитом на последнем шаге.
Контент внутри modal под условным рендерингом будет находится. Каждый "шаг" отображается по набору условий (допустим стейт в компоненте с номером шага). Далее схема будет следующая:
- заполнили 1й шаг, нажали кнопку "дальше"
- по клику на кнопку стейт поменялся ->
- затем сработали условия для скрытия 1го шага и показа 2го шага
- заполнили 2й шаг -> клик-> стейт -> смена условий и показ 3го шага
- сделали сабмит, перестали рендерить модалку

благодарю) рад видеть, что статьи приносят кому-то пользу)

выбрать с клавиатуры теперь можно, апдейт проведён) поможет секция "Поддержка ввода с клавиатуры"

спасибо за замечание, хороший пойнт.
Дополнил статью секцией "Поддержка ввода с клавиатуры"

Ссылки на codesandbox так же положил в статью

всю работу делает родительский элемент,

вы правы - в данной реализации пагинатор это стейтлесс компонент. Его задача просто предоставлять контролы и уметь в 2 режима отображения (с навигацией и без). Контейнер же содержит в себе состояние и на основе этого состояния ходит за данными (через useEffect). Мне кажется, что убирать логику работы с данными в сам пагинатор - это означает, что мы сможем переиспользовать компонент только в местах с такой же логикой подтягивания данных. В случае же с вынесением состояния в контейнер пагинатор становится переиспользуемым в большем количестве кейсов.
Плюс подобная реализация это весьма удобно, так как очень часто, помимо простой пагинации ещё на страницах поиска применяются фильтры. И данная реализация, когда состояние и логика подтягивания данных, находится в контейнере, позволяет легко покрывать и эти кейсы. Например:


  const [search, setSearchValue] = useState<string | null>(null);
  ...
  useEffect(() => {
    const fetchData = async () => {
      ...
      try {
        const response = await api.get.data({ page, search });
        ...
      } catch (err) {...} finally {...}
    };

    fetchData();
  }, [search, page]);

уметь отключать кнопки переключения в граничных условиях

умеет же))

в компоненте проставляются атрибуты disabled для button элементов (кнопок), что и делает их не интерактивными: https://www.w3schools.com/tags/att_button_disabled.asp. В дополнение в css проставляется cursor: not-allowed; при hover в кейсе наличия disabled атрибута, что помогает сориентироваться пользователю)
Сами же граничные условия задаются в контейнере и передаются через props - disable: { left: boolean; right: boolean; };

просто вывод текущей страницы слэш количество страниц?

да, просто вывод текущего положения.
Если хочется, можно с небольшими доработками сделать любую логику:
- любое кол-во доступных страниц выводить (показывать сколько-то предыдущих/последующих, выводить общее и т.д и т.п
- вообще убрать навигацию

Мне кажется вопрос того, что тёмный/светлый режим, выставленный на пользовательской машине, синхронизирован или не синхронизирован с темизацией конкретного сайта - это вопрос продуктовой экспертизы.
Если говорить про реализацию такого синка, то кажется достаточно usEffect подправить и ходить не в localsorage за типом включённой темы, а в настройки.

Хотя лично мне субъективно кажется, что пользователи любят держать контроль в своих руках постоянно и если предоставить им явный контрол (зависящий только от их действий) то им будет удобнее/лучше)

Про терминологию - theme это как раз отражает выбранный набор цветов, реализующих определённую палитру для всех элементов сайта. Если вводится синк с системным режимом, то компоновка может быть какой угодно - не только "малиновая в двух вариантах для тёмного/светлого режима", но и "малиновая тема для светлого режима, и зелёная тема для тёмного режима". Комбинации могут быть любыми. Theme это более атомарный термин, нежели theme-mode.

почему не обязать сервер передавать защищенную куку, которую браузер и так будет цеплять к fetch запросам, а сервер валидировать

да можно конечно) и для множества сценариев это будет чуть более безопасно)

но статья не про сравнение куки vs localstorage, а про то, как можно юзать localstorage если такой выбор был сделан)

Вообще для ssr адаптации не делал.
Кажется надо будет слегка доработать WithAuth для этих кейсов.


WithAuth попробует тебя авторизовать и если не получится - перенаправит на страницу логина. Если токена не найдёт - отправит апи запрос. Во время ssr этот запрос должен пройти нормально и токен появится и children зарендерятся - т.е. ssr случится. Но токен этот не сохранится, так как нет локалстораджа.

Надо кажется спустить вниз (во фронт) этот токен, если он был подтянут вовремя ssr и там уже на клиенте его сохранить в сторадж и вроде все кейсы покрыты будут.

Хорошее примечание, спасибо)

хм. Судя по всему речь идёт об очень старых версиях firefox - с версии 3.5 (от 2009) уже гарантируется доступность глобал объекта
https://caniuse.com/?search=localStorage
https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
Кажется этим можно пренебречь, так как количество пользователей браузеров 2009 года в 2023 стремится к нулю)

А сам метод хранилища нам отдаст null если не найдёт там значения https://developer.mozilla.org/en-US/docs/Web/API/Storage/getItem

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

А дальше ответ на вопрос от 2 факторов зависит:
1) юзаешь ли ты хук useTextFormField или пишешь свой
2) как ты напишешь правила проверки email.

если например ты юзаешь useTextFormField и положишь туда 2 валидатора:
- required (значит просто не пустое поле должно быть)
- email (значит, что строка мейла должна быть по паттерну какому-то)

Если предположить, что email валидатор будет возвращать ошибку на любое значение переданной строки, которое не соответствует паттерну проверки email (например заданному через регулярку). - То да - при вводе "my" в поле, у тебя будет в поле hasError проставлятся true, а в поле error будет лежать текст ошибки.

Потом эту шткуку прикручиваешь к view в рендере. Эта ошибка (по хорошему) сразу должна подсказывать пользователю какие данные от него ждут и в каком виде.

PS:
Если тебе нужно изменить логику как-то - можно спокойно написать свой кастомный хук, который переопределит handleChange и там уже например не вызывать валидацию если не нужно)

чекни код handleChange внутри useTextFormField - его можно скорректировать как тебе нужно)

>А вы для всех полей запускаете все этапы валидации при каждом изменении?
- Нет, только для поля с которым взаимодействует пользователь )

Взаимодействуем с полем - для него и тригерим запуск валидации. Триггерим запуск валидаторов для конкретного поля на события блюра и изменения (для этого есть handleBlur handleChange, которые генерит кастомный хук (см тайпинги DefaultField))

Общий прогон всех валидаторов на всю форму целесообразно делать по событию сабмита (handleFormSubmit внутри useForm).

Триггеры:

  • Для поля

    • при "касании" (blur)

    • по мере ввода данных (change)

    • по кастомному триггеру

  • Для формы

    • при отправке формы (submit)

    • по кастомному триггеру


Если честно, про стандарт livr слышу впервые. На первый взгляд выглядит как что-то хорошее) почитаю спеку на досуге - спасибо)

"ввёл пароль, что-то узнал" - такого кейса как раз не возникает, так как мы саппортим пользователя по мере ввода данных. Т.е. на каждый onchange у нас срабатывает вся валидация, которая закреплена за полем. И таким образом мы не ждём, пока человек введёт весь пароль в миллион символов и узнает, что есть 10 правил, которые он нарушил, а помогаем ему "налету".

Но для того, чтобы было совсем хорошо, нам надо либо впилить тоненькую подсказку серым текстом под полем (о чём в статье упоминал всколзь), либо лучше использовать тултипы для такого функционала (например иконка знака вопроса и вспылвающая подсказка, где пользователь (если хочет) может увидеть все правила ввода сразу).

Информация

В рейтинге
Не участвует
Дата рождения
Зарегистрирован
Активность

Специализация

Фронтенд разработчик
Ведущий
JavaScript
TypeScript
React
Redux
Webpack
Кроссбраузерная верстка
Node.js
Express
Веб-разработка
Адаптивная верстка