web-dev-qa-db-de.com

Javascript User-Agent (Ajax) unterscheidet sich vom gesendeten User-Agent, wenn eine Website angefordert wird

Ich habe festgestellt, dass Chrome (64.0.3282.137) auf meinem Telefon (OnePlus 3, Android 8.0.0) beim Anfordern einer Webseite etwas andere Benutzeragenten sendet als beim Anfordern über Ajax.

Dieser User-Agent wird gesendet, wenn eine Webseite angefordert wird:

Mozilla/5.0 (Linux; Android 8.0.0; ONEPLUS A3003 Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36

Dieser User-Agent sendet einen Ajax-Aufruf und wird auch beim Aufruf von navigator.userAgent zurückgegeben:

Mozilla/5.0 (Linux; Android 8.0.0; Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36

Unterschied: ONEPLUS A3003

Kannst du mir sagen, warum das Modell in den nativen Aufrufen enthalten ist, aber nicht in Ajax-Aufrufen?

Zusätzliche Informationen: Wenn das Feature "Desktop-Site anfordern" aktiviert ist, ist der Benutzeragent in beiden Fällen Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Safari/537.36.

26
SpazzMarticus

Ich habe den Quellcode von Chrom analysiert, um Einblicke zu erhalten. Ich konnte meine Anfängerfähigkeiten in c ++ nur bis zu einem gewissen Grad verbessern.

Der Benutzeragent des Clients oder der Plattform wird in diesem Codeblock (Datei: useragent.cc) erkannt.

std::string BuildUserAgentFromProduct(const std::string& product) {
  std::string os_info;
  base::StringAppendF(
      &os_info,
      "%s%s",
      getUserAgentPlatform().c_str(),
      BuildOSCpuInfo().c_str());
  return BuildUserAgentFromOSAndProduct(os_info, product);
}

Sie können BuildOSCpuInfo () im Codeblock sehen, der für das Hinzufügen der auf OS basierenden Informationen auf der Grundlage von Plattformen sorgt, die hier zu finden sind

std::string Android_build_codename = base::SysInfo::GetAndroidBuildCodename();
std::string Android_device_name = base::SysInfo::HardwareModelName(); // this line in particular adds the ONEPLUS A3003

Diese Funktion (BuildUserAgentFromProduct ()) wird jedoch nicht direkt im Netzmodul verwendet, das die HTTP-Anforderungen sendet.

Als ich den Code für das net (http) -Modul untersucht habe, sehe ich, dass sie den Benutzeragenten * abrufen und ihn durch eine Reihe von String-Manipulationen und Funktionen zum Leerschneiden von Leerräumen verarbeiten. AddHeadersFromString () in http_request_headers.cc ist die Schnittstelle, über die die Useragent-Zeichenfolge zum Anforderungsheader hinzugefügt wird.

Hinweis *: Ich denke jedoch, dass die Kopfdaten nicht von useragent.cc stammen, da ich die Aufrufe für diese Funktion nirgendwo finden kann. Aber ich könnte hier falsch liegen.

** Ich glaube, dass dies der Ort ist, an dem der Wert für OSInfo geändert wird. Jedes Whitespace-Zeichen, das nicht erkannt wird oder ein falsches Format aufweist, das ursprünglich beabsichtigt war, kann dieses Ergebnis liefern. 

Hinweis **: Ich konnte die obige Anweisung nicht testen und beweisen, da der in Chromium verwendete String im Namen von StringPiece einen Wrapper hat (* Wrapper ist nur ein Begriff, den ich verwende, technisch gesehen kann es sein) auf eine andere Art genannt, die ich nicht kenne. Und ich weiß nicht, wie ich den Code für StringPiece in c ++ schreiben soll.

Ein sehr einfaches Beispiel, wie es schief gehen kann, wird unten gegeben.

int main()
{
   std::string s = " ONEPLUS\rA3003\rBuild/OPR6.170623.013";
   std::string delimiter = "\r\n"; //this is the delimeter used in chromium source code.
   std::string token = s.substr(0, s.find(delimiter,0));
   std::cout << token << std::endl;
   return 0;
}

https://www.onlinegdb.com/SkTrbFJDz

Der Grund, warum die anfängliche Benutzer-Agent-Zeichenfolge den Wert hat und die nachfolgende http-Anforderung nicht den Wert hat, liegt in der Architektur der Chrome-App in Android. Wenn die Seite anfänglich geladen wird, werden die Werte tatsächlich von der Chrome-App festgelegt (eine sehr große Java-Codebasis. Ich denke jedoch, dass die Kerndatei, die wir sehen müssen, LoadUrlParams.Java ist) Der Useragent wird nicht vom selben Netzmodul (http) getrimmt, sondern von der Java-Implementierung (), dies geschieht nur beim ersten Laden. Alle anderen nachfolgenden Aufrufe verwenden jedoch das net (http) -Modul des Browsers.

Dateiverweislinks: https://cs.chromium.org/chromium/src/content/common/user_agent.cc?sq=package:chromium&dr=CSs&l=80

https://cs.chromium.org/chromium/src/net/http/http_request_headers.cc?type=cs&q=AddHeadersFromString&l=155

https://cs.chromium.org/chromium/src/content/public/Android/Java/src/org/chromium/content_public/browser/LoadUrlParams.java?q=createLoadDataParamsWithBaseUrl&dr=CSs

Ich füge diese Antwort nur hinzu, um einen der Gründe zu nennen, aus denen das Problem möglicherweise aufgetreten ist. Wenn ich mehr Zeit habe, werde ich sehen, ob ich irgendwie einen Test durchführen kann und dies beweisen kann. Eine letzte Anmerkung Diese Antwort gibt keine Lösung, um das Problem zu beheben. Es gibt nur den Grund für die Ursache.

[Aktualisieren]

Ein sehr billiger Trick ist zu sehen, ob navigator.useragent den oneplus-Wert hat und ajax-Header in der Anfrage setzt und sendet. Dadurch wird der Mechanismus des Browsers zum Hinzufügen des User Agent-Headers überschrieben.

XMLHttpRequest.setRequestHeader(header, value)
5
karthick

Im ersten Benutzeragenten identifiziert der Browser das Gerät als mobiles Gerät, indem er den Benutzeragenten vor der Anforderung ändert. daher der ONEPLUS A3003. Im zweiten Fall jedoch aufgrund der Spezifikation von w3 (Hier finden Sie es) können Sie den userAgent nicht ändern. daher die Auslassung von ONEPLUS A3003.

Wenn Sie die Funktion "Desktop-Site anfordern" verwenden, muss userAgent nicht vom Browser geändert werden. Daher wird derselbe BenutzerAgent angezeigt.

HINWEIS: Der Standardbenutzeragent für diesen Chrome-Browser lautet: Mozilla/5.0 (Linux; Android 8.0.0; Build/OPR6.170623.013) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.137 Mobile Safari/537.36