Perversões curiosas do mundo da TI - 4

imagem

O site Daily WTF coleciona histórias engraçadas, selvagens e / ou tristes do mundo da TI há 15 anos. Traduzi várias histórias que me pareciam interessantes. Todos os nomes e nomes de empresas foram alterados. Edições anteriores podem ser encontradas sob o rótulo " perversões curiosas ".

A primeira história. Fim do mês


[Original]

Se você perguntar a um engenheiro de projeto se é seguro atravessar uma ponte, ele ficará feliz em lhe dizer quão confiáveis ​​são as pontes, como a matemática funciona nelas, até onde chegamos em questões de segurança da construção. Depois de conversar com ele, você terá a impressão de que nem uma única ponte na Terra se desintegrará. Mas se você perguntar ao engenheiro de desenvolvimento de software sobre os bancos, provavelmente ficará horrorizado e com uma probabilidade 50/50 de se convencer de investir todo o dinheiro em bitcoin. Os bancos são notórios por suas más decisões ao criar software - não porque essas decisões são repugnantes, mas porque a maioria das pessoas supõe que os bancos são mais precisos e cuidadosos com a segurança.

Kato trabalha no Inibank, onde um produto comercial chamado T24 é usado como o núcleo do sistema bancário. O sistema T24 é usado por centenas de bancos em todo o mundo. Pode ser personalizado para uma ampla gama de soluções bancárias. Como na maioria dos pacotes personalizados. Existem programadores especializados em escrever código para ele e consultores que ajudam os bancos com grandes atualizações.

A equipe do Inibank estava ocupada, então o banco convidou um consultor para participar de um projeto especial. No final do dia útil, o banco conduziu o processo de conclusão, necessário para que todo o dinheiro vá para onde foi direcionado, todos os dados de saída necessários sejam recalculados e todos os relatórios necessários sejam executados. Nos bancos, esse processo também altera a data do sistema para o próximo dia útil. É por isso que quando você realiza operações bancárias online no domingo, nenhuma transação começa a ser processada até segunda-feira de manhã. O consultor teve que criar um novo relatório que seria executado durante o processo de conclusão e incluiu processamento adicional se a data corresponder ao final do mês.

Kato mostrou ao novo consultor como o banco configura relatórios de final do dia. “Veja, temos variáveis ​​globais para o dia útil anterior, para hoje e para o próximo dia útil. Eles têm o formato YYMMDD para facilitar o trabalho ".

“Sim, sim, entendi. Eu entendi. Em que formato eles estão?

"... Uhh ... eu posso apenas assumir que este é o ano, mês e dia."

“Sim, sim, tudo bem. Ótimo. Então eu vou trabalhar.

Após essa conversa, Kato teve um mau pressentimento sobre isso. mas ele tentou se livrar dele. O consultor disse que tudo está configurado e pronto. Ele sabe exatamente o que está fazendo, certo? Kato jogou isso fora de sua cabeça e parou de se preocupar até o momento da revisão do código chegar e ele encontrou uma pérola:

 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 

Explique brevemente o que acontece aqui:

  1. Aproveite o próximo dia útil e altere o dia para 01 para obter o primeiro dia do mês.
  2. Alteramos essa data subtraindo 1 dia no calendário da Espanha.
  3. Pegamos a data do servidor e a convertemos para o formato AAAAMMDD, chamando o comando Date três vezes.
  4. Se a data calculada na etapa 2 for igual à data calculada na etapa 3, inicie o processo.

Bem, na verdade ... funciona. Para a maior parte. A menos que, por algum motivo, o final do dia não aconteça após a meia-noite do penúltimo dia do mês - e isso não é tão raro. Nesse caso, o código pensará erroneamente que este é o último dia do mês e começará a criar o relatório. O que combina bem com outro problema: se a mesma coisa acontecer no último dia do mês, a criação do relatório não começará por engano. E o melhor bug: se o último dia do mês for domingo, o calendário do servidor nunca será instalado nele, porque ele ignora os dias não úteis.

Por falar em dias não úteis: como o Inibank está localizado nos EUA, não há razão para usar o calendário da Espanha. Sim, os meses e as semanas serão os mesmos, mas no calendário do software em espanhol você precisará especificar feriados nos EUA, caso contrário, o programa continuará funcionando. Por fim, como se tudo isso não bastasse, a chamada tripla Data significa que pode haver discordâncias ao iniciar exatamente à meia-noite: o valor do mês é solicitado antes da meia-noite e no dia seguinte.

Kato adicionou um comentário, sugerindo uma maneira de alterar o código:

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

Cinco minutos depois, o consultor foi até sua mesa. "O que essa edição significa?"

Kato não estava disposto a discutir naquele momento. - Seu código está quebrado, amigo. Tudo isso não é necessário. "

“Entendo, entendo. Na verdade, esse é apenas um procedimento operacional padrão para o nosso setor. Bem, tudo bem. "

Kato duvidava muito disso, mas simplesmente deu de ombros. “Então a indústria está errada. Eu expliquei tudo no comentário ".

Sim. Sim, eu li. Mas vou ler de novo. E ele desapareceu tão de repente quanto apareceu.

Edições foram feitas, Kato aprovou o código e o consultor desapareceu na neblina.

Às vezes, deitado na cama à noite, Kato se perguntava: o consultor realmente entendeu o que havia feito de errado ou apenas concordou em olhar, recebeu seu cheque e continuou escrevendo em algum lugar um código terrível por um preço duas vezes maior que o salário de Kato? Nos bancos em que não há funcionários que possam verificar o código.

Mas não invista todo o dinheiro em bitcoin. É ainda pior lá.

A segunda história. Como isso é feito


[Original]

As pessoas gostam de comer cachorro-quente até descobrir como cozinham. A maioria não pergunta, porque não quer saber e continua comendo cachorro-quente. Ao desenvolver software, às vezes precisamos perguntar. Não apenas para resolver problemas, mas também porque alguns programadores têm medo de que o software em seus carros, viajando pela estrada a uma velocidade de 100 km / h, seja montado a partir de fitas e paus. Toda a nossa indústria se sai mal com suas tarefas .

Brett trabalhou como analista de sistemas no MedStitute Medical Research Center. O MedStitute usou um software proprietário chamado MedTech para armazenar e analisar dados. Médicos e pesquisadores gostaram dos resultados da MedTech, mas a colega Brett Tyree sabia como eles foram criados.

O software não teve acesso ao back-end e todo o processo de desenvolvimento ocorreu na GUI do "mouse programável". Essa interface parecia ter sido escrita por uma pessoa que estudou programação em sites de copiar e colar dos anos 90, examinou dez minutos do Jurassic Park e procurou respostas para o StackOverflow até que algo pudesse ser compilado. A "linguagem de programação" também mostrou um nível semelhante de reflexão na filosofia do design. Cada um deve ter um else . Alguns módulos usavam valores booleanos, outros retornavam cadeias vazias para indicar valores falsos. A partir da documentação, não ficou claro em qual situação um ou outro aconteceu. De fato, cada if transformou em três declarações.

Brett precisava iniciar um novo estudo. Foi baseado em um conjunto simples de estatísticas e pacientes agrupados usando uma variável aleatória. Brett procurou na lista uma variável que pudesse ser randomizada, mas não achou necessária. Ele sugeriu que cometeu um erro e voltou algumas telas para verificar o nome dela, copiando-o para uma pesquisa. Brett retornou à lista de variáveis ​​aleatórias. Ela não estava lá. Ele olhou mais de perto a lista e notou que a lista de variáveis ​​aleatórias continha dados de campos de múltipla escolha. O campo que ele precisava para randomizar foi baseado em um campo calculado.

Brett sabia que Tyree estava trabalhando em outro projeto que aleatoriamente por campo computado, então ele entrou em contato com ele no Slack. “Como você codificou essa variável aleatória? A Medtech impede que isso aconteça?

"Estou falando de conferência, ligo para você mais tarde", escreveu Tyree.

Alguns minutos depois, Tyree ligou para Brett.

“Você precisa começar com dois campos. Vamos dizer. vamos chamá-los de $variable_choice , ou seja, uma pergunta de múltipla escolha e $variable_calced , ou seja, seu campo calculado. Quando você deseja criar uma variável que executa a seleção aleatória com base em um campo calculado, você diz à Medtech que essa variável aleatória é baseada em $variable_choice . Então você exclui $variable_choice e renomeia $variable_calced para $variable_choice

“Pare, o sistema permite que você faça isso, mas não permite que você randomize os campos calculados de nenhuma outra maneira? E ela não verifica?

"Espero que nada mude, e ela não começa a verificar isso até a conclusão do meu projeto", respondeu Tyree.

“Este estudo deve ocorrer em dez anos. E sua conclusão bem-sucedida depende se os desenvolvedores consideram esse truque um bug? ”

“Consegui encontrar apenas uma solução desse tipo. Deixe-me saber se você encontrar algo melhor.

Brett não satisfez tal invasão e voltou a estudar a documentação. Ele encontrou uma solução “melhor”: você pode criar um campo de múltipla escolha somente leitura com o único valor padrão - o valor do campo calculado. Infelizmente, o usuário pode inadvertidamente alterar a lista, respondendo a uma pergunta de múltipla escolha antes de calcular o valor do campo calculado.

No final, a única coisa que restava para Brett era fazer uma pausa, ir ao refeitório e comprar alguns cachorros-quentes.

A terceira história. Portabilidade e hardware


[Original]


Muitas luas atrás, quando os PCs tinham caixas de metal pesado e plástico, Matt e seu colega foram convidados a avaliar o pacote de software para a operação do departamento de vendas que estava por vir. Infelizmente, ele e seu colega trabalharam em escritórios diferentes na mesma cidade. Naquela época, ainda não existiam ferramentas eficazes de colaboração on-line; portanto, Matt regularmente precisava viajar para outro escritório, levando um PC com ele. Isso significava que cada vez que era necessário desconectar os cabos periféricos do gabinete 473, carregar o computador pelos corredores e descer as escadas, pegar um ônibus para chegar a outro escritório, no qual ele fazia tudo isso na ordem inversa. Às vezes, a organização incorreta do trabalho obrigava esse casal a trabalhar nos finais de semana, o que significa que eles carregam máquinas de trabalho para casa.

No processo, o disco rígido de 20 MB no computador de Matt transbordou. De seu escritório, ele enviou uma solicitação ao departamento de TI. Para atender a solicitação, foi designado o técnico de Gary, que depois de algum tempo apareceu no cubo de Matt, segurando um novo disco rígido e uma chave de fenda. Gary enviou Matt para um café para se concentrar em seu "paciente". Após uma pequena cirurgia, o PC de Matt ligou e trabalhou com um grande disco rígido.

Um dia antes do prazo final do projeto, Matt quase completou sua parte do trabalho. Ele tinha apenas que fazer algumas adições ao seu relatório, copiá-lo para disquetes e enviá-lo ao departamento de vendas. Devolvendo o PC ao cubo e conectando os fios, ele ligou a energia e ouviu um estalo. O PC estava morto e não mostrava sinais de vida.

Após uma ligação de pânico para o departamento de TI, Gary apareceu novamente em seu escritório com uma chave de fenda. Abrindo a caixa do PC, ele imediatamente gritou: “Espere um minuto! Você arrastou um computador para algum lugar?

Matt fez uma careta. Bem, sim. Essa é a coisa?

Sim, claro! Você não deveria ter feito isso! Gary começou a xingar. "O disco rígido começou a sair e colocou em curto tudo o que havia dentro!"

Matt se inclinou sobre Gary para ver por si mesmo o interior do computador. Ele imediatamente notou que o novo disco rígido estava "fixo" na fita.

“Pare! Que você não deveria ter feito isso! Matt apontou para um pedaço de fita adesiva. "Devo entrar em contato com seu supervisor por precaução?"

O rosto de Gary franziu o cenho. "Eles não me dão as fixações necessárias!

"Então encontre quem os tem!"

Dado o prazo iminente, com a permissão do chefe, Matt transferiu sua inscrição ainda mais. Quase imediatamente, a fita adesiva foi substituída por hardware genuíno. Ele nunca entendeu por que os funcionários do departamento de TI não tinham acesso ao equipamento necessário; ele sugeriu que era uma idéia brilhante de algum idiota economizar dinheiro. Matt só conseguia adivinhar que outras improvisações desesperadas faziam a infraestrutura de TI funcionar e quanto tempo elas passariam despercebidas se o PC dele não quebrasse.

A quarta história. É assim que o PL / SQL afeta seu cérebro.


[Original]

O eterno campeão entre as decisões mais estranhas e sem sucesso permanecerá para sempre o Oracle . Hoje, olhamos para um pequeno código PL / SQL.

PL / SQL é uma linguagem estranha, uma mistura de linguagem SQL e linguagem processual (processual) (linguagem) com orientação a objetos colada ao lado. A sintaxe é soberbamente capaz de criar a impressão de que foi desenvolvida na década de 1970, e cada nova função ou mudança de linguagem continua essa tradição.

A estrutura de cada módulo de código PL / SQL é baseada em bloco . Cada bloco é um espaço para nome independente. Em suma, sua anatomia é assim:

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

Se você estiver gravando um procedimento armazenado ou um manipulador de eventos, substitua a palavra-chave DECLARE por CREATE [OR REPLACE] . Você também pode aninhar blocos dentro de outros blocos, com bastante frequência pode ver o código estruturado desta maneira:

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

Sim, muito rapidamente começa a ficar confuso. E sim, se você deseja fornecer pelo menos uma manipulação de erros aproximadamente estruturada, deve começar a colocar blocos um no outro.

O idioma e o banco de dados têm outros recursos divertidos. Antes da versão 12c, eles não tinham um tipo de coluna IDENTITY . Nas versões anteriores, era necessário usar o objeto SEQUENCE e escrever procedimentos ou manipuladores de eventos que executam numeração automática forçada. Normalmente, o operador SELECT INTO… foi usado para atribuir um valor a uma variável. Bônus: o Oracle SQL sempre exige que uma tabela seja especificada na instrução FROM , portanto, você deve usar uma tabela 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 neste contexto indica a linha para a qual estamos numerando automaticamente. Nas versões mais antigas do Oracle, essa era a maneira "usual" de criar colunas com numeração automática. Benoit descobriu outra maneira ligeiramente menos comum de fazer a mesma operação:

 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; 

Muita coisa está acontecendo aqui. Primeiro, observe que a seção DECLARE contém a instrução CURSOR . Os cursores permitem percorrer os registros. Eles são muito caros e, no mundo Oracle, é um recurso que precisa ser liberado.

Este manipulador de eventos (gatilho) usa um bloco aninhado sem motivo. Ele também usa a variável adicional pl_error_id , que pode ser dispensada.

Mas a parte realmente estranha é o bloco IF get_seq%NOTFOUND . Tudo é bem simples: verifica a condição de o cursor não retornar uma string. Para este cursor, isso não pode acontecer nem teoricamente , portanto as operações internas nunca são executadas. Uma sequência sempre retorna um valor. E isso é bom , dado o código que vai além.

raise_application_error é um análogo do throw no Oracle. Essa instrução aumenta a pilha de blocos executáveis ​​até encontrar a seção EXCEPTIONS para lidar com o erro. Observe que fechamos o cursor após esta declaração - ou seja, nunca fechamos o cursor. Os cursores, como mencionado acima, são caros e o Oracle apenas permite que um número limitado deles seja usado.

Aqui vemos um exemplo estranho de como um desenvolvedor tenta se defender contra um erro que não pode acontecer, de uma maneira que levará a novos erros ao longo do tempo.

A quinta história. Logins com criptografia dupla


[Original]

Criar autenticação para a API da Web é uma tarefa difícil , mas possui muitas soluções bem estabelecidas. O mais difícil é realmente escolher uma das várias opções, após as quais basta adicionar um componente.

Quando implementado corretamente, o sistema não depende do tipo de cliente. Eu posso acessar o serviço através de um navegador, em um cliente grosso ou através de cURL. Se implementado incorretamente, você obtém o que aconteceu com Amira .

Ela resolveu o problema de extrair as estatísticas de que precisava do back-end, mas não conseguiu descobrir o método de autenticação. Portanto, ela estudou o código front-end para entender como ele executa a autenticação:

 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 um lado, posso assumir que esse código é muito antigo, dado o document.loginForm usado para interações com elementos DOM. Por outro lado, o JSEncrypt foi lançado pela primeira vez em 2013, o que nos dá a faixa etária máxima.

Passamos os parâmetros de acesso ao back-end enviando o formulário, que, de acordo com o desenvolvedor do código, exigia limpeza - todos os & + na senha são substituídos, mas ... isso não é necessário, porque o formulário deve atender à solicitação POST e, além disso, criptografamos os dados .

Aqui está o que eu penso. O código é realmente muito antigo. O desenvolvedor o copiou de uma postagem no StackOverflow por volta de 2005, que não usava criptografia e POST formulários via POST . Ano após ano, pequenas alterações foram adicionadas a ele. mas o mecanismo subjacente nunca mudou.

Amira verificou o histórico e descobriu que a criptografia não era usada na versão anterior. challenge , MD5, , , .

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

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


All Articles