Perversiones curiosas del mundo de TI - 4

imagen

El Daily WTF ha estado recopilando historias divertidas, salvajes y / o tristes del mundo de TI durante 15 años. Traduje varias historias que me parecieron interesantes. Todos los nombres de compañías y nombres han sido cambiados. Los problemas anteriores se pueden encontrar bajo la etiqueta " perversiones curiosas ".

La primera historia Fin de mes


[Original]

Si le pregunta a un ingeniero de diseño si es seguro cruzar un puente, estará encantado de decirle qué tan confiables son los puentes, cómo funcionan las matemáticas en ellos, qué tan lejos hemos llegado en materia de seguridad en la construcción. Después de hablar con él, tendrá la impresión de que ni un solo puente en la Tierra se desmoronará. Pero si le pregunta al ingeniero de desarrollo de software sobre los bancos, lo más probable es que se horrorice, y con una probabilidad del 50/50 se convencerá de invertir todo el dinero en bitcoin. Los bancos son conocidos por sus malas decisiones al crear software, no porque estas decisiones sean desagradables, sino porque la mayoría de las personas asumen que los bancos son más precisos y cuidadosos con la seguridad.

Kato trabaja en Inibank, donde se utiliza un producto comercial llamado T24 como núcleo del sistema bancario. El sistema T24 es utilizado por cientos de bancos en todo el mundo. Se puede personalizar para una amplia gama de soluciones bancarias. Como con la mayoría de los paquetes personalizados. Hay programadores que se especializan en escribir código para él y consultores que ayudan a los bancos con actualizaciones importantes.

El personal de Inibank estaba ocupado, por lo que el banco invitó a un consultor a participar en un proyecto especial. Al final de la jornada laboral, el banco realizó el proceso de finalización, que es necesario para que todo el dinero vaya a donde fue dirigido, se recalculen todos los datos de salida necesarios y se ejecuten todos los informes requeridos. En los bancos, este proceso también cambia la fecha del sistema al siguiente día hábil. Es por eso que cuando realiza operaciones bancarias en línea el domingo, ni una sola transacción comienza a procesarse hasta el lunes por la mañana. El consultor tuvo que crear un nuevo informe que se ejecutaría durante el proceso de finalización e incluía un procesamiento adicional si la fecha correspondía al final del mes.

Kato le mostró al nuevo consultor cómo el banco establece los informes al final del día. “Vea, tenemos variables globales para el día hábil anterior, para hoy y para el día hábil siguiente. Tienen el formato YYMMDD para facilitar el trabajo ".

"Sí, sí, lo tengo. Lo entiendo ¿En qué formato están?

"... Uhh ... solo puedo suponer que este es el año, mes y día".

"Sí, sí, está bien. Genial Luego me pongo a trabajar.

Después de esta conversación, Kato tuvo un mal presentimiento sobre esto. pero trató de deshacerse de él. El consultor dijo que todo está listo y listo. Él sabe exactamente lo que está haciendo, ¿verdad? Kato se lo quitó de la cabeza y dejó de preocuparse hasta que llegó el momento de revisar el código y encontró esa perla:

 TH.DATE = R.DATES(EB.DAT.NEXT.WORKING.DAY)[1,6]:"01" CALL CDT('ES00',TH.DATE,"-1C") WTODAY = OCONV(DATE(),"DY") : FMT(OCONV(DATE(),"DM"),'R%2') : FMT(OCONV(DATE(),"DD"),'R%2') IF TH.DATE EQ WTODAY THEN 

Explica brevemente lo que sucede aquí:

  1. Tome el siguiente día hábil y cambie el día a 01 para obtener el primer día del mes.
  2. Cambiamos esta fecha restando 1 día calendario en el calendario de España.
  3. Tomamos la fecha del servidor y la traducimos al formato AAAAMMDD, llamando al comando Fecha tres veces.
  4. Si la fecha calculada en el paso 2 es igual a la fecha calculada en el paso 3, inicie el proceso.

Bueno, en realidad ... funciona. En su mayor parte A menos que por alguna razón, el final del día no ocurra después de la medianoche del penúltimo día del mes, y esto no es tan raro. En este caso, el código pensará erróneamente que este es el último día del mes y comenzará a crear el informe. Lo que va bien con otro problema: si sucede lo mismo el último día del mes, la creación del informe no comenzará por error. Y el mejor error: si el último día del mes resultó ser domingo, entonces el calendario del servidor nunca se instalará en él, ya que omite los días no laborables.

Hablando de días no laborables: dado que Inibank se encuentra en los EE. UU., No hay razón para usar el calendario de España. Sí, los meses y las semanas serán los mismos, pero en el calendario de software español debe especificar los días festivos en los EE. UU., De lo contrario, el programa continuará funcionando. Finalmente, como si todo esto no fuera suficiente, la llamada de fecha triple significa que puede haber desacuerdos al comenzar exactamente a la medianoche: el mes se solicita antes de la medianoche y el día después.

Kato agregó un comentario, sugiriendo una forma de cambiar el código:

 IF R.DATES(EB.DAT.TODAY)[5,2] # R.DATES(EB.DAT.LAST.WORKING.DAY)[5,2] THEN 

Cinco minutos después, el consultor fue a su escritorio. "¿Qué significa esta edición?"

Kato no estaba de humor para discutir en ese momento. “Tu código está roto, amigo. Todo esto no es necesario ".

“Ya veo, ya veo. En realidad, esto es solo un procedimiento operativo estándar para nuestra industria. Bueno, está bien ".

Kato lo dudaba mucho, pero simplemente se encogió de hombros. “Entonces la industria está equivocada. Le expliqué todo en el comentario ".

"Sí. Si, lo lei. Pero lo volveré a leer. Y desapareció tan repentinamente como apareció.

Se hicieron modificaciones, Kato aprobó el código y el consultor desapareció en la niebla.

A veces, acostado en la cama por la noche, Kato se preguntaba: ¿el asesor realmente entendía lo que había hecho mal, o simplemente accedió a mirar, recibió su cheque y continuó escribiendo en algún lugar un código terrible por un precio dos veces el salario de Kato? En aquellos bancos donde no hay empleados que puedan verificar el código.

Pero no invierta todo el dinero en bitcoin. Es aún peor allí.

La segunda historia. ¿Cómo se hace esto?


[Original]

A la gente le encanta comer hot dogs hasta que descubran cómo cocinan. La mayoría no pregunta, porque no quieren saber y continúan comiendo hot dogs. Al desarrollar software, a veces tenemos que preguntar. No solo para resolver problemas, sino también porque algunos programadores temen que el software en sus automóviles, que viajan a lo largo de la carretera a una velocidad de 100 km / h, esté ensamblado a partir de cintas y palos. Toda nuestra industria se desempeña mal con sus tareas .

Brett trabajó como analista de sistemas en el MedStitute Medical Research Center. MedStitute utilizó un software propietario llamado MedTech para almacenar y analizar datos. A los médicos e investigadores les gustaron los resultados de MedTech, pero su colega Brett Tyree sabía cómo se crearon.

El software no tenía acceso al backend, y todo el proceso de desarrollo tuvo lugar en la GUI del "mouse programable". Parece que esta interfaz fue escrita por una persona que estudió programación en sitios web de copiar y pegar de los años 90, examinó diez minutos de Jurassic Park y buscó respuestas a StackOverflow hasta que se pudo compilar algo. El "lenguaje de programación" también mostró un nivel similar de consideración en la filosofía de diseño. Cada uno if debe haber tenido else . Algunos módulos utilizaron valores booleanos, otros devolvieron cadenas vacías para indicar valores falsos. De la documentación no estaba claro en qué situación ocurrió uno u otro. De hecho, cada if convirtió en tres declaraciones.

Brett necesitaba comenzar un nuevo estudio. Se basó en un conjunto simple de estadísticas y pacientes agrupados utilizando una variable aleatoria. Brett buscó en la lista una variable que pudiera asignarse al azar, pero no lo consideró necesario. Sugirió que cometió un error y retrocedió algunas pantallas para verificar su nombre copiándolo para una búsqueda. Brett regresó a la lista de variables aleatorias. Ella no estaba allí. Echó un vistazo más de cerca a la lista y notó que la lista de variables aleatorias contenía datos de campos de opción múltiple. El campo que necesitaba aleatorizar se basaba en un campo calculado.

Brett sabía que Tyree estaba trabajando en otro proyecto que se aleatorizó por campo calculado, por lo que lo contactó en Slack. “¿Cómo codificaste esta variable aleatoria? ¿Medtech evita que esto suceda?

"Estoy hablando de conferencias, te llamaré más tarde", escribió Tyree.

Unos minutos más tarde, Tyree llamó a Brett.

“Necesitas comenzar con dos campos. Digamos llamémosles $variable_choice , es decir, una pregunta de opción múltiple, y $variable_calced , es decir, su campo calculado. Cuando desea crear una variable que realiza una selección aleatoria basada en un campo calculado, le dice a Medtech que esta variable aleatoria se basa en $variable_choice . Luego elimina $variable_choice y cambia el nombre de $variable_calced a $variable_choice

“Detente, ¿el sistema te permite hacer esto, pero no te permite aleatorizar los campos calculados de ninguna otra manera? ¿Y ella no lo comprueba? "

"Espero que nada cambie, y ella no comienza a verificar esto hasta la finalización de mi proyecto", respondió Tyree.

“Este estudio debería llevarse a cabo durante diez años. ¿Y su finalización exitosa depende de si los desarrolladores consideran que este truco es un error?

“Logré encontrar solo esa solución. Avísame si encuentras algo mejor.

Brett no satisfizo tal truco, y volvió a estudiar la documentación. Encontró una solución "mejor": puede crear un campo de opción múltiple de solo lectura con el único valor predeterminado: el valor del campo calculado. Desafortunadamente, el usuario podría cambiar la lista inadvertidamente respondiendo una pregunta de opción múltiple antes de calcular el valor del campo calculado.

Al final, lo único que le quedaba a Brett era tomar un descanso, ir a la cafetería y comprar un par de perritos calientes.

La tercera historia. Portabilidad y hardware


[Original]


Hace muchas lunas, cuando las PC tenían cajas de metal pesado y plástico, se le pidió a Matt y su colega que evaluaran el paquete de software para la próxima operación del departamento de ventas. Desafortunadamente, él y su colega trabajaron en diferentes oficinas dentro de la misma ciudad. En esa época, todavía no existían herramientas efectivas de colaboración en línea, por lo que Matt regularmente tenía que viajar a otra oficina, llevándose una PC con él. Esto significaba que cada vez que era necesario desconectar los cables periféricos del caso 473, llevar la computadora por los pasillos y bajar las escaleras, tomar un autobús para llegar a otra oficina, en la que hizo todo esto en el orden inverso. A veces, la organización incorrecta de la mano de obra obligó a esta pareja a trabajar los fines de semana, lo que significa que llevan máquinas de trabajo a casa.

En el proceso, el disco duro de 20 MB en la computadora de Matt se desbordó. Desde su oficina, envió una solicitud al departamento de TI. Para completar la solicitud, se designó al técnico de Gary, quien después de un tiempo apareció en el cubo de Matt, sosteniendo un nuevo disco duro y un destornillador. Gary envió a Matt a tomar un café para concentrarse en su "paciente". Después de una pequeña cirugía, la PC de Matt se encendió y trabajó con un disco duro grande.

El día antes de la fecha límite del proyecto, Matt casi completó su parte del trabajo. Solo tenía que hacer algunas adiciones a su informe, y luego copiarlo en disquetes y enviarlo al departamento de ventas. Devolvió su PC al cubo y conectó los cables, encendió la alimentación y escuchó un estallido. La PC estaba muerta y no mostraba signos de vida.

Después de una llamada de pánico al departamento de TI, Gary apareció nuevamente en su oficina con un destornillador. Al abrir la carcasa de la PC, inmediatamente gritó: “¡Espera un minuto! ¿Arrastraste una computadora a alguna parte?

Matt frunció el ceño. "Bueno, sí. ¿Esa es la cosa?

"Sí, por supuesto! ¡No deberías haber hecho eso! Gary comenzó a maldecir. "¡El disco duro comenzó a pasar el rato y acortó todo dentro!"

Matt se inclinó sobre Gary para ver por sí mismo el interior de la computadora. Inmediatamente se dio cuenta de que el nuevo disco duro estaba "fijado" a cinta.

“¡Para! ¡Que no deberías haber hecho esto! Matt señaló un trozo de cinta adhesiva. "¿Debería contactar a su supervisor por si acaso?"

La cara de Gary frunció el ceño. "¡No me dan los cierres necesarios!

"¡Entonces encuentra al que los tiene!"

Dado el plazo inminente, con el permiso del jefe, Matt transfirió su solicitud aún más. Casi inmediatamente, la cinta adhesiva fue reemplazada por hardware genuino. Nunca entendió por qué los empleados del departamento de TI no tenían acceso al equipo necesario; sugirió que era una idea brillante de un idiota ahorrar dinero. Matt solo podía adivinar qué otras improvisaciones desesperadas hicieron funcionar su infraestructura de TI y cuánto tiempo pasarían desapercibidas si su PC no se rompía.

La cuarta historia. Así es como PL / SQL afecta su cerebro.


[Original]

El campeón eterno entre las decisiones más extrañas y sin éxito seguirá siendo para siempre Oracle . Hoy nos fijamos en un pequeño código PL / SQL.

PL / SQL es un lenguaje extraño, una mezcla de SQL y lenguaje interactivo (de procedimiento) con lenguaje orientado a objetos pegado a un lado. La sintaxis es excelentemente capaz de crear la impresión de que se desarrolló en la década de 1970, y cada nueva función o cambio de idioma continúa esta tradición.

La estructura de cada módulo de código PL / SQL está basada en bloques . Cada bloque es un espacio de nombres independiente. En resumen, su anatomía se ve así:

 DECLARE -- variable declarations go here BEGIN -- code goes here EXCEPTIONS -- exception handling code goes here, using WHEN clauses END; 

Si está escribiendo un procedimiento almacenado o un controlador de eventos, reemplace la palabra clave DECLARE con CREATE [OR REPLACE] . También puede anidar bloques dentro de otros bloques, por lo que a menudo puede ver el código estructurado de esta manera:

 BEGIN DECLARE --stuff BEGIN --actions END; --more actions END; 

Sí, bastante rápido comienza a ser confuso. Y sí, si desea proporcionar un manejo de errores al menos aproximadamente estructurado, debe comenzar a colocar bloques entre sí.

El idioma y la base de datos tienen otras características divertidas. Antes de la versión 12c, no tenían un tipo de columna IDENTITY . En versiones anteriores, tenía que usar el objeto SEQUENCE y escribir procedimientos o controladores de eventos que realizaran numeración automática forzada. Normalmente, el operador SELECT INTO… se usaba para asignar un valor a una variable. Bonificación: Oracle SQL siempre requiere que se especifique una tabla en la instrucción FROM , por lo que debe usar una tabla dual inventada, como esta:

 CREATE TRIGGER "SOME_TABLE_AUTONUMBER" BEFORE INSERT ON "SOME_TABLE" FOR EACH ROW BEGIN SELECT myseq.nextval INTO :new.id FROM dual; END; 

:new en este contexto indica la línea para la que estamos numerando automáticamente. En versiones anteriores de Oracle, esta era la forma "habitual" de crear columnas con numeración automática. Benoit descubrió otra forma, un poco menos común, de hacer la misma operación:

 CREATE OR REPLACE TRIGGER "SCHEMA1"."TABLE1_TRIGGER" BEFORE INSERT ON "SCHEMA1"."TABLE1" FOR EACH ROW BEGIN DECLARE pl_error_id table1.error_id%TYPE; CURSOR get_seq IS SELECT table1_seq.nextval FROM dual; BEGIN OPEN get_seq; FETCH get_seq INTO pl_error_id; IF get_seq%NOTFOUND THEN raise_application_error(-20001, 'Sequence TABLE1_SEQ does not exist'); CLOSE get_seq; END IF; CLOSE get_seq; :new.error_id := pl_error_id; END; END table1_trigger; 

Están pasando muchas cosas aquí. Primero, observe que la sección DECLARE contiene la instrucción CURSOR . Los cursores le permiten recorrer en iteración los registros. Son muy caros y en el mundo de Oracle es un recurso que necesita ser liberado.

Este controlador de eventos (activador) utiliza un bloque anidado sin ningún motivo. También utiliza la variable adicional pl_error_id , que se puede prescindir.

Pero la parte realmente extraña es el bloque IF get_seq%NOTFOUND . Todo es bastante simple: comprueba la condición de que el cursor no devuelva una cadena. Para este cursor, esto no puede suceder ni siquiera en teoría , por lo que las operaciones internas nunca se realizan. Una secuencia siempre devuelve un valor. Y esto es bueno , dado el código que va más allá.

raise_application_error es un análogo de throw en Oracle. Esta declaración sube la pila de bloques ejecutables hasta que encuentra la sección EXCEPTIONS para manejar el error. Observe que cerramos el cursor después de esta declaración; es decir, nunca cerramos el cursor. Los cursores, como se mencionó anteriormente, son caros, y Oracle solo permite que se use un número limitado de ellos.

Aquí vemos un extraño ejemplo de cómo un desarrollador intenta defenderse de un error que no puede suceder, de una manera que conducirá a nuevos errores con el tiempo.

La quinta historia. Inicios de sesión encriptados dobles


[Original]

Crear autenticación para la API web es una tarea difícil , pero tiene muchas soluciones bien establecidas. Lo más difícil es elegir una de las diversas opciones, después de lo cual es suficiente simplemente agregar un componente.

Cuando se implementa correctamente, el sistema no depende del tipo de cliente. Puedo acceder al servicio a través de un navegador, en un cliente pesado o a través de cURL. Si se implementa incorrectamente, obtienes lo que le pasó a Amira .

Ella resolvió el problema de extraer las estadísticas que necesitaba del backend, pero no pudo descubrir el método de autenticación. Por lo tanto, estudió el código de front-end para comprender cómo se realiza la autenticación:

 crypt = new JSEncrypt(); crypt.setPublicKey('<removed>'); challenge = "<removed>"; function doChallengeResponse() { document.loginForm.password.value.replace(/&/g, '%26'); document.loginForm.password.value.replace(/\\+/g, '%2B'); document.loginForm.password.value = crypt.encrypt(document.loginForm.password.value); document.loginForm.response.value = document.loginForm.password.value; document.loginForm.password.value = ''; document.loginForm.submit(); } 

Por un lado, puedo suponer que este código es muy antiguo, dado el document.loginForm utilizado para las interacciones con elementos DOM. Por otro lado, JSEncrypt se lanzó por primera vez en 2013, lo que nos da la barra de edad máxima.

Transmitimos los parámetros de acceso al backend enviando el formulario, que, según el desarrollador del código, requiere limpieza: se reemplazan todos & + en la contraseña, pero ... esto no es necesario, porque el formulario debe cumplir con la solicitud POST y, además, ciframos los datos .

Aquí está lo que pienso. El código es en realidad bastante antiguo. El desarrollador lo copió de una publicación en StackOverflow alrededor de 2005, que no utilizaba el cifrado ni el POST formularios a través de POST . Año tras año, se le agregaron pequeños cambios. pero el mecanismo subyacente nunca ha cambiado.

Amira revisó el historial y descubrió que el cifrado no se usaba en la versión anterior. challenge , MD5, , , .

: , , , , cURL -. , SSL/TLS .

Source: https://habr.com/ru/post/446714/


All Articles