paint-brush
Si no puedes controlar el almacenamiento, controla el accesopor@axotion
207 lecturas

Si no puedes controlar el almacenamiento, controla el acceso

por Kamil Fronczak
Kamil Fronczak HackerNoon profile picture

Kamil Fronczak

@axotion

I’m a 2X-year-old tech dude from Poland, and this is...

4 min read2025/01/18
Read on Terminal Reader
Read this story in a terminal
Print this story
tldt arrow
es-flagES
Lee esta historia en Español!
en-flagEN
Read this story in the original language, English!
ko-flagKO
이 이야기를 한국어로 읽어보세요!
bn-flagBN
এই গল্পটি বাংলায় পড়ুন!
ja-flagJA
この物語を日本語で読んでください!
tl-flagTL
Basahin ang kwentong ito sa Filipino!
uk-flagUK
Читайте цю історію українською!
lv-flagLV
Izlasi šo stāstu latviešu valodā!
el-flagEL
Διαβάστε αυτή την ιστορία στα ελληνικά!
bs-flagBS
Pročitajte ovu priču na bosanskom!
lt-flagLT
Skaitykite šią istoriją lietuvių kalba!
si-flagSI
මේ කතාව සිංහලෙන් කියවන්න!
sv-flagSV
Läs denna berättelse på svenska!
ES

Demasiado Largo; Para Leer

Últimamente, he estado pensando en cómo hacer que algunos de mis puntos finales cruciales sean más seguros al utilizar JWT almacenado localmente.
featured image - Si no puedes controlar el almacenamiento, controla el acceso
Kamil Fronczak HackerNoon profile picture
Kamil Fronczak

Kamil Fronczak

@axotion

I’m a 2X-year-old tech dude from Poland, and this is my blog about tech stuff: NestJS, Node

Últimamente, he estado pensando en cómo hacer que algunos de mis puntos finales cruciales sean más seguros al utilizar JWT almacenado localmente.


Puede que no sea la mejor práctica para la seguridad (debido a la posibilidad de ataques XSS), pero no era un requisito que yo estableciera. Tuve que adaptarme.


Para que esto sea más seguro, encontré una solución que espero que también te ayude.

El problema

Supongo que todos sabemos qué es JWT: un token emitido por el servicio backend, que no puede ser modificado por el frontend, porque eso cambiaría la firma e invalidaría automáticamente el token.


Suena genial, hasta que nos encontramos con una situación en la que el token puede ser robado, como en mi caso con el ataque XSS. Muchos sitios web almacenan tokens en el almacenamiento local en lugar de en cookies exclusivas de HTTP, por lo que también son vulnerables.

La solución

Entonces, cuando no es posible cambiar la forma en que el frontend almacena ese token, tenemos que cambiar la forma en que emitimos y validamos el token, y este es el momento en el que quiero presentarles una solución simple: JWT con huella digital hash, pero veamos el código.


Supongamos que tenemos un punto final para emitir tokens, llamémoslo punto final de inicio de sesión.

 @Controller('v1/sign-in') export class SignInAction { constructor(private jwtService: JwtService) {} @Post() async handle( @Req() request: Request, @Body() body: SignInHttpRequest, ): Promise<SignInHttpResponse> { const ip = request.headers['x-forwarded-for'] || request.socket.remoteAddress; const userAgent = request.headers['user-agent']; const token = this.jwtService.sign({ email: body.email, fingerprint: getSHA512Hash(`${ip}${userAgent}`), // It's worth to mention, that to make it even more secure, you should add salt }); return { token, }; } }


Entonces, lo que estamos haciendo aquí es básicamente recolectar el agente de usuario y la IP remota del usuario que se está conectando, codificarlo y luego colocarlo en el token JWT, por lo que incluso si el usuario o el atacante quisieran ver qué hay dentro del token JWT, solo verán un valor codificado aleatorio.


Pero, ¿cómo va a mejorar mi seguridad? Echemos un vistazo a nuestro segundo punto final, mostremos la huella digital.


 @Controller('v1/fingerprint') @UseGuards(AuthGuard(JWT_STRATEGY)) export class ShowFingerPrintAction { @Get() async handle(@Req() request) { return { fingerprint: request.user.fingerprint, }; } }


En un principio, no es nada especial. Punto final que devuelve la huella digital de la solicitud, ¿qué lo hace más seguro? ¡JWT_STRATEGY!


 export const JWT_STRATEGY = 'JWT'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy, JWT_STRATEGY) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: 'hard!to-guess_secret', passReqToCallback: true, }); } async validate(request: Request, payload: any): Promise<any> { const fingerprint = payload.fingerprint; const ip = request.headers['x-forwarded-for'] || request.socket.remoteAddress; const userAgent = request.headers['user-agent']; const calculatedFingerprint = getSHA512Hash(`${ip}${userAgent}`); // It's worth to mention, that to make it even more secure, you should add salt if (fingerprint !== calculatedFingerprint) { throw new BadRequestException('Invalid fingerprint'); } return payload; } }

Como puede ver, en la estrategia, extraemos los mismos valores que cuando los extrajimos del punto final de inicio de sesión y los comparamos: si la IP o el agente de usuario han cambiado, denegaremos el acceso a nuestro punto final de huella digital.


Este es el caso en el que incluso si el atacante robara nuestro token, no podría hacer nada con él, porque

  • Él no sabe qué es el hash dentro de la huella digital.
  • No le permitiremos conectarse a nuestros puntos finales debido a una IP y un agente de usuario diferentes (y quizás más factores)


Así es como podemos proteger nuestro punto final crucial de una manera muy sencilla, aunque, por supuesto, hay algunas desventajas.

  • Para cada llamada, tenemos que calcular el hash sha512
  • Si el usuario tiene una IP dinámica tendrá que iniciar sesión con frecuencia


Para el primer problema, por supuesto, podrías verificar solo la IP y ni siquiera hacer un hash al emitir un token, pero entonces el atacante potencial conoce el vector del ataque (suplantación de IP u otros métodos), por lo que es más seguro sacrificar algo de rendimiento por seguridad.


Espero que este método le ayude a introducir una capa adicional de seguridad en sus puntos finales cruciales.


Enlace al código fuente funcional: Código fuente


Consejos:

  • El encabezado X-FORWARDER-FOR se puede falsificar fácilmente a menos que uses servicios como Cloudflare, tenlo en cuenta


L O A D I N G
. . . comments & more!

About Author

Kamil Fronczak HackerNoon profile picture
Kamil Fronczak@axotion
I’m a 2X-year-old tech dude from Poland, and this is my blog about tech stuff: NestJS, Node

ETIQUETAS

ESTE ARTÍCULO FUE PRESENTADO EN...

Read on Terminal Reader
Read this story in a terminal
 Terminal
Read this story w/o Javascript
Read this story w/o Javascript
 Lite
Also published here
X REMOVE AD