You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Delphi THTTPClient HTTP2请求退化为HTTP1遭Cloudflare拦截排查

Delphi THTTPClient访问Cloudflare保护的HTTP2服务器失败问题

问题场景

在Delphi Rad Studio 12 + Windows 10 Home Single Language 22H2环境下,使用THTTPClient访问仅支持HTTP2协议的Cloudflare保护服务器时,请求被拦截并返回403状态,响应协议显示为HTTP/1.1。但Postman及Chrome、Edge、Firefox浏览器均可正常获取目标验证码JSON数据,说明代码存在配置或行为模拟缺陷。

现有代码

procedure TForm1.Button1Click(Sender: TObject);
var
  Http:THTTPClient;
  CM:TCookieManager;
  url,Sver:String;
  Res:IHTTPResponse;
begin
  CM:=TCookieManager.Create;
  Http:=THTTPClient.Create;
  try
    Http.cookieManager:=cm;
    http.ProtocolVersion:=THTTPProtocolVersion.HTTP_2_0;
    url:='https://service.sipd.kemendagri.go.id/auth/captcha/new';
    Res:=http.Get(url,nil);
    case Res.Version of
      THTTPProtocolVersion.HTTP_1_0: Sver:='HTTP_1_0';
      THTTPProtocolVersion.HTTP_1_1: Sver:='HTTP_1_1';
      THTTPProtocolVersion.HTTP_2_0: Sver:='HTTP_2_0';
      else Sver:='UNKNOWN_HTTP';
    end;
    Mlog.clear;
    Mlog.lines.add(Format('Result = %d:: %s',[Res.StatusCode,Res.StatusText]));
    Mlog.lines.add(Format('Protocol = %s',[Sver]));
    MOutput.clear;
    MOutput.text:=Res.ContentAsString;
  finally
    http.free;
    CM.free;
  end;
end;

运行日志

Result = 403:: 
Protocol = HTTP_1_1

拦截响应内容

<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js ie6 oldie" lang="en-US"> <![endif]-->
<!--[if IE 7]>    <html class="no-js ie7 oldie" lang="en-US"> <![endif]-->
<!--[if IE 8]>    <html class="no-js ie8 oldie" lang="en-US"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en-US"> <!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta charset="UTF-8" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link rel="stylesheet" id="cf_styles-css" href="/cdn-cgi/styles/cf.errors.css" />
<!--[if lt IE 9]><link rel="stylesheet" id='cf_styles-ie-css' href="/cdn-cgi/styles/cf.errors.ie.css" /><![endif]-->
<style>body{margin:0;padding:0}</style>


<!--[if gte IE 10]><!-->
<script>
  if (!navigator.cookieEnabled) {
    window.addEventListener('DOMContentLoaded', function () {
      var cookieEl = document.getElementById('cookie-alert');
      cookieEl.style.display = 'block';
    })
  }
</script>
<!--<![endif]-->

</head>
<body>
  <div id="cf-wrapper">
    <div class="cf-alert cf-alert-error cf-cookie-error" id="cookie-alert" data-translate="enable_cookies">Please enable cookies.</div>
    <div id="cf-error-details" class="cf-error-details-wrapper">
      <div class="cf-wrapper cf-header cf-error-overview">
        <h1 data-translate="block_headline">Sorry, you have been blocked</h1>
        <h2 class="cf-subheadline"><span data-translate="unable_to_access">You are unable to access</span> kemendagri.go.id</h2>
      </div><!-- /.header -->

      <div class="cf-section cf-highlight">
        <div class="cf-wrapper">
          <div class="cf-screenshot-container cf-screenshot-full">
            
              <span class="cf-no-screenshot error"></span>
            
          </div>
        </div>
      </div><!-- /.captcha-container -->

      <div class="cf-section cf-wrapper">
        <div class="cf-columns two">
          <div class="cf-column">
            <h2 data-translate="blocked_why_headline">Why have I been blocked?</h2>

            <p data-translate="blocked_why_detail">This website is using a security service to protect itself from online attacks. The action you just performed triggered the security solution. There are several actions that could trigger this block including submitting a certain word or phrase, a SQL command or malformed data.</p>
          </div>

          <div class="cf-column">
            <h2 data-translate="blocked_resolve_headline">What can I do to resolve this?</h2>

            <p data-translate="blocked_resolve_detail">You can email the site owner to let them know you were blocked. Please include what you were doing when this page came up and the Cloudflare Ray ID found at the bottom of this page.</p>
          </div>
        </div>
      </div><!-- /.section -->

      <div class="cf-error-footer cf-wrapper w-240 lg:w-full py-10 sm:py-4 sm:px-8 mx-auto text-center sm:text-left border-solid border-0 border-t border-gray-300">
    <p class="text-13">
      <span class="cf-footer-item sm:block sm:mb-1">Cloudflare Ray ID: <strong class="font-semibold">9e775832adde406d</strong></span>
      <span class="cf-footer-separator sm:hidden">&bull;</span>
      <span id="cf-footer-item-ip" class="cf-footer-item hidden sm:block sm:mb-1">
        Your IP:
        <button type="button" id="cf-footer-ip-reveal" class="cf-footer-ip-reveal-btn">Click to reveal</button>
        <span class="hidden" id="cf-footer-ip">180.249.211.56</span>
        <span class="cf-footer-separator sm:hidden">&bull;</span>
      </span>
      <span class="cf-footer-item sm:block sm:mb-1"><span>Performance &amp; security by</span> <a rel="noopener noreferrer" href="https://www.cloudflare.com/5xx-error-landing" id="brand_link" target="_blank">Cloudflare</a></span>
      
    </p>
    <script>(function(){function d(){var b=a.getElementById("cf-footer-item-ip"),c=a.getElementById("cf-footer-ip-reveal");b&&"classList"in b&&(b.classList.remove("hidden"),c.addEventListener("click",function(){c.classList.add("hidden");a.getElementById("cf-footer-ip").classList.remove("hidden")}))}var a=document;document.addEventListener&&a.addEventListener("DOMContentLoaded",d)})();</script>
  </div><!-- /.error-footer -->

    </div><!-- /#cf-error-details -->
  </div><!-- /#cf-wrapper -->

  <script>
    window._cf_translation = {};
    
    
  </script>
<script>(function(){function c(){var b=a.contentDocument||a.contentWindow.document;if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'9e775832adde406d',t:'MTc3NTM3OTQzOA=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script></body>
</html>

问题分析与解决方案

核心问题

  1. HTTP2协商失败THTTPClient设置ProtocolVersion:=HTTP_2_0仅为请求偏好,实际需要通过ALPN协议与服务器协商HTTP2。当前请求降级到HTTP/1.1,不符合服务器仅接受HTTP2的要求,触发Cloudflare拦截。
  2. 非浏览器请求特征:缺少浏览器样式的请求头,且未处理Cloudflare的Cookie验证、JS挑战逻辑,被识别为自动化请求拦截。

解决方案

方案1:修正HTTP2配置并模拟浏览器请求头

修改代码,添加浏览器请求头并确保HTTP2协商正常:

procedure TForm1.Button1Click(Sender: TObject);
var
  Http:THTTPClient;
  CM:TCookieManager;
  url,Sver:String;
  Res:IHTTPResponse;
  Headers: TStringList;
begin
  CM:=TCookieManager.Create;
  Http:=THTTPClient.Create;
  try
    Http.CookieManager := CM;
    // 强制偏好HTTP2协议
    Http.ProtocolVersion := THTTPProtocolVersion.HTTP_2_0;
    // 添加浏览器请求头,避免被识别为自动化请求
    Headers := TStringList.Create;
    try
      Headers.Add('User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36');
      Headers.Add('Accept: application/json, text/javascript, */*; q=0.01');
      Headers.Add('Accept-Language: id-ID,id;q=0.9,en-US;q=0.8,en;q=0.7');
      Headers.Add('Accept-Encoding: gzip, deflate, br');
      Headers.Add('X-Requested-With: XMLHttpRequest');
      
      url:='https://service.sipd.kemendagri.go.id/auth/captcha/new';
      Res:=Http.Get(url, Headers);
      
      case Res.Version of
        THTTPProtocolVersion.HTTP_1_0: Sver:='HTTP_1_0';
        THTTPProtocolVersion.HTTP_1_1: Sver:='HTTP_1_1';
        THTTPProtocolVersion.HTTP_2_0: Sver:='HTTP_2_0';
        else Sver:='UNKNOWN_HTTP';
      end;
      
      Mlog.Clear;
      Mlog.Lines.Add(Format('Result = %d:: %s',[Res.StatusCode, Res.StatusText]));
      Mlog.Lines.Add(Format('Protocol = %s',[Sver]));
      MOutput.Clear;
      MOutput.Text:=Res.ContentAsString;
    finally
      Headers.Free;
    end;
  finally
    Http.Free;
    CM.Free;
  end;
end;

方案2:处理Cloudflare JS挑战(若方案1仍失败)

如果Cloudflare仍拦截请求,说明需要完成JS人机验证。此时建议使用嵌入式浏览器控件(如CEF4Delphi):

  • 先加载目标页面,等待Cloudflare验证完成
  • 提取验证后的Cookie和请求头
  • 使用提取的信息发送请求获取验证码数据

内容的提问来源于stack exchange,提问作者Theo

火山引擎 最新活动