Le site Web
Daily WTF recueille depuis 15 ans des histoires drôles, sauvages et / ou tristes du monde informatique. J'ai traduit plusieurs histoires qui m'ont paru intéressantes. Tous les noms et noms d'entreprises ont été modifiés. Les numéros précédents se trouvent sous l'étiquette «
perversions curieuses ».
La première histoire. Fin du mois
[Original]Si vous demandez à un ingénieur en conception s'il est sécuritaire de traverser un pont, il se fera un plaisir de vous dire à quel point les ponts sont fiables, comment les mathématiques y fonctionnent, dans quelle mesure nous avons progressé en matière de sécurité des bâtiments. Après avoir parlé avec lui, vous aurez l'impression qu'aucun pont sur Terre ne se désagrègera jamais. Mais si vous interrogez l'ingénieur en développement logiciel sur les banques, vous serez très probablement horrifié, et avec une probabilité de 50/50 vous convaincre d'investir tout l'argent dans le bitcoin. Les banques sont connues pour leurs mauvaises décisions lors de la création de logiciels - non pas parce que ces décisions sont dégoûtantes, mais parce que la plupart des gens supposent que les banques sont plus précises et prudentes en matière de sécurité.
Kato travaille à Inibank, où un produit commercial appelé T24 est utilisé comme noyau du système bancaire. Le système T24 est utilisé par des centaines de banques à travers le monde. Il peut être personnalisé pour une large gamme de solutions bancaires. Comme avec la plupart des packages personnalisés. Il y a des programmeurs spécialisés dans l'écriture de code et des consultants qui aident les banques avec les mises à jour majeures.
Le personnel d'Inibank étant occupé, la banque a invité un consultant à participer à un projet spécial. À la fin de la journée de travail, la banque a effectué le processus d'achèvement, qui est nécessaire pour que tout l'argent aille là où il était dirigé, toutes les données de sortie nécessaires sont recalculées et tous les rapports requis sont exécutés. Dans les banques, ce processus modifie également la date du système au jour ouvrable suivant. C'est pourquoi lorsque vous effectuez des opérations bancaires en ligne le dimanche, aucune transaction ne commence à être traitée avant lundi matin. Le consultant a dû créer un nouveau rapport qui serait exécuté pendant le processus d'achèvement et incluait un traitement supplémentaire si la date correspondait à la fin du mois.
Kato a montré au nouveau consultant comment la banque établit des rapports de fin de journée. «Vous voyez, nous avons des variables globales pour le jour ouvrable précédent, pour aujourd'hui et pour le jour ouvrable suivant. Ils ont le format YYMMDD pour faciliter leur utilisation. "
«Ouais, ouais, j'ai compris. Je comprends. Dans quel format sont-ils? "
"... Euh ... Je peux seulement supposer que c'est l'année, le mois et le jour."
«Ouais, ouais, d'accord. Super. Ensuite, je me mets au travail. »
Après cette conversation, Kato avait un mauvais pressentiment à ce sujet. mais il a essayé de se débarrasser de lui. Le consultant a déclaré que tout était installé et prêt. Il sait exactement ce qu'il fait, non? Kato l'a jeté de sa tête et a cessé de s'inquiéter jusqu'à ce que le temps pour la révision du code soit arrivé et qu'il ait trouvé une telle perle:
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
Expliquez brièvement ce qui se passe ici:
- Prenez le jour ouvrable suivant et changez le jour en 01 pour obtenir le premier jour du mois.
- Nous modifions cette date en soustrayant 1 jour calendaire du calendrier espagnol.
- Nous prenons la date du serveur et la traduisons au format YYYYMMDD, en appelant la commande Date trois fois.
- Si la date calculée à l'étape 2 est égale à la date calculée à l'étape 3, démarrez le processus.
Eh bien, en fait ... ça marche. Pour la plupart. Sauf pour une raison quelconque, la fin de la journée ne se produit pas après minuit l'avant-dernier jour du mois - et ce n'est pas si rare. Dans ce cas, le code pensera à tort qu'il s'agit du dernier jour du mois et commencera à créer le rapport. Ce qui va bien avec un autre problème: si la même chose se produit le dernier jour du mois, la création du rapport ne commencera pas par erreur. Et le meilleur bogue: si le dernier jour du mois s'est avéré être dimanche, le calendrier du serveur ne sera jamais installé dessus, car il saute les jours non ouvrés.
En parlant de jours non ouvrés: Inibank étant situé aux USA, il n'y a aucune raison d'utiliser le calendrier espagnol. Oui, les mois et les semaines seront les mêmes, mais dans le calendrier logiciel espagnol, vous devez spécifier les jours fériés aux États-Unis, sinon le programme continuera de fonctionner. Enfin, comme si tout cela n'était pas encore suffisant, le triple appel Date signifie qu'il peut y avoir des désaccords lors du démarrage à minuit exactement: la valeur du mois est demandée avant minuit et le lendemain.
Kato a ajouté un commentaire, suggérant un moyen de changer le code:
IF R.DATES(EB.DAT.TODAY)[5,2] # R.DATES(EB.DAT.LAST.WORKING.DAY)[5,2] THEN
Cinq minutes plus tard, le consultant s'est rendu à son bureau. "Que signifie cette modification?"
Kato n'était pas d'humeur à discuter à ce moment. «Votre code est cassé, ami. Tout cela n'est pas nécessaire. "
«Je vois, je vois. Il s'agit en fait d'un mode opératoire standard pour notre industrie. Eh bien, d'accord. "
Kato en doutait beaucoup, mais haussa simplement les épaules. «Alors l'industrie a tort. J'ai tout expliqué dans le commentaire. "
"Ouais. Oui, je l'ai lu. Mais je vais le relire. » Et il a disparu aussi soudainement qu'il est apparu.
Des modifications ont été apportées, Kato a approuvé le code et le consultant a disparu dans le brouillard.
Parfois, allongé dans son lit la nuit, Kato se demandait: le consultant comprenait-il vraiment ce qu'il avait fait de mal, ou acceptait-il simplement de regarder, recevait son chèque et continuait à écrire quelque part un code terrible pour un prix deux fois le salaire de Kato? Dans les banques où aucun employé ne peut vérifier le code.
Mais n'investissez pas tout l'argent dans le bitcoin. C'est encore pire là-bas.
La deuxième histoire. Comment cela se fait
[Original]Les gens aiment manger des hot-dogs jusqu'à ce qu'ils découvrent comment ils cuisinent. La plupart ne demandent pas, car ils ne veulent pas savoir et continuent de manger des hot-dogs. Lors du développement de logiciels, nous devons parfois demander. Non seulement pour résoudre des problèmes, mais aussi parce que certains programmeurs ont peur que le logiciel dans leurs voitures, circulant sur l'autoroute à une vitesse de 100 km / h, soit assemblé à partir de bandes et de bâtons.
Toute notre industrie fait mal ses tâches .
Brett a travaillé comme analyste de systèmes au MedStitute Medical Research Center. MedStitute a utilisé un logiciel propriétaire appelé MedTech pour stocker et analyser les données. Les médecins et les chercheurs ont aimé les résultats de MedTech, mais leur collègue Brett Tyree savait comment ils ont été créés.
Le logiciel n'avait pas accès au backend, et l'ensemble du processus de développement s'est déroulé dans l'interface graphique "souris programmable". Cette interface semblait avoir été écrite par une personne qui a étudié la programmation sur des sites de copier-coller des années 90, regardé dix minutes
de Jurassic Park et recherché des réponses à StackOverflow jusqu'à ce que quelque chose puisse être compilé. Le «langage de programmation» a également montré un niveau similaire de réflexion dans la philosophie de conception. Chacun
doit avoir eu un
else
. Certains modules ont utilisé des valeurs booléennes, d'autres ont renvoyé des chaînes vides pour indiquer de fausses valeurs. D'après la documentation, il n'était pas clair dans quelle situation l'un ou l'autre s'est produit. En fait, chaque
if
s'est transformée en trois déclarations.
Brett avait besoin de commencer une nouvelle étude. Il était basé sur un ensemble simple de statistiques et des patients groupés utilisant une variable randomisée. Brett a cherché dans la liste une variable qui pouvait être randomisée, mais ne l'a pas trouvée nécessaire. Il a suggéré qu'il avait fait une erreur et est retourné quelques écrans pour vérifier son nom en le copiant pour une recherche. Brett est revenu sur la liste des variables randomisées. Elle n'était pas là. Il a examiné de plus près la liste et a remarqué que la liste des variables randomisées contenait des données provenant de champs à choix multiple. Le champ dont il avait besoin pour randomiser était basé sur un champ calculé.
Brett savait que Tyree travaillait sur un autre projet randomisé par champ calculé, il l'a donc contacté à Slack. «Comment avez-vous codé cette variable aléatoire? Medtech empêche-t-il cela de se produire? »
"Je parle de conférence, je vous rappellerai plus tard", a écrit Tyree.
Quelques minutes plus tard, Tyree a appelé Brett.
«Vous devez commencer par deux champs. Disons. appelons-les
$variable_choice
, c'est-à-dire une question à choix multiples, et
$variable_calced
, c'est-à-dire votre champ calculé. Lorsque vous souhaitez créer une variable qui effectue une sélection aléatoire sur la base d'un champ calculé, vous dites à Medtech que cette variable aléatoire est basée sur
$variable_choice
. Ensuite, vous supprimez
$variable_choice
et renommez
$variable_calced
en
$variable_choice
»
«Arrêtez, le système vous permet de le faire, mais ne vous permet pas de randomiser les champs calculés d'une autre manière? Et elle ne le vérifie pas? "
"J'espère que rien ne change, et elle ne commence à vérifier cela qu'à la fin de mon projet", a répondu Tyree.
«Cette étude devrait s'étaler sur dix ans. Et sa réussite dépend si les développeurs considèrent cette astuce comme un bug? »
«J'ai réussi à ne trouver qu'une telle solution. Faites-moi savoir si vous trouvez quelque chose de mieux. "
Brett n'a pas satisfait un tel hack, et il est retourné à étudier la documentation. Il a trouvé une «meilleure» solution: vous pouvez créer un champ à choix multiples en lecture seule avec la seule valeur par défaut - la valeur du champ calculé. Malheureusement, l'utilisateur peut modifier la liste par inadvertance en répondant à une question à choix multiples
avant de calculer la valeur du champ calculé.
En fin de compte, la seule chose qui restait à Brett était de faire une pause, d'aller à la cafétéria et d'acheter quelques hot-dogs.
La troisième histoire. Portabilité et matériel
[Original]Il y a plusieurs lunes, lorsque les PC avaient des boîtiers en métal lourd et en plastique,
Matt et son collègue ont été invités à évaluer le progiciel pour la prochaine opération du service commercial. Malheureusement, lui et son collègue ont travaillé dans différents bureaux de la même ville. À cette époque, les outils de collaboration en ligne efficaces n'existaient pas encore, alors Matt devait régulièrement se rendre dans un autre bureau, emportant un PC avec lui. Cela signifiait qu'à chaque fois qu'il était nécessaire de déconnecter les câbles périphériques du boîtier 473, de transporter l'ordinateur dans les couloirs et dans les escaliers, de prendre un bus pour se rendre dans un autre bureau, dans lequel il faisait tout cela dans l'ordre inverse. Parfois, la mauvaise organisation du travail obligeait ce couple à travailler le week-end, ce qui signifie qu'il transportait des machines à la maison.
Au cours du processus, le disque dur de 20 Mo de l'ordinateur de Matt a débordé. De son bureau, il a envoyé une demande au service informatique. Pour remplir la demande, le technicien de Gary a été nommé, qui après un certain temps est apparu dans le cube de Matt, tenant un nouveau disque dur et un tournevis. Gary a envoyé à Matt un café pour se concentrer sur son «patient». Après une petite opération, le PC de Matt s'est allumé et a fonctionné avec un grand disque dur.
La veille de la date limite du projet, Matt a presque terminé sa part du travail. Il n'avait qu'à apporter quelques ajouts à son rapport, puis le copier sur des disquettes et l'envoyer au service des ventes. Remettant son PC dans le cube et connectant les fils, il alluma l'alimentation et entendit un bruit. Le PC était mort et ne montrait aucun signe de vie.
Après un appel de panique au service informatique, Gary est de nouveau apparu dans son bureau avec un tournevis. Ouvrant le boîtier du PC, il a immédiatement crié: «Attendez une minute! Avez-vous fait glisser un ordinateur quelque part? "
Matt fronça les sourcils. «Eh bien, oui. C'est ça le truc? "
«Oui, bien sûr! Tu n'aurais pas dû faire ça! »Gary commença à maudire. "Le disque dur a commencé à traîner et a tout court-circuité à l'intérieur!"
Matt se pencha sur Gary pour voir par lui-même l'intérieur de l'ordinateur. Il a immédiatement remarqué que le nouveau disque dur était «fixé» sur une bande.
«Arrête! Que
tu n'aurais pas dû faire ça! Matt désigna un morceau de scotch. "Dois-je contacter votre superviseur au cas où?"
Le visage de Gary fronça les sourcils. "Ils ne me donnent pas les attaches nécessaires!"
"Alors trouve celui qui les a!"
Compte tenu du délai imminent, avec la permission du patron, Matt a transféré sa demande encore plus haut. Presque immédiatement, le ruban adhésif a été remplacé par du matériel d'origine. Il n'a jamais compris
pourquoi les employés du service informatique n'avaient pas accès à l'équipement nécessaire; il a suggéré que c'était une idée géniale d'un idiot d'économiser de l'argent. Matt ne pouvait que deviner quelles autres improvisations désespérées faisaient fonctionner leur infrastructure informatique et combien de temps elles passeraient inaperçues si son PC ne se cassait pas.
La quatrième histoire. C'est ainsi que PL / SQL affecte votre cerveau.
[Original]L'éternel champion parmi les décisions les plus étranges et les plus infructueuses restera pour toujours
Oracle . Aujourd'hui, nous regardons un peu de code PL / SQL.
PL / SQL est un langage étrange, un mélange de langage SQL et de procédure (procédurale) (langage) orienté objet collé sur le côté. La syntaxe est superbement capable de donner l'impression qu'elle a été développée dans les années 1970, et chaque nouvelle fonction ou changement de langage perpétue cette tradition.
La structure de chaque module de code PL / SQL est basée sur des
blocs . Chaque bloc est un espace de noms indépendant. En bref, son anatomie ressemble à ceci:
DECLARE
Si vous écrivez une procédure stockée ou un gestionnaire d'événements, remplacez le mot clé
DECLARE
par
CREATE [OR REPLACE]
. Vous pouvez également imbriquer des blocs dans d'autres blocs, donc vous pouvez souvent voir du code structuré de cette façon:
BEGIN DECLARE
Oui, assez rapidement, cela commence à devenir déroutant. Et oui, si vous voulez fournir une gestion des erreurs au moins approximativement structurée, vous
devez commencer à mettre des blocs les uns dans les autres.
La langue et la base de données ont d'autres fonctionnalités amusantes. Avant la version 12c, ils n'avaient pas de type de colonne
IDENTITY
. Dans les versions précédentes, vous deviez utiliser l'objet
SEQUENCE
et écrire des procédures ou des gestionnaires d'événements qui effectuent une numérotation automatique forcée. En règle générale, l'opérateur
SELECT INTO…
était utilisé pour attribuer une valeur à une variable. Bonus: Oracle SQL nécessite
toujours une table à spécifier dans l'instruction
FROM
, vous devez donc utiliser une table
dual
inventée, comme ceci:
CREATE TRIGGER "SOME_TABLE_AUTONUMBER" BEFORE INSERT ON "SOME_TABLE" FOR EACH ROW BEGIN SELECT myseq.nextval INTO :new.id FROM dual; END;
:new
dans ce contexte indique la ligne pour laquelle nous numérotons automatiquement. Dans les anciennes versions d'Oracle, c'était la façon «habituelle» de créer des colonnes avec une numérotation automatique.
Benoit a découvert une autre façon, un peu moins courante, de faire la même opération:
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;
Il se passe beaucoup de choses ici. Tout d'abord, notez que la section
DECLARE
contient l'instruction
CURSOR
. Les curseurs vous permettent de parcourir les enregistrements. Ils sont très chers et dans le monde Oracle, c'est une ressource qui doit être libérée.
Ce gestionnaire d'événements (déclencheur) utilise un bloc imbriqué sans raison. Il utilise également la variable supplémentaire
pl_error_id
, qui peut être supprimée.
Mais la partie vraiment bizarre est le bloc
IF get_seq%NOTFOUND
. Tout est assez simple: il vérifie la condition que le curseur ne retourne pas de chaîne. Pour ce curseur, cela ne peut pas se produire même
théoriquement , donc les opérations à l'intérieur ne sont jamais effectuées. Une séquence renvoie toujours une valeur. Et c'est
bien vu le code qui va plus loin.
raise_application_error
est un analogue de throw dans Oracle. Cette instruction remonte la pile de blocs exécutables jusqu'à ce qu'elle trouve la section
EXCEPTIONS
pour gérer l'erreur. Notez que nous fermons le curseur
après cette instruction - c'est-à-dire que nous
ne fermons
jamais le curseur. Comme indiqué ci-dessus, les curseurs sont chers et Oracle n'en autorise qu'un nombre limité.
Nous voyons ici un exemple étrange de la façon dont un développeur essaie de se défendre contre une erreur qui ne peut pas se produire, d'une manière qui conduira à de nouvelles erreurs au fil du temps.
La cinquième histoire. Connexions cryptées doubles
[Original]La création de l'authentification pour l'API Web est une tâche
difficile , mais elle comporte de
nombreuses solutions bien établies. La chose la plus difficile est en fait de choisir l'une des différentes options, après quoi il suffit d'ajouter simplement un composant.
Lorsqu'il est correctement implémenté, le système ne dépend pas du type de client. Je peux accéder au service via un navigateur, dans un client lourd ou via cURL. S'il n'est pas correctement mis en œuvre, vous obtenez ce qui est arrivé à
Amira .
Elle a résolu le problème de l'extraction des statistiques dont elle avait besoin depuis le backend, mais n'a pas pu déterminer la méthode d'authentification. Par conséquent, elle a étudié le code frontal pour comprendre comment il effectue l'authentification:
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(); }
D'une part, je peux supposer que ce code est très ancien, étant donné le
document.loginForm
utilisé pour les interactions avec les éléments DOM. D'un autre côté,
JSEncrypt
été publié pour la première fois en 2013, ce qui nous donne la barre d'âge maximale.
Nous transmettons les paramètres d'accès au backend en soumettant le formulaire, qui, selon le développeur du code, a nécessité un nettoyage - tous les
&
+
dans le mot de passe sont remplacés, mais ... cela n'est pas nécessaire, car le formulaire doit répondre à la demande
POST
et, en outre,
nous avons crypté les données .
Voici ce que je pense. Le code
est en fait assez ancien. Le développeur l'a copié à partir d'un article sur StackOverflow vers 2005, qui n'utilisait pas le chiffrement et la
POST
formulaires via
POST
. Année après année, de petits changements y ont été ajoutés. mais le mécanisme sous-jacent n'a jamais changé.
Amira a vérifié l'historique et a constaté que le cryptage n'était pas utilisé dans la version précédente.
challenge
, MD5,
, , .
: , , , , cURL -. ,
SSL/TLS .