Skip to content

Instantly share code, notes, and snippets.

@monochromer
Forked from zmts/tokens.md
Created November 28, 2019 18:42
Show Gist options
  • Save monochromer/7e1b54e8bc84d4286398aca1922cdd96 to your computer and use it in GitHub Desktop.
Save monochromer/7e1b54e8bc84d4286398aca1922cdd96 to your computer and use it in GitHub Desktop.

Revisions

  1. @zmts zmts revised this gist Nov 9, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -100,7 +100,7 @@ CREATE TABLE sessions (
    1. Хакер воспользовался __access token'ом__
    2. Закончилось время жизни __access token'на__
    3. __Клиент хакера__ отправляет __refresh token__ и __fingerprint__ (если знает что он нужен)
    4. Сервер смотрит __fingerprint__ хакера
    4. Сервер смотрит __fingerprint__ хакера (если он есть в запросе)
    5. Сервер не находит __fingerprint__ хакера в сессии и удаляет ее из БД
    6. Сервер логирует попытку несанкционированного обновления токенов
    7. Сервер перенаправляет хакера на станицу логина. Хакер идет лесом
  2. @zmts zmts revised this gist Nov 4, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -116,7 +116,7 @@ __Front-end:__
    __Back-end:__
    - https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth

    ### Чтиво:
    ### Info:
    - Заметка базируется на: https://habrahabr.ru/company/Voximplant/blog/323160/
    - https://tools.ietf.org/html/rfc6749
    - https://www.digitalocean.com/community/tutorials/oauth-2-ru
  3. @zmts zmts revised this gist Nov 4, 2019. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -132,7 +132,6 @@ __Back-end:__
    - https://egghead.io/courses/json-web-token-jwt-authentication-with-node-js
    - https://www.digitalocean.com/community/tutorials/oauth-2-ru
    - https://github.com/shieldfy/API-Security-Checklist/blob/master/README-ru.md

    - https://www.youtube.com/watch?v=Ngh3KZcGNaU
    - https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
    - https://www.youtube.com/watch?v=R0-eoLp871s
  4. @zmts zmts revised this gist Nov 4, 2019. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -129,12 +129,15 @@ __Back-end:__
    - https://habr.com/post/340146/
    - https://habr.com/company/mailru/blog/115163/
    - https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
    - https://www.youtube.com/watch?v=Ngh3KZcGNaU
    - https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
    - https://egghead.io/courses/json-web-token-jwt-authentication-with-node-js
    - https://www.digitalocean.com/community/tutorials/oauth-2-ru
    - https://github.com/shieldfy/API-Security-Checklist/blob/master/README-ru.md

    - https://www.youtube.com/watch?v=Ngh3KZcGNaU
    - https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
    - https://www.youtube.com/watch?v=R0-eoLp871s
    - https://www.youtube.com/watch?v=u9hn3s2kUrg

    ### And why JWT is bad
    - http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
    - http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/
  5. @zmts zmts revised this gist Nov 4, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -53,7 +53,7 @@ __Роль рефреш токенов и зачем их хранить в БД

    Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (да берем `expires_in` прямо из JWT в клиентском приложении) и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__. Для большей уверенности можем обновлять токены на несколько секунд раньше.

    Что такое __fingerprint__ ? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это хеш сгенерированный js'ом на база неких уникальных параметров/компонентов браузера. Преимущество __fingerprint'a__ в том что он нигде персистентно не хранится и генерируется только в случае надобности(во время логина и рефреша)
    Что такое __fingerprint__ ? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это хеш сгенерированный js'ом на базе неких уникальных параметров/компонентов браузера. Преимущество __fingerprint'a__ в том что он нигде персистентно не хранится и генерируется только в момент логина и рефреша.
    - Библиотека для хеширования: https://github.com/Valve/fingerprintjs2
    - Более подробно: https://player.vimeo.com/video/151208427
    - Пример ф-ции получения такого хеша: https://gist.github.com/zmts/b26ba9a61aa0b93126fc6979e7338ca3
  6. @zmts zmts revised this gist Oct 23, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # Про токены, JSON Web Tokens (JWT), аутентификацию и авторизацию. Token-Based Authentication

    `Last update: 21.10.2019`
    `Last major update: 21.10.2019`

    ## Основы:
    __Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор)__ - это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных.
  7. @zmts zmts revised this gist Oct 23, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -65,7 +65,7 @@ CREATE TABLE sessions (
    "id" SERIAL PRIMARY KEY,
    "userId" uuid REFERENCES users(id) ON DELETE CASCADE,
    "refreshToken" uuid NOT NULL,
    "ua" character varying(200) NOT NULL,
    "ua" character varying(200) NOT NULL, /* user-agent */
    "fingerprint" character varying(200) NOT NULL,
    "ip" character varying(15) NOT NULL,
    "expiresIn" bigint NOT NULL,
  8. @zmts zmts revised this gist Oct 21, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -53,7 +53,7 @@ __Роль рефреш токенов и зачем их хранить в БД

    Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (да берем `expires_in` прямо из JWT в клиентском приложении) и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__. Для большей уверенности можем обновлять токены на несколько секунд раньше.

    Что такое __fingerprint__ ? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это хеш сгенерированный js'ом на база неких уникальных параметров/компонентов браузера. Преимущество __fingerprint'a__ в том что он нигде персистентно не хранится и генеригуется только в случае надобности(во время логина и рефреша)
    Что такое __fingerprint__ ? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это хеш сгенерированный js'ом на база неких уникальных параметров/компонентов браузера. Преимущество __fingerprint'a__ в том что он нигде персистентно не хранится и генерируется только в случае надобности(во время логина и рефреша)
    - Библиотека для хеширования: https://github.com/Valve/fingerprintjs2
    - Более подробно: https://player.vimeo.com/video/151208427
    - Пример ф-ции получения такого хеша: https://gist.github.com/zmts/b26ba9a61aa0b93126fc6979e7338ca3
  9. @zmts zmts revised this gist Oct 21, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -96,7 +96,7 @@ CREATE TABLE sessions (
    Вопрос зачем __refresh token'y__ срок жизни, если он обновляется каждый раз при обновлении __access token'a__ ? Это сделано на случай если юзер будет в офлайне более 60 дней, тогда прийдется заново вбить логин/пароль.


    ## В случае кражи токенов (когда юзер логинится с нескольких устройства):
    ## В случае кражи токенов:
    1. Хакер воспользовался __access token'ом__
    2. Закончилось время жизни __access token'на__
    3. __Клиент хакера__ отправляет __refresh token__ и __fingerprint__ (если знает что он нужен)
  10. @zmts zmts revised this gist Oct 21, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -82,11 +82,11 @@ CREATE TABLE sessions (
    5.1 Не истекло ли время жизни
    5.1 На соответствие старого __fingerprint'a__ полученного из текущей сессии с новым полученным из тела запроса
    6. В случае негативного результата бросает ошибку `TOKEN_EXPIRED`/`INVALID_SESSION`
    7. В случае успеха создает новую сессию и записывает ее в БД *
    7. В случае успеха создает новую сессию и записывает ее в БД
    8. Создает новый __access token__
    9. Отправляет клиенту `{ accessToken, refreshToken }`

    * Стоит заметить что процесс добавления сессии в таблицу должен имеет свои меры безопасности. При добавлении стоит проверять сколько сессий всего есть у юзера и если их слишком много или юзер конектится одновременно из нескольких подсетей, стоит предпринять меры. Имплементируя данную проверку я проверяю только что бы юзер имел максимум до 5 одновременных сессий максимум, и на 6'ой удаляю все остальные сессии кроме текущей(6'ой). Все остальные проверки на ваше усмотрение в зависимости от задачи.
    Стоит заметить что процесс добавления сессии в таблицу должен имеет свои меры безопасности. При добавлении стоит проверять сколько сессий всего есть у юзера и если их слишком много или юзер конектится одновременно из нескольких подсетей, стоит предпринять меры. Имплементируя данную проверку я проверяю только что бы юзер имел максимум до 5 одновременных сессий максимум, и на 6'ой удаляю все остальные сессии кроме текущей(6'ой). Все остальные проверки на ваше усмотрение в зависимости от задачи.

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

  11. @zmts zmts revised this gist Oct 21, 2019. 1 changed file with 52 additions and 73 deletions.
    125 changes: 52 additions & 73 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,8 @@
    # Про токены, JSON Web Tokens (JWT), аутентификацию и авторизацию. Token-Based Authentication

    ## Основы:
    `Last update: 21.10.2019`

    ## Основы:
    __Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор)__ - это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных.

    __Авторизация(authorization — разрешение, уполномочивание)__ - это проверка прав пользователя на доступ к определенным ресурсам.
    @@ -31,100 +32,78 @@ __Токены__ предоставляют собой средство __авт

    __access token__ - используется для __авторизации запросов__ и хранения дополнительной информации о пользователе (аля __user_id__, __user_role__ или еще что либо, эту информацию также называет __payload__). Сам токен храним не в localStorage как это обычно делают, а __в памяти клиентского приложения.__

    __refresh token__ - выдается сервером по результам успешной аутентификации и используется для получения нового __access token'a__ и обновления __refresh token'a__
    __refresh token__ - выдается сервером по результам успешной аутентификации и используется для получения новой пары __access/refresh__ токенов. Храним в любом персистентном хранилище.

    Каждый токен имеет свой срок жизни, например __access__: 30мин, __refresh__: 60дней
    Каждый токен имеет свой срок жизни, например __access__: 30 мин, __refresh__: 60 дней

    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них какую либо `sensitive data` (passwords, payment credentials, etc...)__

    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут бесконтрольно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).

    ## Схема создания/использования токенов (api/auth/login):
    1. Пользователь логинится в приложении, передавая логин/пароль на сервер
    2. Сервер проверят подлинность логина/пароля, в случае удачи генерирует и отправляет клиенту два токена(__access, refresh__) и время смерти __access token'а__ (`expires_in` поле, в __unix timestamp__). Также в __payload__ __refresh token'a__ добавляется __user_id__
    ## Логин, создание сессии/токенов (api/auth/login):
    1. Пользователь логинится в приложении, передавая логин/пароль и __fingerprint__ браузера (ну или некий иной уникальный индентификатор устройства если это не браузер)
    2. Сервер проверят подлинность логина/пароля,
    3. В случае удачи создает и записывает сессию в БД `{ userId: uuid, refreshToken: uuid, expiresIn: int, fingerprint: string, ... }`
    4. Отправляет клиенту два токена __access и refresh token uuid__ (взятый из выше созданной сессии)
    ```
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "9f34dd3a-ff8d-43aa-b286-9f22555319f6",
    "expires_in": 1502305985425
    "refreshToken": "9f34dd3a-ff8d-43aa-b286-9f22555319f6"
    ```
    3. Клиент сохраняет токены и время смерти __access token'а__, используя __access token__ для последующей авторизации запросов
    4. Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (из `expires_in`)и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__
    5. Клиент сохраняет токены(__access__ в памяти приложения, __refresh__ персистентно), используя __access token__ для последующей авторизации запросов.

    ## Схема рефреша токенов (одна сессия/устройство, api/auth/refresh-tokens):
    1. Клиент(фронтенд) проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера и достает из него __refresh token__
    4. Сравнивает __refresh token__ клиента с __refresh token'ом__ найденным в БД
    5. Проверяет валидность и срок действия __refresh token'а__
    6. В случае успеха сервер:
    1. Создает и перезаписывает __refresh token__ в БД
    2. Создает новый __access token__
    3. Отправляет оба токена и новый `expires_in` __access token'а__ клиенту
    7. Клиент повторяет запрос к API c новым __access token'ом__

    __С такой схемой юзер сможет быть залогинен только на одном устройстве.__ Тоесть в любом случае при смене устройства ему придется логинится заново.

    __Если рассматривать возможность аутентификации на более чем одном девайсе/браузере(мульти сессии):__ необходимо хранить весь список валидных рефреш токенов юзера. Если юзер авторизовался более чем на ±10ти устройствах(что есть весьма подозрительно), автоматически инвалидоровать все рефреш токены кроме текущего и отправлять email с security уведомлением. Как вариант список токенов можно хранить в jsonb(если используется PostgreSQL).

    ## Схема рефреша токенов (мульти сессии/несколько устройств, api/auth/refresh-tokens):
    Для использования возможности аутентификации на более чем одном девайсе необходимо хранить все рефреш токены по каждому юзеру.
    Я этот список храню в записи юзера в виде JSONB. Во время кажого процесса логина необходимо добавлять IP/Fingerprint пользователя-владельца логина/пароля в белый список.
    Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (да берем `expires_in` прямо из JWT в клиентском приложении) и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__. Для большей уверенности можем обновлять токены на несколько секунд раньше.

    Что такое __fingerprint__ ? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это хеш сгенерированный js'ом на база неких уникальных параметров/компонентов браузера. Преимущество __fingerprint'a__ в том что он нигде персистентно не хранится и генеригуется только в случае надобности(во время логина и рефреша)
    - Библиотека для хеширования: https://github.com/Valve/fingerprintjs2
    - Более подробно: https://player.vimeo.com/video/151208427
    - Пример ф-ции получения такого хеша: https://gist.github.com/zmts/b26ba9a61aa0b93126fc6979e7338ca3

    ## Рефреш токенов (api/auth/refresh-tokens):
    Для использования возможности аутентификации на более чем одном девайсе необходимо хранить все рефреш токены по каждому юзеру. Я храню это список в PostgreSQL таблице. В процессе каждого логина создается запись с IP/Fingerprint и другой мета информацией то есть сессия.
    ```
    -------------------------------------------------------------------------------------------------
    | id | username | refreshTokensMap | whitelistIP
    -------------------------------------------------------------------------------------------------
    | 1 | alex | { refreshTokenTimestamp1: 'refreshTokenBody1', refreshTokenTimestamp2: 'refreshTokenBody2'} | ['111.111.111.111', '222.222.222.222']
    -------------------------------------------------------------------------------------------------
    CREATE TABLE sessions (
    "id" SERIAL PRIMARY KEY,
    "userId" uuid REFERENCES users(id) ON DELETE CASCADE,
    "refreshToken" uuid NOT NULL,
    "ua" character varying(200) NOT NULL,
    "fingerprint" character varying(200) NOT NULL,
    "ip" character varying(15) NOT NULL,
    "expiresIn" bigint NOT NULL,
    "createdAt" timestamp with time zone NOT NULL DEFAULT now(),
    "updatedAt" timestamp with time zone NOT NULL DEFAULT now()
    );
    ```
    1. Клиент(фронтенд) проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера
    1. Проверяет IP юзера запрашиваемого обновление токенов с белым списком, если все успешно достает __refresh token__ из записи в `refreshTokensMap`
    2. Если IP юзера отсутствует в белом списке, редиректит на страницу логина
    4. Сравнивает __refresh token__ клиента с __refresh token'ом__ найденным в `refreshTokensMap`
    5. Проверяет валидность и срок действия __refresh token'а__ (но если токен не валиден удаляет его сразу)
    6. В случае успеха сервер:
    1. __Удаляет старый рефреш токен__
    2. Проверяет количество уже существующих решфреш токенов.
    3. Если их больше 10, удаляет все токены, создает новый и запиывает его в БД.
    4. Если их меньше 10 просто создает и записывает новый в БД.
    5. Создает новый __access token__
    6. Отправляет оба токена и новый `expires_in` __access token'а__ клиенту
    7. Клиент повторяет запрос к API c новым __access token'ом__

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

    Как дополнительная мера можно вообще заблокировать данного юзера при попытке залогинится более чем на 10ти устройствах. С возможностью разблокировки только через email. Но в этом случае нам необходимо будет во время каждого рефреша проверять список токенов на наличие мертвых(не валидных).

    ## Ключевой момент:
    В момент рефреша то есть обновления __access token'a__ обновляются __ОБА__ токена. Но как же __refresh token__ может сам себя обновить, он ведь создается только после успешной аунтефикации ? __refresh token__ в момент рефреша сравнивает себя с тем __refresh token'ом__ который лежит в БД и вслучае успеха, а также если у него не истек срок, система рефрешит токены. __Внимание__ при обновлении __refresh token'a__ продливается также и его срок жизни.
    1. Клиент(фронтенд) проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` `{ refreshToken: uuid, fingerprint: string }`
    3. Сервер получает запись сессии по UUID'у рефреш токена
    4. Cохраняет текущую сессию в переменную и удаляет ее из таблицы
    5. Проверяет текущую сессию:
    5.1 Не истекло ли время жизни
    5.1 На соответствие старого __fingerprint'a__ полученного из текущей сессии с новым полученным из тела запроса
    6. В случае негативного результата бросает ошибку `TOKEN_EXPIRED`/`INVALID_SESSION`
    7. В случае успеха создает новую сессию и записывает ее в БД *
    8. Создает новый __access token__
    9. Отправляет клиенту `{ accessToken, refreshToken }`

    Возникает вопрос зачем __refresh token'y__ срок жизни, если он обновляется каждый раз при обновлении __access token'a__ ? Это сделано на случай если юзер будет в офлайне более 60 дней, тогда прийдется заново вбить логин/пароль.
    * Стоит заметить что процесс добавления сессии в таблицу должен имеет свои меры безопасности. При добавлении стоит проверять сколько сессий всего есть у юзера и если их слишком много или юзер конектится одновременно из нескольких подсетей, стоит предпринять меры. Имплементируя данную проверку я проверяю только что бы юзер имел максимум до 5 одновременных сессий максимум, и на 6'ой удаляю все остальные сессии кроме текущей(6'ой). Все остальные проверки на ваше усмотрение в зависимости от задачи.

    ## В случае кражи токенов (когда когда юзер логинится только с одного устройства: одна сессия):
    Таким образом если юзер залогинился на пяти устройствах, рефреш токены будут постоянно обновляться и все счастливы. Но если с аккаунтом юзера начнут производить подозрительные действия(попытаются залогинится более чем на 5'ти устройствах) система сбросит все сессии(рефреш токены) кроме последней.

    1. Хакер воспользовался __access token'ом__
    2. Закончилось время жизни __access token'на__
    3. __Клиент хакера__ отправляет __refresh token__
    4. Хакер получает новую пару токенов
    5. На сервере создается новая пара токенов(__"от хакера"__)
    5. Юзер пробует зайти на сервер >> обнаруживается что токены невалидны
    6. Сервер перенаправляет юзера на форму аутентификации
    7. Юзер вводит логин/пароль
    8. Создается новая пара токенов >> пара токенов __"от хакера"__ становится не валидна
    ## Ключевой момент:
    В момент рефреша то есть обновления __access token'a__ обновляются __ОБА__ токена. Но как же __refresh token__ может сам себя обновить, он ведь создается только после успешной аунтефикации ? __refresh token__ в момент рефреша сравнивает себя с тем __refresh token'ом__ который лежит в БД и вслучае успеха, а также если у него не истек срок, система рефрешит токены.

    __Проблема:__ Поскольку __refresh token__ продлевает срок своей жизни каждый раз при рефреше токенов >> хакер пользуется токенами до тех пор пока юзер не залогинится.
    Вопрос зачем __refresh token'y__ срок жизни, если он обновляется каждый раз при обновлении __access token'a__ ? Это сделано на случай если юзер будет в офлайне более 60 дней, тогда прийдется заново вбить логин/пароль.

    ## В случае кражи токенов (когда когда юзер логинится с нескольких устройства: мульти сессии):
    Во время кажого процесса логина необходимо добавлять IP/Fingerprint пользователя-владельца логина/пароля в белый список. Таким образом при каждой попытке зайти с новой точки доступа придется перелогиниватся.

    ## В случае кражи токенов (когда юзер логинится с нескольких устройства):
    1. Хакер воспользовался __access token'ом__
    2. Закончилось время жизни __access token'на__
    3. __Клиент хакера__ отправляет __refresh token__
    4. Сервер смотрит IP адрес хакера
    5. Сервер не находит IP адрес хакера в белом списке и удаляет __refresh token__ из БД (можно так же забанить этот IP)
    3. __Клиент хакера__ отправляет __refresh token__ и __fingerprint__ (если знает что он нужен)
    4. Сервер смотрит __fingerprint__ хакера
    5. Сервер не находит __fingerprint__ хакера в сессии и удаляет ее из БД
    6. Сервер логирует попытку несанкционированного обновления токенов
    7. Сервер перенапрявляет харека на станицу логина. Хакер идет лесом
    7. Сервер перенаправляет хакера на станицу логина. Хакер идет лесом
    8. Юзер пробует зайти на сервер >> обнаруживается что __refresh token__ отсутствует
    9. Сервер перенаправляет юзера на форму аутентификации
    10. Юзер вводит логин/пароль
  12. @zmts zmts revised this gist Oct 19, 2019. 1 changed file with 5 additions and 2 deletions.
    7 changes: 5 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -130,9 +130,12 @@ __Проблема:__ Поскольку __refresh token__ продлевает
    10. Юзер вводит логин/пароль

    ### Пример имплементации:
    __Front-end:__ https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/http.init.js
    __Front-end:__
    - https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/http.init.js
    - https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/auth.service.js

    __Back-end:__ https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth
    __Back-end:__
    - https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth

    ### Чтиво:
    - Заметка базируется на: https://habrahabr.ru/company/Voximplant/blog/323160/
  13. @zmts zmts revised this gist Oct 18, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -43,8 +43,8 @@ __Роль рефреш токенов и зачем их хранить в БД
    1. Пользователь логинится в приложении, передавая логин/пароль на сервер
    2. Сервер проверят подлинность логина/пароля, в случае удачи генерирует и отправляет клиенту два токена(__access, refresh__) и время смерти __access token'а__ (`expires_in` поле, в __unix timestamp__). Также в __payload__ __refresh token'a__ добавляется __user_id__
    ```
    "accessToken": "...",
    "refreshToken": "...",
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "9f34dd3a-ff8d-43aa-b286-9f22555319f6",
    "expires_in": 1502305985425
    ```
    3. Клиент сохраняет токены и время смерти __access token'а__, используя __access token__ для последующей авторизации запросов
  14. @zmts zmts revised this gist Oct 18, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -29,13 +29,13 @@ __Токены__ предоставляют собой средство __авт

    При попытке хакером подменить данные в __header'ре__ или __payload'е__, токен cтанет не валидным, поскольку сигнатура не будет соответствовать изначальным значениям. А возможность сгенерировать новую сигнатуру у хакера отсутствует, поскольку секретный ключ для зашифровки лежит на сервере.

    __access token__ - используется для __авторизации запросов__ и хранения дополнительной информации о пользователе (аля __user_id__, __user_role__ или еще что либо, эту информацию также называет __payload__)
    __access token__ - используется для __авторизации запросов__ и хранения дополнительной информации о пользователе (аля __user_id__, __user_role__ или еще что либо, эту информацию также называет __payload__). Сам токен храним не в localStorage как это обычно делают, а __в памяти клиентского приложения.__

    __refresh token__ - выдается сервером по результам успешной аутентификации и используется для получения нового __access token'a__ и обновления __refresh token'a__

    Каждый токен имеет свой срок жизни, например __access__: 30мин, __refresh__: 60дней

    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли.__
    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них какую либо `sensitive data` (passwords, payment credentials, etc...)__

    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут бесконтрольно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).

  15. @zmts zmts revised this gist Aug 7, 2019. 1 changed file with 9 additions and 2 deletions.
    11 changes: 9 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -151,5 +151,12 @@ __Back-end:__ https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth
    - https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
    - https://egghead.io/courses/json-web-token-jwt-authentication-with-node-js
    - https://www.digitalocean.com/community/tutorials/oauth-2-ru


    - https://github.com/shieldfy/API-Security-Checklist/blob/master/README-ru.md

    ### And why JWT is bad
    - http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
    - http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/
    - https://medium.com/@cjainn/anatomy-of-a-jwt-token-part-1-8f7616113c14
    - https://medium.com/@cjainn/anatomy-of-a-jwt-token-part-2-c12888abc1a2
    - https://scotch.io/bar-talk/why-jwts-suck-as-session-tokens
    - https://t.me/why_jwt_is_bad
  16. @zmts zmts revised this gist Jul 11, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -51,7 +51,7 @@ __Роль рефреш токенов и зачем их хранить в БД
    4. Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (из `expires_in`)и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__

    ## Схема рефреша токенов (одна сессия/устройство, api/auth/refresh-tokens):
    1. Клиент проверяет перед запросом не истекло ли время жизни __access token'на__
    1. Клиент(фронтенд) проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера и достает из него __refresh token__
    4. Сравнивает __refresh token__ клиента с __refresh token'ом__ найденным в БД
    @@ -76,7 +76,7 @@ __Если рассматривать возможность аутентифи
    | 1 | alex | { refreshTokenTimestamp1: 'refreshTokenBody1', refreshTokenTimestamp2: 'refreshTokenBody2'} | ['111.111.111.111', '222.222.222.222']
    -------------------------------------------------------------------------------------------------
    ```
    1. Клиент проверяет перед запросом не истекло ли время жизни __access token'на__
    1. Клиент(фронтенд) проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера
    1. Проверяет IP юзера запрашиваемого обновление токенов с белым списком, если все успешно достает __refresh token__ из записи в `refreshTokensMap`
  17. @zmts zmts revised this gist May 21, 2019. 1 changed file with 26 additions and 12 deletions.
    38 changes: 26 additions & 12 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -50,7 +50,7 @@ __Роль рефреш токенов и зачем их хранить в БД
    3. Клиент сохраняет токены и время смерти __access token'а__, используя __access token__ для последующей авторизации запросов
    4. Перед каждым запросом клиент предварительно проверяет время жизни __access token'а__ (из `expires_in`)и если оно истекло использует __refresh token__ чтобы обновить __ОБА__ токена и продолжает использовать новый __access token__

    ## Схема рефреша токенов (api/auth/refresh-tokens):
    ## Схема рефреша токенов (одна сессия/устройство, api/auth/refresh-tokens):
    1. Клиент проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера и достает из него __refresh token__
    @@ -64,21 +64,24 @@ __Роль рефреш токенов и зачем их хранить в БД

    __С такой схемой юзер сможет быть залогинен только на одном устройстве.__ Тоесть в любом случае при смене устройства ему придется логинится заново.

    __Если рассматривать возможность аутентификации на более чем одном девайсе/браузере:__ необходимо хранить весь список валидных рефреш токенов юзера. Если юзер авторизовался более чем на ±10ти устройствах(что есть весьма подозрительно), автоматически инвалидоровать все рефреш токены кроме текущего и отправлять email с security уведомлением. Как вариант список токенов можно хранить в jsonb(если используется PostgreSQL).
    __Если рассматривать возможность аутентификации на более чем одном девайсе/браузере(мульти сессии):__ необходимо хранить весь список валидных рефреш токенов юзера. Если юзер авторизовался более чем на ±10ти устройствах(что есть весьма подозрительно), автоматически инвалидоровать все рефреш токены кроме текущего и отправлять email с security уведомлением. Как вариант список токенов можно хранить в jsonb(если используется PostgreSQL).

    ## Схема рефреша токенов (мульти сессии, api/auth/refresh-tokens):
    Для использования возможности аутентификации на более чем одном девайсе необходимо хранить все рефреш токены по каждому юзеру. Я этот список храню в записи юзера в виде JSONB.
    ## Схема рефреша токенов (мульти сессии/несколько устройств, api/auth/refresh-tokens):
    Для использования возможности аутентификации на более чем одном девайсе необходимо хранить все рефреш токены по каждому юзеру.
    Я этот список храню в записи юзера в виде JSONB. Во время кажого процесса логина необходимо добавлять IP/Fingerprint пользователя-владельца логина/пароля в белый список.
    ```
    -------------------------------------------------------------------------------------------------
    | id | username | refreshTokensMap
    | id | username | refreshTokensMap | whitelistIP
    -------------------------------------------------------------------------------------------------
    | 1 | alex | { refreshTokenTimestamp1: 'refreshTokenBody1', refreshTokenTimestamp2: 'refreshTokenBody2'}
    | 1 | alex | { refreshTokenTimestamp1: 'refreshTokenBody1', refreshTokenTimestamp2: 'refreshTokenBody2'} | ['111.111.111.111', '222.222.222.222']
    -------------------------------------------------------------------------------------------------
    ```
    1. Клиент проверяет перед запросом не истекло ли время жизни __access token'на__
    2. Если истекло клиент отправляет на `auth/refresh-token` URL __refresh token__
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера и достает из него __refresh token__
    4. Сравнивает __refresh token__ клиента с __refresh token'ом__ найденным в БД
    3. Сервер берет __user_id__ из __payload'a__ __refresh token'a__ по нему ищет в БД запись данного юзера
    1. Проверяет IP юзера запрашиваемого обновление токенов с белым списком, если все успешно достает __refresh token__ из записи в `refreshTokensMap`
    2. Если IP юзера отсутствует в белом списке, редиректит на страницу логина
    4. Сравнивает __refresh token__ клиента с __refresh token'ом__ найденным в `refreshTokensMap`
    5. Проверяет валидность и срок действия __refresh token'а__ (но если токен не валиден удаляет его сразу)
    6. В случае успеха сервер:
    1. __Удаляет старый рефреш токен__
    @@ -98,7 +101,8 @@ __Если рассматривать возможность аутентифи

    Возникает вопрос зачем __refresh token'y__ срок жизни, если он обновляется каждый раз при обновлении __access token'a__ ? Это сделано на случай если юзер будет в офлайне более 60 дней, тогда прийдется заново вбить логин/пароль.

    ## В случае кражи(обоих токенов):
    ## В случае кражи токенов (когда когда юзер логинится только с одного устройства: одна сессия):

    1. Хакер воспользовался __access token'ом__
    2. Закончилось время жизни __access token'на__
    3. __Клиент хакера__ отправляет __refresh token__
    @@ -111,9 +115,19 @@ __Если рассматривать возможность аутентифи

    __Проблема:__ Поскольку __refresh token__ продлевает срок своей жизни каждый раз при рефреше токенов >> хакер пользуется токенами до тех пор пока юзер не залогинится.

    ### В случае паранои:
    - Хранить список валидных данных принадлежащим владельцу токена: deviceID, fingerprint браузера, IP/Subnet (в этом случае при каждой попытке зайти с новой точки доступа к интерету придется перелогиниватся)
    - Дополнительно шифровать токены (в nodejs например crypt >> aes-256)
    ## В случае кражи токенов (когда когда юзер логинится с нескольких устройства: мульти сессии):
    Во время кажого процесса логина необходимо добавлять IP/Fingerprint пользователя-владельца логина/пароля в белый список. Таким образом при каждой попытке зайти с новой точки доступа придется перелогиниватся.

    1. Хакер воспользовался __access token'ом__
    2. Закончилось время жизни __access token'на__
    3. __Клиент хакера__ отправляет __refresh token__
    4. Сервер смотрит IP адрес хакера
    5. Сервер не находит IP адрес хакера в белом списке и удаляет __refresh token__ из БД (можно так же забанить этот IP)
    6. Сервер логирует попытку несанкционированного обновления токенов
    7. Сервер перенапрявляет харека на станицу логина. Хакер идет лесом
    8. Юзер пробует зайти на сервер >> обнаруживается что __refresh token__ отсутствует
    9. Сервер перенаправляет юзера на форму аутентификации
    10. Юзер вводит логин/пароль

    ### Пример имплементации:
    __Front-end:__ https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/http.init.js
  18. @zmts zmts revised this gist Apr 8, 2019. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -112,9 +112,8 @@ __Если рассматривать возможность аутентифи
    __Проблема:__ Поскольку __refresh token__ продлевает срок своей жизни каждый раз при рефреше токенов >> хакер пользуется токенами до тех пор пока юзер не залогинится.

    ### В случае паранои:
    - хранить список валидных IP/Subnet, deviceID, fingerprint браузера, генерить рандомный randomUserID
    - дополнительно шифровать токены (в nodejs например crypt >> aes-256)
    - зашивать в payload также IP/подсеть владельца токена. В этом случае при каждой попытке зайти с новой точки доступа к интерету придется перелогиниватся.
    - Хранить список валидных данных принадлежащим владельцу токена: deviceID, fingerprint браузера, IP/Subnet (в этом случае при каждой попытке зайти с новой точки доступа к интерету придется перелогиниватся)
    - Дополнительно шифровать токены (в nodejs например crypt >> aes-256)

    ### Пример имплементации:
    __Front-end:__ https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/http.init.js
  19. @zmts zmts revised this gist Mar 18, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -112,7 +112,7 @@ __Если рассматривать возможность аутентифи
    __Проблема:__ Поскольку __refresh token__ продлевает срок своей жизни каждый раз при рефреше токенов >> хакер пользуется токенами до тех пор пока юзер не залогинится.

    ### В случае паранои:
    - хранить список валидных IP, deviceID, fingerprint браузера, генерить рандомный randomUserID
    - хранить список валидных IP/Subnet, deviceID, fingerprint браузера, генерить рандомный randomUserID
    - дополнительно шифровать токены (в nodejs например crypt >> aes-256)
    - зашивать в payload также IP/подсеть владельца токена. В этом случае при каждой попытке зайти с новой точки доступа к интерету придется перелогиниватся.

  20. @zmts zmts revised this gist Mar 5, 2019. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -124,6 +124,7 @@ __Back-end:__ https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth
    ### Чтиво:
    - Заметка базируется на: https://habrahabr.ru/company/Voximplant/blog/323160/
    - https://tools.ietf.org/html/rfc6749
    - https://www.digitalocean.com/community/tutorials/oauth-2-ru
    - https://jwt.io/introduction/
    - https://auth0.com/blog/using-json-web-tokens-as-api-keys/
    - https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
  21. @zmts zmts revised this gist Feb 11, 2019. 1 changed file with 0 additions and 3 deletions.
    3 changes: 0 additions & 3 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,5 @@
    # Про токены, JSON Web Tokens (JWT), аутентификацию и авторизацию. Token-Based Authentication

    ## Preconditions:
    В данной заметке рассматривается работа JWT с __симметичным__ алгоритмом шифрования (HS256/HS384/HS512)

    ## Основы:

    __Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор)__ - это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных.
  22. @zmts zmts revised this gist Nov 19, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -139,5 +139,6 @@ __Back-end:__ https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth
    - https://www.youtube.com/watch?v=Ngh3KZcGNaU
    - https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
    - https://egghead.io/courses/json-web-token-jwt-authentication-with-node-js
    - https://www.digitalocean.com/community/tutorials/oauth-2-ru


  23. @zmts zmts revised this gist Nov 19, 2018. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -132,8 +132,9 @@ __Back-end:__ https://github.com/zmts/supra-api-nodejs/tree/master/actions/auth
    - https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
    - https://auth0.com/blog/ten-things-you-should-know-about-tokens-and-cookies/
    - https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
    - https://habrahabr.ru/company/dataart/blog/262817/
    - https://habr.com/company/dataart/blog/262817/
    - https://habr.com/post/340146/
    - https://habr.com/company/mailru/blog/115163/
    - https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
    - https://www.youtube.com/watch?v=Ngh3KZcGNaU
    - https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
  24. @zmts zmts revised this gist Oct 12, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@

    ## Основы:

    __Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор)__ - это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с логином/паролем, сохранённым в базе данных пользователей.
    __Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор)__ - это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных.

    __Авторизация(authorization — разрешение, уполномочивание)__ - это проверка прав пользователя на доступ к определенным ресурсам.

  25. @zmts zmts revised this gist Oct 6, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -40,7 +40,7 @@ __refresh token__ - выдается сервером по результам у

    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли.__

    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут безнаказанно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).
    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут бесконтрольно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).

    ## Схема создания/использования токенов (api/auth/login):
    1. Пользователь логинится в приложении, передавая логин/пароль на сервер
  26. @zmts zmts revised this gist Oct 5, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -40,7 +40,7 @@ __refresh token__ - выдается сервером по результам у

    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли.__

    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом мы наверняка знаем о клиентах которых обслуживает сервер и кому позволено авторизоваться. Если не хранить рефреш токен в БД то велика вероятность того что токены будут безнаказанно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).
    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут безнаказанно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).

    ## Схема создания/использования токенов (api/auth/login):
    1. Пользователь логинится в приложении, передавая логин/пароль на сервер
  27. @zmts zmts revised this gist Oct 5, 2018. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -38,7 +38,9 @@ __refresh token__ - выдается сервером по результам у

    Каждый токен имеет свой срок жизни, например __access__: 30мин, __refresh__: 60дней

    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли__
    __Поскольку токены это не зашифрованная информация крайне не рекомендуется хранить в них такую информацию как пароли.__

    __Роль рефреш токенов и зачем их хранить в БД.__ Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом мы наверняка знаем о клиентах которых обслуживает сервер и кому позволено авторизоваться. Если не хранить рефреш токен в БД то велика вероятность того что токены будут безнаказанно гулять по рукам злоумышленников. Для отслеживания которых нам прийдется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).

    ## Схема создания/использования токенов (api/auth/login):
    1. Пользователь логинится в приложении, передавая логин/пароль на сервер
  28. @zmts zmts revised this gist Oct 3, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -73,7 +73,7 @@ __Если рассматривать возможность аутентифи
    -------------------------------------------------------------------------------------------------
    | id | username | refreshTokensMap
    -------------------------------------------------------------------------------------------------
    | 1 | alex | { refreshTokenId1: 'refreshTokenBody1', refreshTokenId2: 'refreshTokenBody2'}
    | 1 | alex | { refreshTokenTimestamp1: 'refreshTokenBody1', refreshTokenTimestamp2: 'refreshTokenBody2'}
    -------------------------------------------------------------------------------------------------
    ```
    1. Клиент проверяет перед запросом не истекло ли время жизни __access token'на__
  29. @zmts zmts revised this gist Oct 3, 2018. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion tokens.md
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ __JSON Web Token (JWT)__ — содержит три блока, разделе

    Пример подписанного JWT токена (после декодирования 1 и 2 блоков):
    ```
    { «alg»: «HS256», «typ»: «JWT» }.{ «iss»: «auth.myservice.com», «aud»: «myservice.com», «exp»: «1435937883», «userName»: «John Smith», «userRole»: «Admin» }.S9Zs/8/uEGGTVVtLggFTizCsMtwOJnRhjaQ2BMUQhcY
    { alg: "HS256", typ: "JWT" }.{ iss: "auth.myservice.com", aud: "myservice.com", exp: 1435937883, userName: "John Smith", userRole: "Admin" }.S9Zs/8/uEGGTVVtLggFTizCsMtwOJnRhjaQ2BMUQhcY
    ```

    __Токены__ предоставляют собой средство __авторизации__ для каждого запроса от клиента к серверу. Токены(и соотвественно сигнатура токена) генерируются на сервере основываясь на секретном ключе(который хранится на сервере) и __payload'e__. Токен в итоге хранится на клиенте и используется при необходимости __авторизации__ како-го либо запроса. Такое решение отлично подходит при разработке SPA.
  30. @zmts zmts revised this gist Sep 13, 2018. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions tokens.md
    Original file line number Diff line number Diff line change
    @@ -115,6 +115,7 @@ __Проблема:__ Поскольку __refresh token__ продлевает
    ### В случае паранои:
    - хранить список валидных IP, deviceID, fingerprint браузера, генерить рандомный randomUserID
    - дополнительно шифровать токены (в nodejs например crypt >> aes-256)
    - зашивать в payload также IP/подсеть владельца токена. В этом случае при каждой попытке зайти с новой точки доступа к интерету придется перелогиниватся.

    ### Пример имплементации:
    __Front-end:__ https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/http.init.js