如何在我的客户端应用程序中处理第三方站点上的验证码

本文关键字:站点 第三方 验证 处理 我的 客户端 应用程序 | 更新日期: 2023-09-27 18:37:19

我很好奇人们如何为没有公共 API 的网站构建第三方应用程序,但我真的找不到任何关于这个主题的教程。所以我决定试一试。我创建了一个简单的桌面应用程序,该应用程序使用 HttpClient 将 GET 请求发送到我经常使用的网站,然后分析响应并在 WPF 窗口中显示数据。这种方法效果很好(可能是因为该网站相当简单)。

但是,今天我尝试从不同的地方运行我的应用程序,并且不断收到 403 错误以响应我的应用程序的请求。事实证明,我使用的网络是通过VPN服务器,而我尝试访问的站点使用CloudFlare作为保护层,这显然迫使VPN用户输入reCaptcha才能访问目标站点。

var baseAddress = new Uri("http://www.cloudflare.com");
using (var client = new HttpClient() { BaseAddress = baseAddress })
{
   var message = new HttpRequestMessage(HttpMethod.Get, "/");
   //this line returns CloudFlare home page if I use regualr network and reCaptcha page, when I use VPN
   var result = await client.SendAsync(message);
   //this line throws if I use VPN (403 Forbidden)
   result.EnsureSuccessStatusCode();
}

现在的问题是:在客户端应用程序中处理CloudFlare保护的正确方法是什么?我是否必须像 Web 浏览器一样在我的应用程序中显示 reCaptcha?我是否必须设置任何特定的标头才能获得正确的响应而不是 403?欢迎任何提示,因为这对我来说是一个全新的领域。

附言我用 C# 编写,因为这是我最熟悉的语言,但我不介意使用任何其他语言,只要他们回答了这个问题。

如何在我的客户端应用程序中处理第三方站点上的验证码

我想

,一种方法是在客户端应用程序之外的Web浏览器中处理验证码。

  1. 解析响应以查看它是否是验证码页面。
  2. 如果是 - 在浏览器中打开此页面。
  3. 让用户在那里解决验证码。
  4. 从浏览器的cookie存储中获取CloudFlare cookie。您将需要__cfduid(用户ID)和cf_clearance(解决验证码的证明)。
  5. 将这些 Cookie 附加到客户端应用程序发送的请求。
  6. 在接下来的 24 小时内正常使用应用程序(直到 CloudFlare cookie 过期)。

现在这里最难的部分是(4)。手动复制粘贴cookie以使我的问题中的代码片段与VPN一起使用很容易:

var baseAddress = new Uri("http://www.cloudflare.com");
var cookieContainer = new CookieContainer();
using (var client = new HttpClient(new HttpClientHandler() { CookieContainer = cookieContainer } , true) { BaseAddress = baseAddress })
{
    var message = new HttpRequestMessage(HttpMethod.Get, "/");
    //I've also copy-pasted all the headers from browser
    //some of those might be optional
    message.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0");
    message.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
    message.Headers.Add("Accept-Encoding", "gzip, deflate" });
    message.Headers.Add("Accept-Language", "en-US;q=0.5,en;q=0.3");
    //adding CloudFlare cookies
    cookieContainer.Add(new Cookie("__cfduid", "copy-pasted-cookie-value", "/", "cloudflare.com"));
    cookieContainer.Add(new Cookie("cf_clearance", "copy-pasted-cookie-value", "/", "cloudflare.com"));
    var result = await client.SendAsync(message);
    result.EnsureSuccessStatusCode();
}
但我认为自动化获取 cookie

的过程将是一项棘手的任务,因为不同的浏览器将 cookie 存储在不同的地方和/或格式。更不用说您需要使用外部浏览器才能使用此方法才能工作的事实,这真的很烦人。不过,这是需要考虑的事情。

"为没有公共 API 的网站构建第三方应用程序"的答案是,即使某些软件供应商没有公共 API,他们也有合作伙伴计划。

很好的例子是Netflix,他们曾经有一个公共API。启用公共 API 时开发的一些应用程序允许继续使用 api。

在你的方案中,客户端应用充当 Web 爬网程序(下载 html 内容并尝试分析信息)。您要做的是抓取Cloudfare数据,这些数据并不意味着由第三方应用程序(机器人)抓取。从云方面来看,他们已经做了正确的事情来拥有一个可以防止自动请求的验证码。

此外,如果您尝试以高频率(请求/秒)发送请求,并且Cloudfare具有威胁检测机制,则您的IP地址将被阻止。我假设他们已经确定了您尝试使用的VPN服务器IP地址并将其列入黑名单,这就是您获得403的原因。

基本上,您完全依赖于您尝试通过客户端应用程序访问的Cloudfare页面中的安全漏洞。这是一种黑客Cloudfare(做Cloudfare限制的事情),我不推荐。

如果你有一个很酷的想法,最好联系他们的开发团队并讨论一下。

如果您仍然需要它,我遇到了同样的问题,并在 2 年前提出了以下解决方案。

它使用 C# WebBrowser 类打开受 Cloudflare 保护的网页,等待大约 6 秒,以便 CloudFlare 保存清除 cookie,然后程序将 cookie 保存到磁盘。

您需要一个支持 JavaScript 的浏览器,例如 C# WebBrowser 类,因为 Cloudflare 验证码页面需要 javascript 才能运行并倒计时以保存 cookie,任何其他尝试都将失败。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Net;
using System.Threading;
namespace kek
{
    public partial class Form1 : Form
    {
        [DllImport("wininet.dll", SetLastError = true)]
        public static extern bool InternetGetCookieEx(string url, string cookieName, StringBuilder cookieData, ref int size, Int32 dwFlags, IntPtr lpReserved);
        private Uri Uri = new Uri("http://www.my-cloudflare-protected-website.com");
        private const Int32 InternetCookieHttponly = 0x2000;
        private const Int32 ERROR_INSUFFICIENT_BUFFER = 0x7A;
        public Form1()
        {
            InitializeComponent();
            webBrowser1.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.webBrowser1_DocumentCompleted);
            webBrowser1.Navigate(Uri, null, null, "User-Agent: kappaxdkappa'r'n"); //user-agent needs to be set another way if that doesnt work
        }
        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            int waitTime = 0;
            if(webBrowser1.DocumentTitle.Contains("We are under attack")) //check what string identifies the unique cloudflare captcha page and put it here
            {
                waitTime = 6000;
            }
            Task.Run(async () =>
            {
                await Task.Delay(waitTime); //cookie can be saved right away, but the waiting period might not have passed yet
                String cloudflareCookie = GetCookie(Uri, "cf_clearance");
                if (!String.IsNullOrEmpty(cloudflareCookie))
                {
                    System.IO.StreamWriter file = new System.IO.StreamWriter("c:''CFcookie.blob"); //save to %appdata%'MyProgram'Cookies'clearence.blob
                    file.Write(cloudflareCookie);
                    file.Close();
                }
            });
        }
        String GetCookie(Uri uri, String cookieName)
        {
            int datasize = 0;
            StringBuilder cookieData = new StringBuilder(datasize);
            InternetGetCookieEx(uri.ToString(), cookieName, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero);
            if (Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER && datasize > 0)
            {
                cookieData = new StringBuilder(datasize);
                if (InternetGetCookieEx(uri.ToString(), cookieName, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
                {
                    if (cookieData.Length > 0)
                    {
                        CookieContainer container = new CookieContainer();
                        container.SetCookies(uri, cookieData.ToString());
                        return container.GetCookieHeader(uri);
                    }
                }
            }
            return String.Empty;
        }
    }
}

一些注意事项:

  • 使用更好的用户代理
  • cookie 也保存到磁盘,因为我需要它来做一些事情还。不确定内置浏览器是否保存了 cookie 以供下次使用时间,但如果没有,这样您就可以简单地再次加载它。
  • 将"我们受到攻击"短语更改为标识的短语您尝试绕过的 CF 验证码页面。
  • __cfduid饼干不是必需

编辑:抱歉,在阅读此处的其他答案后,我非常专注于Cloudflare本身,以至于我没有注意到您需要绕过有时在Cloudflare页面上找到的Recaptcha。我的代码可以在浏览器和 cookie 部分为您提供一些帮助,但至少现在您将很难解决 Recaptcha。几周前,他们使它变得更加困难。我可以建议编译您自己的Firefox版本,然后通过点击复选框自动解决验证码。如果您没有获得简单的验证码,则需要为用户显示它。请注意,您还需要随机化浏览器的行为以及单击复选框的方式,否则它会将您检测为机器人。