如何在我的客户端应用程序中处理 third-party 站点上的重新验证
How to handle recaptcha on third-party site in my client application
我很好奇人们如何为 没有 public API 的网站构建 third-party 应用程序,但我真的找不到关于这个主题的任何教程.所以我决定试一试。我创建了一个简单的桌面应用程序,它使用 HttpClient
向我经常使用的站点发送 GET 请求,然后解析响应并在我的 WPF window 中显示数据。这种方法效果很好(可能是因为网站相当简单)。
但是,今天我尝试从不同的地方 运行 我的应用程序,并且我不断收到 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 保护的正确方法是什么?我是否必须像网络浏览器一样在我的应用程序中显示 reCaptcha?我是否必须设置任何特定的 headers 才能获得正确的响应而不是 403?欢迎任何提示,因为这对我来说是一个全新的领域。
P.S。我用 C# 编写,因为这是我最熟悉的语言,但我不介意回答者使用任何其他语言,只要他们回答了问题。
我想,一种解决方法是在客户端应用程序之外的 Web 浏览器中处理验证码。
- 解析响应以查看它是否是验证码页面。
- 如果是 - 在浏览器中打开此页面。
- 让用户在那里解决验证码。
- 从浏览器的 cookie 存储中获取 CloudFlare cookie。您将需要
__cfduid
(用户 ID)和 cf_clearance
(解决验证码的证明)。
- 将这些 cookie 附加到客户端应用程序发送的请求中。
- 在接下来的 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 的过程将是一项棘手的任务,因为不同的浏览器以不同的 and/or 格式存储 cookie。更不用说您需要使用外部浏览器才能使这种方法起作用,这真的很烦人。不过,还是要考虑一下。
对 "build third-party apps for sites with NO public APIs" 的回答是,即使某些软件供应商没有 public api,他们也有合作伙伴计划。
Netflix 就是一个很好的例子,他们曾经有一个 public api。一些在 Public Api 启用时开发的应用程序允许继续 api 使用。
在您的场景中,您的客户端应用充当网络爬虫(下载 html 内容并尝试解析信息)。您要做的是抓取 Cloudfare 数据,该数据不应由第三方应用程序(机器人)抓取。从 cloudfare 方面来看,他们做了正确的事情来拥有一个阻止自动请求的验证码。
此外,如果您尝试以高频率发送请求 (requests/sec),并且如果 Cloudfare 具有威胁检测机制,您的 IP 地址将被阻止。我假设他们已经确定了您尝试使用的 VPN 服务器 IP 地址并将其列入黑名单,这就是您收到 403 的原因。
基本上,您完全依赖于您尝试通过客户端应用程序访问的 Cloudfare 页面中的安全漏洞。这是我不推荐的黑客 Cloudfare(做一些 cloudfare 限制的事情)。
如果您有一个很棒的想法,最好联系他们的开发团队并进行讨论。
如果您仍然需要它,我在 2 年前遇到了同样的问题并提出了以下解决方案。
它使用 C# WebBrowser class 打开受 Cloudflare 保护的网页,等待大约 6 秒,以便 CloudFlare 保存清除 cookie,然后程序将 cookie 保存到磁盘。
您需要一个支持 javascript 的浏览器,例如 C# WebBrowser class,因为 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
时间,但如果没有,您可以通过这种方式重新加载它。
- 将 "We are under attack" 短语更改为标识的短语
您试图绕过的 CF 验证码页面。
- __cfduid cookie 不需要 afaik
编辑:抱歉,在阅读了此处的其他答案后,我非常专注于 Cloudflare 本身,以至于我没有注意到您需要绕过有时在 Cloudflare 页面上找到的 Recaptcha。我的代码可以在浏览器和 cookie 部分为您提供一些帮助,但您将很难解决 Recaptcha,至少现在是这样。几周前,他们变得更加困难。我可以推荐编译你自己的 Firefox 版本,然后通过点击复选框自动解决验证码。如果你没有得到那个简单的验证码,那么你需要为用户显示它。请注意,您还需要随机化浏览器的行为以及点击复选框的方式,否则它会将您检测为机器人。
我很好奇人们如何为 没有 public API 的网站构建 third-party 应用程序,但我真的找不到关于这个主题的任何教程.所以我决定试一试。我创建了一个简单的桌面应用程序,它使用 HttpClient
向我经常使用的站点发送 GET 请求,然后解析响应并在我的 WPF window 中显示数据。这种方法效果很好(可能是因为网站相当简单)。
但是,今天我尝试从不同的地方 运行 我的应用程序,并且我不断收到 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 保护的正确方法是什么?我是否必须像网络浏览器一样在我的应用程序中显示 reCaptcha?我是否必须设置任何特定的 headers 才能获得正确的响应而不是 403?欢迎任何提示,因为这对我来说是一个全新的领域。
P.S。我用 C# 编写,因为这是我最熟悉的语言,但我不介意回答者使用任何其他语言,只要他们回答了问题。
我想,一种解决方法是在客户端应用程序之外的 Web 浏览器中处理验证码。
- 解析响应以查看它是否是验证码页面。
- 如果是 - 在浏览器中打开此页面。
- 让用户在那里解决验证码。
- 从浏览器的 cookie 存储中获取 CloudFlare cookie。您将需要
__cfduid
(用户 ID)和cf_clearance
(解决验证码的证明)。 - 将这些 cookie 附加到客户端应用程序发送的请求中。
- 在接下来的 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 的过程将是一项棘手的任务,因为不同的浏览器以不同的 and/or 格式存储 cookie。更不用说您需要使用外部浏览器才能使这种方法起作用,这真的很烦人。不过,还是要考虑一下。
对 "build third-party apps for sites with NO public APIs" 的回答是,即使某些软件供应商没有 public api,他们也有合作伙伴计划。
Netflix 就是一个很好的例子,他们曾经有一个 public api。一些在 Public Api 启用时开发的应用程序允许继续 api 使用。
在您的场景中,您的客户端应用充当网络爬虫(下载 html 内容并尝试解析信息)。您要做的是抓取 Cloudfare 数据,该数据不应由第三方应用程序(机器人)抓取。从 cloudfare 方面来看,他们做了正确的事情来拥有一个阻止自动请求的验证码。
此外,如果您尝试以高频率发送请求 (requests/sec),并且如果 Cloudfare 具有威胁检测机制,您的 IP 地址将被阻止。我假设他们已经确定了您尝试使用的 VPN 服务器 IP 地址并将其列入黑名单,这就是您收到 403 的原因。
基本上,您完全依赖于您尝试通过客户端应用程序访问的 Cloudfare 页面中的安全漏洞。这是我不推荐的黑客 Cloudfare(做一些 cloudfare 限制的事情)。
如果您有一个很棒的想法,最好联系他们的开发团队并进行讨论。
如果您仍然需要它,我在 2 年前遇到了同样的问题并提出了以下解决方案。
它使用 C# WebBrowser class 打开受 Cloudflare 保护的网页,等待大约 6 秒,以便 CloudFlare 保存清除 cookie,然后程序将 cookie 保存到磁盘。
您需要一个支持 javascript 的浏览器,例如 C# WebBrowser class,因为 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 时间,但如果没有,您可以通过这种方式重新加载它。
- 将 "We are under attack" 短语更改为标识的短语 您试图绕过的 CF 验证码页面。
- __cfduid cookie 不需要 afaik
编辑:抱歉,在阅读了此处的其他答案后,我非常专注于 Cloudflare 本身,以至于我没有注意到您需要绕过有时在 Cloudflare 页面上找到的 Recaptcha。我的代码可以在浏览器和 cookie 部分为您提供一些帮助,但您将很难解决 Recaptcha,至少现在是这样。几周前,他们变得更加困难。我可以推荐编译你自己的 Firefox 版本,然后通过点击复选框自动解决验证码。如果你没有得到那个简单的验证码,那么你需要为用户显示它。请注意,您还需要随机化浏览器的行为以及点击复选框的方式,否则它会将您检测为机器人。