Às vezes, torna-se necessário transferir dados entre um aplicativo em execução no navegador e um programa em execução no mesmo sistema em que o navegador está sendo executado. Isso pode ser necessário, por exemplo, se precisarmos trabalhar com equipamentos conectados localmente. Leitor de cartão inteligente, chave de criptografia de hardware e assim por diante.

Imagem daqui
Os primeiros a serem lembrados são três maneiras de resolver esse problema:
- Faça com as ferramentas do navegador ou escreva plugins para elas
- Organizar a troca de dados por meio do back-end, atuando como intermediário
- Adicione um serviço HTTP ao programa e acesse-o diretamente no navegador
O terceiro item parece bom, permite remover a autorização no programa, não requer nenhuma interface do usuário. Vamos tentar implementá-lo escrevendo um programa em C # no .NET Framework 4. Como estamos falando do .NET, a solução será apenas para Windows (XP e mais recente). Faremos o aplicativo da web em angular.
Por que não 1 e 2?
O primeiro item definitivamente trará muita dor, você terá que suportar navegadores separadamente, você pode fazer muito longe de tudo nos plug-ins de navegadores. No entanto, teoricamente, é possível trabalhar com cartões inteligentes por meio de plugins. Mas você precisa de uma maneira mais simples.
O segundo ponto é fácil de implementar, mas para esse esquema, você precisará autorizar não apenas no site, mas também no aplicativo local. Isso significa que será necessário algum tipo de interface, mas ao alterar a senha, também será necessária uma nova autorização no programa. Além disso, nas redes corporativas, haverá problemas adicionais com a rede, geralmente eles têm acesso à Internet por meio de proxies com filtragem e autorização severas, você também precisa criar uma interface para configurar os proxies e nem sempre pode se livrar das configurações automáticas. Será mais difícil para um usuário longe da TI trabalhar com isso; criaremos mais trabalho de suporte técnico. Obviamente, você pode criar um pacote de instalação individualmente para cada usuário para remover a necessidade de autorização primária, mas isso só aumentará os problemas.
O que o HTTPS tem a ver com isso?
Quando um site é executado em HTTPS, os navegadores bloqueiam o download de conteúdo ativo usando HTTP. No entanto, de acordo com a lógica das coisas, os navegadores devem considerar a solicitação à máquina local via HTTP como segura e não devem bloqueá-la. Isso acabou não sendo bem assim.
A tabela mostra os resultados de um pequeno estudo do comportamento dos navegadores na plataforma Windows:
A tabela mostra o comportamento dos navegadores ao tentar fazer uma solicitação no endereço apropriado. Os navegadores no mecanismo Chromium se comportam de maneira semelhante ao Chrome e o comportamento do Edge 44 é semelhante ao do IE 11. Um certificado válido é emitido para HTTPS, assinado com um certificado raiz autoassinado. O comportamento para https://127.0.0.1 e https: // localhost é o mesmo, apenas para 127.0.0.1, você também precisa emitir um certificado, e raramente são encontrados certificados para endereços IP, então vamos pular este ponto.
Tudo funciona no Chrome. O Chrome e o IE usam o armazenamento de certificados do sistema; portanto, o HTTPS também funciona neles. O Firefox usa seu próprio repositório de certificados, portanto, não confia em nosso certificado autoassinado. O Firefox e o IE não confiam no nome do host local, e isso mesmo, porque ninguém garante que o problema seja resolvido para 127.0.0.1 (embora eles possam verificá-lo como o Chrome).
O principal problema: o IE não permite acessar o programa via HTTP. Então, mexa com certificados que não podemos evitar.
Para trabalhar com navegadores, você também precisará especificar os cabeçalhos corretos de Controle de Acesso - Permitir Origem, Métodos de Controle de Acesso - Permitir, Cabeçalhos de Controle de Acesso - Permitir Cabeçalhos ( CORS ) no programa.
Certificado SSL
Você pode criar um registro DNS para o seu domínio, por exemplo local.example.com, que será resolvido para 127.0.0.1. Emita um certificado SSL para este domínio, distribua-o com o programa. Você precisará distribuir a chave privada deste certificado com o programa. Isso é completamente inadequado. E o certificado no programa também precisará ser atualizado.
O IE não confiará em um certificado SSL autoassinado, ele deve ser assinado com um certificado raiz confiável (e pode ser autoassinado).
Você pode gerar um certificado raiz e um certificado SSL e distribuí-los com o programa, adicionando ao armazenamento de certificados local. Parece inseguro. E também pode ser necessário revogar ou renovar o certificado. Portanto, geraremos certificados com chaves diretamente no computador do usuário no primeiro início do programa.
Criando certificados em c #
Para o .NET, existe uma biblioteca BouncyCastle que pode fazer tudo o que precisamos. O único problema é que, para adicionar um certificado à loja, você precisará solicitar um aumento de privilégios. Você também precisará de direitos elevados para usar o netsh para proteger o certificado em uma porta específica do sistema.
netsh http add sslcert ipport=0.0.0.0:{PORT} certhash={certThumbprint}
No exemplo, o método RegisterSslOnPort na classe SslHelper faz esse trabalho.
Serviço HTTP no programa C #
Para criar um servidor HTTP (S) leve, usamos a biblioteca Nancy . Nancy é uma estrutura da Web leve para .NET, simples e fácil de usar. Muito foi escrito sobre ele, inclusive sobre Habré . Graças ao módulo Nancy.SelfHosting, podemos hospedar nosso aplicativo sem usar o IIS.
Por exemplo, vamos criar um terminal que lida com a adição de dois números. É importante aqui definir os cabeçalhos CORS corretos, caso contrário, o navegador não executará uma solicitação para nossa API.
Nancymodule public class CalcNancyModule : NancyModule { public CalcNancyModule() {
Adicione a inicialização do Nancy ao nosso aplicativo e estamos prontos para a batalha.
Inicialização de Nancy var hostConfigs = new HostConfiguration(); hostConfigs.UrlReservations.CreateAutomatically = true; hostConfigs.RewriteLocalhost = false; var uris = new Uri[] { new Uri($"http://localhost:{HTTPPORT}"), new Uri($"http://127.0.0.1:{HTTPPORT}"), new Uri($"https://localhost:{HTTPSPORT}") }; using (var host = new NancyHost(hostConfigs, uris)) { host.Start(); }
Na primeira inicialização, você precisa gerar certificados e colocá-los na loja, solicitando os direitos apropriados. A classe SslHelper é usada para essas manipulações, nas quais o único método público CheckOrCreateCertificates executa o trabalho. Como parâmetros, os certificados SubjectName são transmitidos a ele. O método verifica se os certificados necessários estão disponíveis e o sistema, se não, os cria.
Para simular trabalho árduo e longos atrasos no exemplo, adicione Thread.Sleep (1000) às nossas chamadas de API.
Nesta aplicação está pronta para ser executada, vá para a web.
Aplicação web
Como você pode ver na tabela de comportamento do navegador, um ponto de extremidade não pode ser dispensado; pelo menos dois devem ser usados:
Em um aplicativo da web, precisamos determinar se estamos no IE (ou Edge) - use HTTPS, se não - HTTP. Você pode torná-lo mais confiável e não descobrir em qual navegador estamos, mas tente executar uma solicitação para o método GET / Calc da nossa API; se a solicitação for bem-sucedida, trabalharemos; caso contrário, tentaremos outro protocolo.
Tudo isso é necessário apenas se o próprio aplicativo da Web usar HTTPS, pois ao usar o protocolo HTTP, os navegadores não impõem restrições às solicitações, apenas os cabeçalhos CORS corretos.
No aplicativo angular, crie um serviço InteractionService que verifique a disponibilidade do terminal local primeiro via HTTP e depois por HTTPS. A verificação é realizada pelo método checkAvailability e o resultado do teste está disponível quando você assina a variável $ disponível do tipo BehaviorSubject com o valor inicial false.
Adicionamos o trabalho de adicionar números ao componente AppComponent. Quando você clica no botão “Calcular”, o aplicativo da Web faz uma solicitação para GET / Calc / Add? Num1 = {num1} & num2 = {num2}. A resposta ou o erro é exibido no campo Resultado.
Ao depurar, mesmo via HTTPS, você pode não perceber problemas, pois o domínio para solicitações será o mesmo - localhost. Portanto, você precisa testar o aplicativo com um nome de domínio diferente.
Para simplificar o trabalho de implantar um aplicativo da Web o máximo possível, usamos o serviço https://stackblitz.com , este é um IDE da web para angular e não apenas com uma amostra do VSCode. O aplicativo finalizado está disponível no link .
E você pode digitar o código aqui .
O aplicativo não funcionará interativamente no stackblitz, você precisará abri-lo em uma guia privada separada ou em outro navegador em https://angular-pfwfrm.stackblitz.io .
Como tentar?
O aplicativo da web é convenientemente iniciado usando o stackblitz, simplesmente clicando no link https://angular-pfwfrm.stackblitz.io .
Você pode executar o aplicativo Web localmente.
Para isso você precisaPara fazer isso, você precisa clonar o repositório:
git clone https://github.com/jdtcn/InteractionExample.git cd InteractionExample
na pasta AngularWebApp, você precisa executar os comandos:
npm install ng serve --ssl true
O aplicativo da Web estará disponível em https: // localhost: 4200 /
O aplicativo local pode ser compilado a partir do exemplo (abra CsClientApp.sln na pasta CsClientApp) usando o Visual Studio e execute, ou use o script para o programa LINQPad .
Se você é um desenvolvedor .NET e não usa o LINQPad , leia sobre isso, uma coisa indispensável no desenvolvimento. Para executar o exemplo, você precisa abrir o script no LINQPad'e (na primeira vez em que precisa executar o LINQPad com direitos de administrador para que os certificados sejam instalados) e instalar os pacotes nouget BouncyCastle, Nancy, Nancy.Hosting.Self e, em seguida, execute o script. Depois disso, você pode clicar no botão "Calcular" no aplicativo Web e obter o resultado da operação.
Segurança
É importante formar corretamente os cabeçalhos do CORS em um aplicativo real para que vilões de outros sites não possam acessar nosso programa. Se o vilão tiver a oportunidade de trabalhar com os privilégios do usuário em seu computador e ignorar a verificação do CORS, ele poderá fazer tudo o que o nosso programa pode fazer.
De qualquer forma, o programa deve funcionar com direitos mínimos e, se fizer algo sensível aos documentos, você precisará adicionar pedidos de confirmação de operações.
Conclusão
A tarefa aparentemente simples acabou sendo bastante volumosa e até exigindo muletas adicionais para trabalhar com certificados.
Essa abordagem teve um bom desempenho em uma aplicação real. Obviamente, para usar o código do exemplo, você precisa adicionar o tratamento de erros normal.
É conveniente solicitar elevação de privilégios ao instalar o programa, usando o InnoSetup é fácil fazer isso e passar o atributo necessário na primeira execução do programa. Além disso, antes da instalação, é conveniente verificar a presença do .NET 4 e instalá-lo, se não estiver instalado.
Ninguém no Virustotal reage a esse programa, mas eu gostaria! Mas se você montar o pacote de instalação no InnoSetup, alguns antivírus de terceira categoria começarão a trabalhar nele. Isso ajuda a se livrar da assinatura do instalador com o certificado de assinatura de código.
A atualização automática do programa aqui está nos bastidores, mas certamente não será supérflua em um aplicativo real. Squirrel é adequado para gerenciar atualizações automáticas. Também é conveniente usar o esquilo para remover nossos certificados do sistema quando você excluir o programa.
Código de exemplo postado no GitHub .
Obrigado pela atenção!