Páginas filhas
  • Integracao com o WebService do Totvs Mashups - Integração com Recaptcha

Versões comparadas

Chave

  • Esta linha foi adicionada.
  • Esta linha foi removida.
  • A formatação mudou.

Introdução

A utilização cada vez mais crescente do reCaptcha 2, serviço do Google que impossibilita que robôs sejam utilizados, para extrair dados de páginas da Web fez com que o mecanismo do TOTVS Mashup fosse aprimorado para tratar este tipo controle. Para isso foram feitas alterações no Web Service do Mashup para contemplar esta integração.

 

Como o mecanismo do reCaptcha 2 não pode ser tratado diretamente no servidor de Mashups, foram feitas alterações na API e nos Web Services do Mashup para permitir que o cliente do Mashup faça os devidos tratamentos necessários para a execução.

Pré-requisitos

O reCaptcha tem um mecanismo de controle baseado na Url do site que utiliza o serviço, com uma chave da API específica para esta Url. Com está combinação é possível simular a execução do reCaptcha como se estivesse no próprio site. Para isso é necessária a utilização de um web browser embutido que permita a injeção de HTML simulando uma Url específica. Como por exemplo o CEF (Chromium Embeeded Framework)  - https://en.wikipedia.org/wiki/Chromium_Embedded_Framework.

Parâmetro do Mashup (SOAData)

Foram criadas duas novas propriedades para a classe SOAData da API do Mashup. Estas propriedades quando estiverem preenchidas deverão ser utilizadas para a resolução do reCaptcha pelo cliente.

RecaptchaKey

Baseado no valor da propriedade RecaptchaKey, o cliente deverá gerar um HTML para executar o reCaptcha utilizando o browser embutido. Este HTML irá conter basicamente a chamada para o reCaptcha. O seguinte código pode ser utilizado como base para o HTML que será gerado, substituindo o valor [SITEKEY] pelo valor da propriedade retornado pelo Mashup.

Neste exemplo, quando o reCaptcha for resolvido a função recaptchaCallback será executada pela API do Google, devolvendo o valor da resposta do reCaptcha, que por sua vez, deverá ser devolvido como valor do parâmetro do Mashup.

Código

Bloco de código
languagexml
titleHTML
<!DOCTYPE html>
<html lang="pt-br">
<head>
   
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
   
    <meta name = "viewport" content = "width = device-width, initial-scale = 1.0, user-scalable = yes">
   
    
TOTVS
<title>TOTVS Mashups 
Recaptcha        
Recaptcha</title>
    <script src="https://www.google.com/recaptcha/api.js?hl=pt-BR" async defer></script>
    <script>
        function recaptchaCallback(resp) {
            recaptchaCallbackObj.solved(resp);
         };
    </script>
</head>
<body>
<input id="idCheckedReCaptcha" name="idCheckedReCaptcha" type="hidden" value="false">
<div class="g-recaptcha" data-callback="recaptchaCallback" data-sitekey="[SITEKEY]"
>
></div> 
</body>

RecaptchaUrl

Esta propriedade irá conter o endereço (Url) que deverá ser simulado pelo browser no momento da carga do HTML gerado utilizando o valor do RecaptchaKey.

...

A biblioteca CEFSharp permite a utilização da API do CEF na plataforma .NET. Ela possui implementações para Windows Forms, WPF e aplicação sem tela e está disponível no GitHub também como um pacote NuGet. O seguinte código cria um UserControl WindowsForms para resolução do reCaptcha em uma aplicação C#.

Código
Bloco de código
languagec#
titleC#
  /// <summary>

...

  /// Controle do Recaptcha

...

  /// </summary>

...

  public partial class SOARecaptchaControl : UserControl

...

  {

...

    /// <summary>

...

    /// Componente do navegador

...

    /// 

...

</summary>
    private ChromiumWebBrowser Browser;

...

    /// <summary>

...

    /// Callback do Javascript

...

    /// 

...

</summary>
    private RecaptchaCallback RecaptchaCallback;

...


    /// <summary>

...

    /// Html base para chamar o recaptcha

...

    /// 

...

</summary>
    private const string Html =

...


      "<!DOCTYPE html>" +
      "<html lang=\"pt-br\">" +
      "<head>" +
      "    <!-- V12-->" +
      "    <meta http-equiv=\"x-ua-compatible\" content=\"IE=9\">" +
      "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\"/>" +
      "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">" +
      "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">" +
      "    <title>Recaptcha Test</title>" +
      "    <script src=\"https://www.google.com/recaptcha/api.js?hl=pt-BR\" async defer></script>" +
      "    <script>" +
      "        function recaptchaCallback(resp) {" +
      "            recaptchaCallbackObj.solved(resp);" +
      "         };" +
      "    </script>" +
      "</head>" +
      "<body>" +
      "<input id=\"idCheckedReCaptcha\" name=\"idCheckedReCaptcha\" type=\"hidden\" value=\"false\">" +
      "<div class=\"g-recaptcha\" data-callback=\"recaptchaCallback\" data-sitekey=\"[SITEKEY]\"></div>" +
      "</body>";

    public SOARecaptchaControl()
    {
      InitializeComponent();
    }

    /// <summary>
    /// Chave do 

...

Recaptcha (RecaptchaKey)

...

    /// 

...

</summary>
    public string SiteKey = "6LeP2TQUAAAAACab2AAHziJUCqPwLmBILdrjhJ54";

...

    /// <summary>

...

    /// Url do Site 

...

(RecaptchaUrl)

...

    /// 

...

</summary>
    public string SiteUrl = "https://www.receita.fazenda.gov.br/Aplicacoes/SSL/ATCTA/CPF/ConsultaSituacao/ConsultaPublica.asp";

...


    /// <summary>

...

    /// Resposta do Recaptcha

...

    /// 

...

</summary>
    public string RecaptchaResponse = null;

...

    private static void InitializeCefSharp()

...

    {

...

      if (!Cef.IsInitialized)

...

        LoadCefSharp();

...

    }

...


    [MethodImpl(MethodImplOptions.NoInlining)]

...

    private static void LoadCefSharp()

...

    {

...

      // inicializa as configurações do chromium...

...

      CefSettings settings = new CefSettings();

...

      settings.BrowserSubprocessPath = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase,

...

                                       Environment.Is64BitProcess ? "x64" : "x86",

...

                                       "CefSharp.BrowserSubprocess.exe");

...


      // inicializa...

...

      Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: null);

...


      // aguarda a inicialização...

...

      while (!Cef.IsInitialized)

...

        Application.DoEvents();

...

    }

...


    private void SOARecaptchaControl_Load(object sender, EventArgs e)

...

    {

...

      // inicializa...

...

      InitializeCefSharp();

...


      // cria o browser...

...

      this.Browser = new ChromiumWebBrowser("about:blank");

...

      this.Browser.Dock = DockStyle.Fill;

...


      // inicializa o callback...

...

      this.RecaptchaCallback = new RecaptchaCallback(this.Browser);

...

      this.RecaptchaCallback.OnSolved += new EventHandler(this.OnRecaptchaSolved);

...

      this.Browser.RegisterJsObject("recaptchaCallbackObj", this.RecaptchaCallback);

...

      // adiciona no UserControl...

...

      this.Controls.Add(this.Browser);

...

    }

...


    private void OnRecaptchaSolved(object sender, EventArgs e)

...

    {

...

      // grava a resposta...

...

      this.RecaptchaResponse = this.RecaptchaCallback.Response;

...

    }

...


    private void OnInitialized()

...

    {

...

      System.Threading.Thread.Sleep(500);

...

      if (this.InvokeRequired)

...

        this.Invoke(new Action(this.OnInitialized));

...

      else

...

        this.Browser.LoadString(Html.Replace("[SITEKEY]", this.SiteKey), this.SiteUrl);

...

    }

...


  }

...

  internal class RecaptchaCallback

...

  {

...

    private ChromiumWebBrowser Browser = null;

...

    public RecaptchaCallback(ChromiumWebBrowser browser)

...

    {

...

      this.Browser = browser;

...

    }

...


    /// <summary>

...

    /// Chave da resposta do Recaptcha

...

    /// 

...

</summary>
    public string Response { get; private set; }

...


    /// <summary>

...

    /// Evento disparado ao resolver o Recaptcha

...

    /// 

...

</summary>
    public event EventHandler OnSolved;

...

    public void solved(string response)

...

    {

...

      // guarda a resposta...

...

      this.Response = response;

...

      // chama o evento...

...

      if (this.OnSolved != null)

...

        this.OnSolved(this, EventArgs.Empty);

...

    }

...

  }

Importante

O mecanismo do reCaptcha utiliza controles adicionais para verificar se realmente é uma pessoa que está utilizando. Por isso ele "facilita" a resolução do reCaptcha quando o usuário está logado em uma conta do Google. Este controle é feito através de Cookies que são repassados para o mecanismo do reCaptcha quando o Script é carregado. Para facilitar a resolução do reCaptcha, é recomendado que os Cookies sejam armazenados e que o usuário faça a autenticação no Google através da página accounts.google.com. 

Para fazer o armazenamento dos Cookies no CefSharp, ao fazer a inicialização do Browser defina o valor da propriedade CachePath da classe CefSettings utilizada na inicialização para o diretório onde os dados de navegação do usuário serão armazenados.

 

Também é possível fazer a leitura dos Cookies da url www.google.com, diretamente dos navegadores instalados no sistema, sugerindo que o usuário faça o login na sua conta do Google para facilitar a utilização deste recurso e "injetá-los" na requisição do Chromium. 

Exemplo de extração de Cookies: https://www.codeproject.com/Articles/330142/Cookie-Quest-A-Quest-to-Read-Cookies-from-Four-Pop