Habla sobre cookies, sesión y jwt

        Charla sobre cookies, sesión y jwt - Nuggets

        Al desarrollar la página de inicio de sesión en el front-end, a menudo nos encontramos con las cookiepalabras , sessiony jwtestas palabras. Aunque se usan a menudo, su comprensión es relativamente superficial. Este artículo trata de aclarar su esencia y la relación entre ellas.

cookie

        Sabemos que HTTPel protocolo no tiene estado, por lo que el front-end necesita pasar una información de estado para decirle al fondo quién inició la solicitud, cookiees decir, esta información de estado, que es una pequeña porción de datos (no más de 4K) almacenada en el navegador Cuando HTTPse realiza la primera solicitud, el navegador la agregará automáticamente al encabezado de la solicitud y la enviará al fondo.

cookievarios atributos

Set-Cookie: sessionId=123; Path=/accounts; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly; SameSite=Strict

Domain & path

cookieAlcance del control

  • domainEs decir, el nombre de dominio, pathes decir, la ruta, cookiesolo se puede usar bajo el especificado domainy path.

  • Cuando domainno se especifica, el valor predeterminado es el nombre de dominio actual (excluyendo los nombres de subdominio); cuando pathno se especifica, el valor predeterminado es todas las rutas '/' debajo del nombre de dominio.

  • En el ejemplo anterior, el primero cookie:sessionIdno se especifica domainy se especifica Path=/accounts, por lo que a.com/accountsse llevará solo cuando se solicite el recurso a continuación cookie.

Expires & Max-Age

cookieTiempo efectivo de control

  • Expiresy Max-Agese usan para especificar cookieel período de tiempo de espera, el primero se usa para especificar el cookieperíodo de tiempo de espera específico y el último se usa para especificar cookieel intervalo de tiempo de espera;
  • Si no se especifica, se eliminará cuando el usuario cierre el navegadorcookie ;

Secure & HttpOnly & SameSite

cookiePolítica de seguridad controlada

  • SecureEspecifica cookieque httpsdebe llevarse en la solicitud;
  • HttpOnlyEstá prohibido utilizar jsla operación en la parte delantera cookiey document.cookieno se obtendrá el valor cookie;
  • SameSiteDeterminar si el navegador lo lleva automáticamente al cruzar dominios cookie;
    • Strictmás estricto. Si SameSiteel valor de es Strict, el navegador bloquea completamente a terceros Cookie. En resumen, si accede a los recursos de InfoQ desde la página de GeekTime y los de InfoQ Cookieestán configurados SameSite = Strict, estos Cookieno se enviarán al servidor de InfoQ . Solo cuando solicite los recursos de InfoQ del sitio de InfoQ, se traerán estas cookies.

    • LaxRelativamente relajado. En el caso de sitios cruzados, Getse llevarán a cabo ambos métodos de abrir un enlace desde un sitio de terceros y enviar un formulario desde un sitio de terceros Cookie. Sin embargo, si el método se utiliza en un sitio de terceros Post, o img、iframesi la URL se carga a través de etiquetas como , estos escenarios no se llevarán a cabo Cookie.

    • Y si se utilizan None, los datos serán enviados en cualquier caso Cookie.

cookieprincipio

Para entender cookieel principio, en primer lugar, ¿quién puede establecerlo cookie? Como se muestra abajo:

imagen.png

        Se puede ver en la figura que cuando el usuario visita a.com, hay un campo en el encabezado de respuesta devuelto por el fondo.Después set-cookiede que el navegador lea el encabezado de respuesta y tenga este campo, guardará automáticamente la información contenida en este campo en el navegador En solicitudes posteriores, el navegador llevará automáticamente estos cookiedatos y los enviará al servidor.

        Por lo tanto, cookielo configura el servidor y el navegador guarda automáticamente la información de este campo en la computadora del usuario .

    cookiedomainSolo se llevará automáticamente bajo la misma solicitud, y el navegador no llevará esta URL cuando acceda a recursos bajo una URL cookiediferente .domaindomaincookie

        Si un usuario solicita la primera a.compágina, el navegador almacena a.comla siguiente cookie. Luego, el usuario abrió b.comla página siguiente y el navegador también almacenó b.comla página siguiente cookie. Si el usuario envía una solicitud b.coma la página en este momento, ¿ cuál a.comllevará el navegador ?domaincookie

        La respuesta es a.com, es decir, el nombre de dominio incluido en la solicitud no tiene cookienada que ver con el sitio web actualmente abierto, pero urltiene algo que ver con la solicitud. Porque esta característica puede dar lugar a CSRFataques .

cookieel uso de

imagen.png

1. Gestión de sesiones

  • Cuando el usuario visita el sitio web de compras (1-4) por primera vez, el sitio web servergenera uno para el usuario sessionIdy lo incluye en la respuesta Set-Cookie: sessionId=123; Expires=Tue, 15 Jan 2021 21:47:38 GMT;;

  • El navegador recibe la respuesta del servidor, la obtiene de la respuesta Set-Cookiey sessionId=123la almacena en el navegador cookie. Dado que Set-Cookieel atributo Caduca se lleva en el navegador, el navegador también cookieestablece el tiempo de caducidad para esto (si no hay ningún Expiresatributo, el navegador lo tratará cookiecomo session cookieun procesamiento, es decir, cuando el usuario cierre el navegador, se cookieeliminará) ;

  • Cuando el usuario agrega un producto al carrito de compras, el navegador enviará la operación del carrito de compras a , y automáticamente lo incluirá en serverla solicitud y obtendrá el usuario correspondiente (más adelante se explicará cómo encontrar al usuario correspondiente a través de sessionId=123) , y agregó un artículo a su carrito de compras;cookiesessionId=123serversessionId=123

  • Luego, el usuario cierra el sitio de compras;

  • Unas horas más tarde, el usuario vuelve a abrir el sitio web de compras y visita el carrito de compras. El sitio web solicita los datos del carrito de compras del backend. El navegador busca en el área local y encuentra que el sitio web es válido. El navegador adjunta cookieautomáticamente sessionId=123la cookie cookiea el encabezado de solicitud del sitio web ;sessionId=123

  • El servidor recibe la solicitud de consulta del carrito de compras y la obtiene del encabezado de la solicitud sessionId=123. El servidor busca en la memoria id=123y sessionencuentra los datos del producto del carrito de compras del usuario, y el servidor devuelve estos datos al front-end.

  • El usuario ve el artículo agregado en el carrito de compras cuando visitó el sitio web por última vez y selecciona el artículo para completar el pago.

        Lo anterior completa la gestión de la sesión.

2. Seguimiento de usuarios (publicidad)

  • El sitio web de compras está conectado a la plataforma de publicidad sdk (sdk de publicidad de Baidu) y se paga para habilitar la publicidad en la plataforma de publicidad;

  • Cuando un usuario visita un sitio web de compras, automáticamente solicitará recursos de la plataforma de publicidad (generalmente solicitando un gif de la plataforma de publicidad) ([2] en la figura). La plataforma de publicidad sdk genera una identificación única para el usuario: y pone en el user123encabezado de respuesta del recurso CarryInfo cookie( Set-Cookie:HMACCOUNT=user123; Path=/; Domain=hm.baidu.com; Expires=Sun, 18 Jan 2038 00:00:00 GMT);

  • El navegador almacenará Set-Cookiela información en cookiey tenga en cuenta que este cookieatributo domaines el nombre de dominio de la plataforma de publicidad, no el nombre de dominio del sitio web de compras Llamamos a este tipo de cookie de terceros cookie(third cookie);

  • El usuario cierra el sitio web después de ver algunos productos en el sitio web de compras;

  • Después de un período de tiempo, el usuario navega por un sitio web de videos youku.com, y el sitio web de videos ha abierto un servicio de publicidad en la plataforma de publicidad y se ha conectado a la plataforma de publicidad sdk. Del mismo modo, el sitio web solicitará automáticamente recursos bajo la plataforma publicitaria ([7][8] en la figura), y el navegador llevará automáticamente las tres partes previamente almacenadascookie (porque el dominio de esta cookie es el nombre de dominio de la plataforma publicitaria recursos).

  • La plataforma de publicidad recibe youku.comla solicitud de recursos y encuentra que se lleva el encabezado de la solicitud cookie:HMACCOUNT=user123. De esta manera, la plataforma publicitaria reconoce que este usuario es un usuario que ha visitado el sitio web de compras anteriormenteuser123 . Dado que el sitio web de compras ha abierto anuncios pagados, este usuario se identifica como un usuario exacto. Cuando youku.comel material publicitario se extrae de la plataforma publicitaria , será llevado al sitio web de compras para la entrega de anuncios y mostrárselos a los usuarios.

  • Cuando el usuario está youku.comviendo el video, se inserta un anuncio de 30 segundos al comienzo del video y el contenido del anuncio trata sobre las actividades preferenciales del sitio web de compras.

  • Los usuarios están más interesados ​​en las actividades impulsadas por este anuncio, y también son usuarios del sitio web de compras, por lo que tienen una base de confianza, por lo que el usuario hace clic en el anuncio, ingresa al sitio web de compras para recibir descuentos y comprar productos, y por lo tanto, recibe ingresos publicitarios de la plataforma publicitaria youku.com.

        Esto completa cookieel seguimiento del usuario.

session

que es exactamentesession

        Como desarrollo front-end, no entendí qué era durante mucho tiempo session, y no entendí completamente qué era hasta que aprendí poco a poco el desarrollo en segundo plano session.

        Del contenido del apartado anterior podemos saber que cookiese guarda en el navegador, es decir el cliente, entonces session¿dónde se guarda?

        La respuesta es el lado del servidor .

        Después de que el navegador lo envía cookieal servidor, ¿cómo sabe el servidor qué usuario es? Es decir, ¿cómo se usa el servidor cookiepara la verificación de inicio de sesión?

set-cookieEl cliente envía una solicitud de inicio de sesión y el servidor verifica la contraseña y el nombre de usuario. Si son correctos, el servidor los configurará         en el encabezado de respuesta key-value como username=zhangsan:

const getCookieExpires = () => {
  const d = new Date()
  d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
  return d.toGMTString()
}

res.setHeader('Set-Cookie', `username=zhangsan; path=/; httpOnly; expires=${getCookieExpires()}`)

        Después de que el navegador obtenga el encabezado de respuesta, almacenará la información en el navegador cookie, que se almacenará en la siguiente solicitud cookie, y el servidor comenzará a analizar cookiela información después de obtener el encabezado de la solicitud:

// 解析请求头中的cookie信息
req.cookie = {}
const cookieStr = req.headers.cookie || ''
cookieStr.split(';').forEach(item => {
  if (!item) {
    return
  }
  const arr = item.split('=')
  req.cookie[arr[0]] = arr[1]
})
console.log('cookie', req.cookie)

        Después del análisis, se realiza la verificación del usuario. La verificación es muy simple, solo para cookiever si hay alguno username, y si hay una descripción, ya ha iniciado sesión.

        Así es cookiecomo se realiza la autenticación de usuario.

        ¡Es muy sencillo!

        cookieHay un problema fatal en lo anterior : la exposición usernamey otra información clave es muy peligrosa.

        La solución es cookiealmacenar en el medio userid, y el servidor almacena la información correspondiente username, por lo que la información almacenada en el servidor usernamees session.

        Ahora, debes saber qué es session.

cómo almacenarsession

session¿ Dónde         se almacena?

        Lo primero que viene a la mente es guardar en memoria (es decir, mantener un objeto globalmente y usar este objeto para guardar información del usuario).Los siguientes son los pasos para usar la memoria para implementar unasession función de almacenamiento:

  • sessionMantener un objeto almacenado globalmente SESSION_DATApara que se pueda acceder a él durante todo el proceso;
  • Si no se incluye el encabezado de la solicitud userid, significa que se trata de una visita y se solicita al usuario que inicie sesión;
  • Si la solicitud tiene un encabezado userid, SESSION_DATAobtenga la información del usuario correspondiente, si no, permita que el usuario inicie sesión;
  • Después de un inicio de sesión exitoso, escriba la información del usuario en sessionel objeto SESSION_DATA;
// session数据 在全局维护一个session_data
const SESSION_DATA = {}

// 当用户发送请求的时候,解析session
// 解析session
let needSetCookie = false
let userId = req.cookie.userId
if (userId) {
  if (!SESSION_DATA[userId]) {
    SESSION_DATA[userId] = {}
  }
} else {
  userId = `${Date.now()}_${Math.random()}`
  SESSION_DATA[userId] = {}
  // 如果没有userid,说明是第一次登录,那么就去设置cookie
  needSetCookie = true
}
// 把session挂载在req上
req.session = SESSION_DATA[userId]

// 在登录接口,登录成功后往session_data里面写数据
if (method === 'POST' && req.path === '/api/user/login') {
  const { username, password } = req.body
  const result = login(username, password)
  return result.then(data => {
    if (data.username) {
      // 设置session数据
      req.session.username = data.username
      req.session.realname = data.realname

      return new SuccessModel('登录成功')
    }
    return new ErrorModel('登录失败')
  })
}

Si sessionlo almacena en la memoria, encontrará dos problemas :

  • Como es una variable global, está en la memoria, pero el tamaño de la memoria asignada a cada proceso es limitado, y cuando hay muchos usuarios, no podrá almacenarla .
    • El sistema operativo asignará un espacio de memoria para cada proceso, como se muestra en la figura anterior, por ejemplo, de 0x1000 a 0x8000, la parte superior es la memoria de pila y la parte inferior es la memoria de montón.Nuestra sesión se coloca en la memoria de montón. Si hay muchos usuarios en ese momento, habrá más y más montones, llenando toda la memoria y todo el proceso colapsará.

WechatIMG106.png

  • En línea se implementa mediante varios procesos y no se puede acceder a los procesos entre procesossession , por lo que el proceso B no puede acceder al proceso A.

WechatIMG107.png

        Las computadoras de hoy en día son todas multinúcleo, por lo que para hacer un uso completo de los recursos de la computadora, una aplicación a menudo inicia múltiples procesos. Si cada proceso lo tiene , no se puede compartir sessionentre procesos . sessionCuando ingresa por primera vez, presiona el del primer proceso session, pero la segunda vez ingresa y presiona el del segundo proceso session, pero sessionno puede iniciar sesión sin su información. Esto es causado por el equilibrio de carga, que asigna qué proceso depende de qué proceso está relativamente inactivo.

        Dado que sessionno es posible guardarlo en la memoria, ¿es posible guardarlo en la base de datos? ej mysql.

        De hecho, también hay un problema. Tengo que verificar la legitimidad del usuario para cada solicitud. Si la verificación es exitosa, vaya al siguiente paso para obtener datos de la base de datos. Esto es equivalente a consultar la base de datos dos veces , lo que conduce a un mayor tiempo de solicitud .

        Para resolver este problema, generalmente lo colocamos sessionen redisesta base de datos de memoria, y la velocidad de acceso a la memoria es mucho mayor que la velocidad de acceso al disco duro.

        Por lo tanto, el modelo común actual de servicios web se muestra en la figura:

imagen.png

session¿Por qué aplicar redis?

1. Se accede a las sesiones con frecuencia y requieren un rendimiento extremadamente alto

    sessionAcceso frecuente, porque tenemos que verificar si iniciar sesión en cada solicitud, que es una operación previa al acceso, por lo que el acceso debe ser muy rápido, si el acceso es muy lento, las operaciones posteriores también se ralentizarán, lo que resultará sessionen un tiempo de solicitud más largo Long, por lo que los requisitos de rendimiento son extremadamente altos.

2. sessionNo considere el problema de la pérdida de datos debido a una falla de energía (daño de memoria)

    sessionSi se pierden los datos de apagado, vuelva a iniciar sesión (iniciar sesión nuevamente es escribir la información relacionada con el usuario, el usuario primero irá a redis para obtener los datos cuando visite la próxima vez, y luego procederá a la siguiente la lógica comercial después de obtener los datos) está bien. Después de iniciar sesión, puede solicitar otras interfaces para useridverificarlo redis. Si hay, significa que ya ha iniciado sesión.

3. La cantidad de datos de la sesión no será demasiado grande (en comparación con los datos almacenados en mysql)

jwt

qué esjwt

json web token( jwt) es un token basado en JSON que se utiliza para declarar ciertos reclamos en la red. Por lo general, consta de tres partes: información del encabezado (header), cuerpo del mensaje (carga útil) y firma (signature).

  • La información del encabezado especifica el jwtalgoritmo de firma a utilizar.
header = {"alg":"HS256","typ":"JWT"}

HS256 Indica que se utilizó un HMAC-SHA256para generar la firma.

  • La carga útil del cuerpo del mensaje es la parte que realmente almacena la información que debe transmitirse. Por ejemplo, normalmente almacenaremos algunas ID de usuario, nombres de usuario y similares. Además, se incluyen algunos metadatos como editor, fecha de caducidad, etc.
payload = {"userName":"admin","iat":1422779638} //iat表示令牌生成的时间
  • Firma: Firma HeaderyPayload

El token sin firmar se base64urlconcatena a partir de la información del encabezado codificado y el cuerpo del mensaje (separados por "."), y la firma se calcula a través de la clave privada:

key = 'secretkey' // 秘钥保存在服务端,即使用户篡改了数据,因为不知道秘钥,生成的token也是无效的
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)  
signature = HMAC-SHA256(key, unsignedToken)

Finalmente, concatene labase64url firma codificada (también separada por ".") al final del token sin firmar :jwt

token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) 

# token看起来像这样: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI

jwtDarse cuenta del principio de inicio de sesión

  1. Primero, el frontend envía su propio nombre de usuario y contraseña al backend a través de un formulario web.

  2. Después de que el backend verifica el nombre de usuario y la contraseña con éxito, toma la identificación del usuario y otra información como jwt Payload(carga útil), realiza la codificación Base64 y la concatenación con el encabezado, y luego firma para formar una cadena tokencomo aaa.bbb.cccesta.

imagen.png

  1. El backend tokendevuelve la cadena como el resultado de retorno de un inicio de sesión exitoso en el frontend, y el frontend puede guardar el resultado devuelto una localStoragey sessionStorageotra vez, y eliminar el guardado al cerrar la sesión token.

  2. El front-end lo envía al back-end en el encabezado de la solicitud para cada solicitud token. Actualmente hay dos formas:

    • Una es cookiela forma de pasar , es decir, ponerlo token, cookiey el navegador lo tomará automáticamente por nosotros cada vez, y no necesitamos configurarlo nosotros mismos.

    • El segundo es ponerlo en el encabezado de la solicitudheader Authorization , debemos configurar manualmente el encabezado de la solicitud nosotros mismos. Por lo general, después de obtenerse token, se almacenará en sessionStorageo localStorageen, para que tokenno desaparezca cuando se actualice la página.

Authorization: Bearer eyJhbGci*...<snip>...*yu5CSpyHI
  1. El backend verifica la existencia, como tokenla validez de la validación de existencia. Por ejemplo, comprobar si la firma es correcta, comprobar si el Token ha caducado, etc.

jwtpros y contras

        De la introducción anterior, podemos ver que el servidor pone toda la información del usuario tokenen Internet y no necesita redisguardarla session, es decir, usar jwtla mayor ventaja y eliminarla session.

        Pero esto traerá un gran problema, porque tokense almacena en el cliente y el servidor no puede invalidar el token emitido.Incluso si sabe que un tokentoken ha sido robado, no tiene forma de invalidarlo. Hasta tokenque caduque (y absolutamente debe establecer un tiempo de caducidad), no hay mucho que pueda hacer. Por ello, es muy necesario fijartoken el tiempo de caducidad .

        Además, tokenaunque se almacena en Local Storage, para evitar CSRFataques, sigue siendo imposible evitarlos XSS, y las secuencias de comandos entre dominios aún pueden robar Local Storagedatos en .

Resumir

        Dado que httpel protocolo no tiene estado, para saber qué usuario inició la solicitud, nació y se cookie-sessionalmacenó cookieen el cliente. Cada vez que se envía una solicitud, el navegador la enviará automáticamente al fondo. cookieDespués de que el fondo la obtenga de la solicitud encabezado, se enviará desde La información personal del usuario se encuentra redisen él sessiony se completa la confirmación del usuario.

Debido a que es problemático         usarlo redisy guardarlo , espero que la información del usuario se guarde directamente en el lado del cliente en lugar del lado del servidor, así nació .sessionjwt

        El servidor encripta la información del usuario con un algoritmo de encriptación y tokenla envía al navegador. El navegador la almacena en él , la agrega al encabezado de la solicitud localstoragepara cada solicitud y la envía al fondo. El fondo verifica la corrección a través de la clave.localstoragetoken

        No importa si es cookie-session, o si jwtambos tienen el propósito de completar la autenticación del usuario, cada uno tiene sus propias ventajas y desventajas, y se puede usar de manera flexible en diferentes escenarios.

Supongo que te gusta

Origin blog.csdn.net/liuqinhou/article/details/132009487
Recomendado
Clasificación