utf8 utf16 transformar online english encryption unicode

encryption - transformar - unicode to utf16



¿Debo usar Base64 o Unicode para almacenar hash y sales? (4)

Nunca he trabajado en el lado de la seguridad de las aplicaciones web, ya que acabo de salir de la universidad. Ahora, estoy buscando un trabajo y trabajando en algunos sitios web, para mantener mis habilidades afiladas y adquirir nuevas. Uno de los sitios en los que estoy trabajando está bastante copiado de la pila MEAN original de los chicos que lo crearon, pero tratando de entenderlo y hacer las cosas mejor donde puedo.

Para calcular el hash & salt, los creadores utilizaron PBKDF2. No me interesa escuchar sobre argumentos a favor o en contra de PBKDF2, ya que no es de lo que trata esta pregunta. Parece que usaron buffers para todo aquí, lo que entiendo es una práctica común en node . Lo que me interesa son sus razones para usar base64 para la codificación del búfer, en lugar de simplemente usar UTF-8 , que es una opción con el objeto del búfer. Hoy en día, la mayoría de las computadoras pueden manejar muchos de los caracteres en Unicode, si no todos, pero los creadores podrían haber elegido codificar las contraseñas en un subconjunto de Unicode sin limitarse a los 65 caracteres de base64 .

Por "la elección entre la codificación como UTF-8 o base64 ", me refiero a transformar el binario del hash, calculado a partir de la contraseña, en la codificación dada. node.js especifica un par de formas de codificar datos binarios en un objeto Buffer. Desde la página de documentación de la clase Buffer:

Pure JavaScript is Unicode friendly but not nice to binary data. When dealing with TCP streams or the file system, it''s necessary to handle octet streams. Node has several strategies for manipulating, creating, and consuming octet streams. Raw data is stored in instances of the Buffer class. A Buffer is similar to an array of integers but corresponds to a raw memory allocation outside the V8 heap. A Buffer cannot be resized.

Lo que la clase Buffer hace, como lo entiendo, es tomar algunos datos binarios y calcular el valor de cada 8 (usualmente) bits. Luego, convierte cada conjunto de bits en un carácter correspondiente a su valor en la codificación que especifique. Por ejemplo, si los datos binarios son 00101100 (8 bits), y especifica UTF-8 como la codificación, la salida sería (una coma). Esto es lo que vería cualquier persona que vea la salida del búfer cuando lo vea con un editor de texto como vim , así como lo que una computadora "vería" cuando "los leyera". La clase Buffer tiene varias codificaciones disponibles, como UTF-8 , base64 y binary .

Creo que sintieron que, mientras almacenaban cualquier personaje UTF-8 imaginable en el hash, como tendrían que hacer, no se eliminarán las computadoras más modernas, con sus gigabytes de RAM y terabytes de espacio, mostrando realmente todos estos caracteres, ya que puede querer hacerlo en los registros, etc., podría asustar a los usuarios, quienes tendrían que mirar caracteres chinos, griegos, búlgaros, etc. extraños, así como caracteres de control, como el botón Ctrl o el botón Backspace o incluso los pitidos. Nunca necesitarían realmente darles sentido a ninguno de ellos, a menos que fueran usuarios experimentados que probaran el propio PBKDF2, pero el primer deber del programador es no dar a ninguno de sus usuarios un ataque al corazón. El uso de base64 aumenta la sobrecarga en aproximadamente un tercio, lo que no vale la pena mencionar en estos días, y disminuye el conjunto de caracteres, que no hace nada para disminuir la seguridad. Después de todo, las computadoras están escritas completamente en binario. Como dije antes, podrían haber elegido un subconjunto diferente de Unicode, pero base64 ya es estándar, lo que lo hace más fácil y reduce el trabajo del programador.

¿Tengo razón sobre las razones por las que los creadores de este repositorio eligieron codificar sus contraseñas en base64 , en lugar de todos los Unicode? ¿Es mejor seguir con su ejemplo, o debería usar Unicode o un subconjunto más grande?


Base64 es mejor, pero considere un alfabeto websafe base64 para el transporte. Base64 puede entrar en conflicto con la sintaxis de la cadena de consulta.

Otra opción que podrías considerar es usar hexadecimal. Es más largo pero rara vez entra en conflicto con cualquier sintaxis.


Esta es una respuesta fácil, ya que hay una gran cantidad de secuencias de bytes que no son cadenas UTF-8 bien formadas. El más común es un byte de continuación (0x80-0xbf) que no está precedido por un byte inicial en una secuencia multibyte (0xc0-0xf7); Los bytes 0xf8-0xff tampoco son válidos.

Así que estas secuencias de bytes no son cadenas UTF-8 válidas:

  • 0x80

  • 0x40 0xa0

  • 0xff

  • 0xfe

  • 0xfa

Si desea codificar datos arbitrarios como una cadena, use un esquema que lo permita. Base64 es uno de esos esquemas.

Un punto adicional: usted podría pensar, bueno, realmente no me importa si son cadenas UTF-8 bien formadas, nunca voy a usar los datos como una cadena, solo quiero entregar este byte secuencia para almacenar para más tarde.

El problema con eso es que si asigna una secuencia de bytes arbitraria a una aplicación que espera una cadena UTF-8, y no está bien formada, la aplicación no está obligada a utilizar esta secuencia de bytes. Podría rechazarlo con un error, podría truncar la cadena, podría intentar "arreglarla".

Por lo tanto, no intente almacenar secuencias de bytes arbitrarias como una cadena UTF-8.


Existe una razón fundamental relacionada con la seguridad para almacenar como Base64 en lugar de Unicode: el hash puede contener el valor de byte "0", utilizado por muchos lenguajes de programación como un marcador de fin de cadena.

Si almacena su hash como Unicode, usted, otro programador o algún código de biblioteca que utilice pueden tratarlo como una cadena en lugar de una colección de bytes, y comparar usando strcmp() o una función similar de comparación de cadenas. Si su hash contiene el valor de byte "0", efectivamente truncó su hash a la parte anterior al "0", lo que hace que los ataques sean mucho más fáciles.

La codificación Base64 evita este problema: el valor de byte "0" no puede ocurrir en la forma codificada del hash, por lo que no importa si compara hashes codificados usando memcmp() (de la manera correcta) o strcmp() (de la manera incorrecta ).

Esto tampoco es solo una preocupación teórica: ha habido varios casos de código para verificar firmas digitales usando strcmp() , lo que debilita enormemente la seguridad.


Un valor de hash es una secuencia de bytes . Esta es información binaria. No es una secuencia de caracteres.

UTF-8 es una codificación para convertir secuencias de caracteres en secuencias de bytes. Almacenar un valor de hash "como UTF-8" no tiene sentido, ya que ya es una secuencia de bytes y no una secuencia de caracteres.

Desafortunadamente, muchas personas han adoptado el hábito de considerar un byte como una especie de personaje disfrazado; Estaba en la base del lenguaje de programación C y todavía infecta algunos marcos bastante modernos y generalizados, como Python. Sin embargo, solo la confusión y la tristeza se encuentran en ese camino Los síntomas habituales son personas que lamentan el lamentable "cero carácter", es decir, un byte de valor 0 (un valor perfectamente fino para un byte) que, convertido en un carácter, se convierte en el carácter especial que sirve como extremo de Indicador de cadena en idiomas de la familia C. Esta confusión puede llevar incluso a vulnerabilidades (el cero implica, para la función de comparación, una terminación anterior a la esperada).

Una vez que haya entendido que el binario es binario, el problema se convierte en: ¿cómo debemos manejar y almacenar nuestro valor de hash? En particular en JavaScript, un lenguaje que se sabe que es especialmente deficiente en el manejo de valores binarios. La solución es una codificación que convierte los bytes en caracteres, no solo cualquier carácter, sino un subconjunto muy pequeño de caracteres de buen comportamiento. Esto se llama Base64 . Base64 es un esquema genérico para codificar bytes en cadenas de caracteres que no incluyen caracteres problemáticos (no cero, solo caracteres imprimibles en ASCII, excluyendo todos los caracteres de control y algunos otros como comillas).

No usar Base64 implicaría suponer que JavaScript puede administrar una secuencia arbitraria de bytes como si fuera simplemente "caracteres normales", y eso simplemente no es cierto.