This article explains the concept of headless browsers and details methods for bypassing headless detection.
What is a Headless Browser?
A headless browser is a browser without a graphical user interface. However, when used for web scraping, it exhibits certain characteristics that can be identified by websites, revealing its automated nature. This guide focuses on making deep-level modifications to the Chromium source code to thoroughly eliminate these identifiable traits.
How to Bypass Headless Detection?
1.Modify the webdriver property
Open the file: third_party\blink\renderer\core\frame\navigator.cc
c
bool Navigator::webdriver() const {
return false;
}
2.Modify rtt (Round-Trip Time)
Open the file: third_party/blink/renderer/modules/netinfo/network_information.ccc
c
c
uint32_t NetworkInformation::rtt() {
return 150;
}
3.Modify Notification.permission
Open the file: third_party/blink/renderer/modules/notifications/notification.cc
c
String Notification::PermissionString(
mojom::blink::PermissionStatus permission) {
switch (permission) {
case mojom::blink::PermissionStatus::GRANTED:
return "granted";
case mojom::blink::PermissionStatus::DENIED:
//return "denied";
return "default";
case mojom::blink::PermissionStatus::ASK:
return "default";
}
NOTREACHED();
//return "denied";
return "default";
}
4.Modify the User-Agent (Specifically for HeadlessChrome)
Open the file: C:\src\chromium\src\headless\lib\browser\headless_browser_impl.cc
Modify the relevant line:
c
const char kHeadlessProductName[] = "Chrome";
5.Address Plugin Detection for Headless Mode
Modify third_party\blink\renderer\modules\plugins\navigator_plugins.cc
c
DOMPluginArray* NavigatorPlugins::plugins(Navigator& navigator) {
DOMPluginArray* pluginsArray = NavigatorPlugins::From(navigator).plugins(navigator.DomWindow());
pluginsArray->UpdatePluginData();
return pluginsArray;
}
Then modify: third_party\blink\renderer\modules\plugins\dom_plugin_array.cc
c
void DOMPluginArray::UpdatePluginData() {
if (should_return_fixed_plugin_data_) {
dom_plugins_.clear();
//if (IsPdfViewerAvailable()) {
// See crbug.com/1164635 and https://github.com/whatwg/html/pull/6738.
// To reduce fingerprinting and make plugins/mimetypes more
// interoperable, this is the spec'd, hard-coded list of plugins:
Vector<String> plugins{"PDF Viewer", "Chrome PDF Viewer",
"Chromium PDF Viewer", "Microsoft Edge PDF Viewer",
"WebKit built-in PDF"};
for (auto name : plugins)
dom_plugins_.push_back(MakeFakePlugin(name, DomWindow()));
//}
return;
}