Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Limit

Es gibt ein solches Limit auf LinkedIn — Limit für die kommerzielle Nutzung. Es ist sehr wahrscheinlich, dass Sie, wie ich vor kurzem, noch nie davon gehört oder damit zu tun hatten.

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Das Grundkonzept des Limits ist, dass wenn Sie die Personensuche außerhalb Ihrer Kontakte zu oft nutzen (es gibt keine genauen Metriken, der Algorithmus entscheidet basierend auf Ihrem Verhalten – wie oft und wie viel Sie gesucht oder Personen hinzugefügt haben), wird das Suchergebnis auf drei Profile anstelle von 1000 (standardmäßig 100 Seiten mit 10 Profilen pro Seite) beschränkt. Das Limit wird zu Beginn eines jeden Monats zurückgesetzt. Natürlich, haben Premium-Konten dieses Limit nicht..

Aber vor kurzem, für ein kleines Projekt, begann ich intensiv mit der Suche auf LinkedIn zu experimentieren und erhielt plötzlich dieses Limit. Das gefiel mir natürlich nicht, besonders da ich es nicht für kommerzielle Zwecke verwendet hatte, daher war mein erster Gedanke, das Limit zu untersuchen und zu versuchen, es zu umgehen.

[Wichtiger Hinweis — die Inhalte des Artikels dienen ausschließlich zu Informations- und Bildungszwecken. Der Autor unterstützt deren Nutzung für kommerzielle Zwecke nicht.]

Wir untersuchen das Problem

Wir haben: Statt zehn Profilen mit Pagination gibt die Suche nur drei aus, gefolgt von einem Block mit einer "Empfehlung" für ein Premium-Konto, und darunter sind verschwommene und nicht klickbare Profile.

Sofort greift man zur Entwicklertools-Konsole, um diese versteckten Profile zu überprüfen – vielleicht können wir einige Stile entfernen, die den Blur-Effekt erzeugen, oder Informationen aus dem Block im Markup extrahieren. Aber, wie zu erwarten, sind diese Profile nur Platzhalterbilder und speichern keine Informationen.

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Gut, jetzt schauen wir in den Network-Tab und überprüfen, ob tatsächlich eine alternative Ausgabe der Suchergebnisse funktioniert, die nur drei Profile zurückgibt. Wir finden die Anfrage an “/api/search/blended” und schauen uns die Antwort an.

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Die Profile kommen in einem Array `included`, aber es gibt insgesamt 15 Entitäten. In diesem Fall sind die ersten drei davon Objekte mit zusätzlichen Informationen, wobei jedes Objekt Daten zu einem bestimmten Profil enthält (zum Beispiel, ob das Profil ein Premium-Profil ist).

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Die folgenden 12 sind echte Profile – Suchergebnisse, von denen uns nur drei angezeigt werden. Wie bereits vermutet, werden nur die Personen angezeigt, für die zusätzliche Informationen verfügbar sind (die ersten drei Objekte). Wenn wir beispielsweise die Antwort eines Profils ohne Limit betrachten, erhalten wir 28 Entitäten – 10 Objekte mit zusätzlichen Informationen und 18 Profile.

Antwort für ein Profil ohne LimitUmgehung des LinkedIn-Suchlimits durch Nutzung der API
Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Warum mehr als 10 Profile angezeigt werden, obwohl genau 10 angefordert werden, und sie nicht an der Anzeige teilnehmen, nicht einmal auf der nächsten Seite – ich weiß es noch nicht. Wenn man die URL der Anfrage analysiert, kann man sehen, dass count=10 (wie viele Profile in der Antwort zurückgegeben werden, maximal 49).

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Ich würde mich über jegliche Kommentare zu diesem Thema freuen.

Wir experimentieren

Gut, das Wichtigste, was wir jetzt sicher wissen, ist – es kommen mehr Profile in der Antwort zurück, als uns angezeigt werden. Das bedeutet, wir können mehr Daten abrufen, trotz des Limits. Lassen Sie uns versuchen, die API direkt aus der Konsole mit fetch aufzurufen.

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Erwartungsgemäß erhalten wir einen Fehler, 403. Das liegt an der Sicherheit, da wir hier kein CSRF-Token senden (CSRF auf Wikipedia. Wenn man es kurz fasst — jedem Anfrage wird ein einzigartiges Token hinzugefügt, das auf dem Server auf Echtheit überprüft wird).

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Es kann von jeder anderen erfolgreichen Anfrage oder aus Cookies kopiert werden, wo es im Feld ‘JSESSIONID’ gespeichert ist.

Wo man das Token findetHeader einer anderen Anfrage:

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Oder aus den Cookies, direkt über die Konsole:

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Versuchen wir es noch einmal, diesmal übergeben wir in fetch die Einstellungen, in denen wir den csrf-token im Header angeben.

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Erfolg, wir erhalten alle 10 Profile. :tada:

Wegen der unterschiedlichen Header weicht die Struktur der Antwort etwas von der ab, die in der Originalanfrage kommt. Man kann die gleiche Struktur erhalten, indem man ‘Accept: ‘application/vnd.linkedin.normalized+json+2.1’ zu unserem Objekt hinzufügt, neben dem csrf-Token.
Beispiel einer Antwort mit hinzugefügtem HeaderUmgehung des LinkedIn-Suchlimits durch Nutzung der API

Mehr über den Accept-Header

Wie geht es weiter?

Anschließend kann der Parameter `start` bearbeitet (manuell oder automatisiert) werden, der den Index angibt, ab dem uns 10 Profile zurückgegeben werden (Standard = 0) aus dem gesamten Suchergebnis. Mit anderen Worten, durch Inkrementierung um 10 nach jeder Anfrage erhalten wir eine normale paginierte Ausgabe, 10 Profile auf einmal.

An diesem Punkt hatte ich genügend Daten und Freiheit, um weiter an meinem Pet-Projekt zu arbeiten. Es wäre ein Fehler gewesen, diese Daten nicht gleich vor Ort auszuprobieren, da ich sie zur Verfügung hatte. Wir werden nicht in Ember, das im Frontend verwendet wird, eingreifen. Auf der Seite war jQuery eingebunden, und mit ein wenig Grundwissen über die Syntax konnte ich in ein paar Minuten Folgendes erstellen.

Code in jQuery

/* рендер блока, принимаем данные профиля и вставляем блок в список профилей используя эти данные */
const  createProfileBlock = ({ headline, publicIdentifier, subline, title }) => {
    $('.search-results__list').append(
        `<li class="search-result search-result__occluded-item ember-view">
            <div class="search-entity search-result search-result--person search-result--occlusion-enabled ember-view">
                <div class="search-result__wrapper">
                    <div class="search-result__image-wrapper">
                        <a class="search-result__result-link ember-view" href="/de/in/${publicIdentifier}/">
                            <figure class="search-result__image">
                                <div class="ivm-image-view-model ember-view">
                                    <img class="lazy-image ivm-view-attr__img--centered EntityPhoto-circle-4  presence-entity__image EntityPhoto-circle-4 loaded" src="http://www.userlogos.org/files/logos/give/Habrahabr3.png" />
                                </div>
                            </figure>
                        </a>
                    </div>
                    
                    <div class="search-result__info pt3 pb4 ph0">
                        <a class="search-result__result-link ember-view" href="/de/in/${publicIdentifier}/">
                            <h3 class="actor-name-with-distance search-result__title single-line-truncate ember-view">
                                ${title.text}
                            </h3>
                        </a>

                        <p class="subline-level-1 t-14 t-black t-normal search-result__truncate">${headline.text}</p>

                        <p class="subline-level-2 t-12 t-black--light t-normal search-result__truncate">${subline.text}</p>
                    </div>
                </div>
            </div>
        <li>`
 );
};

// Wir rufen die API auf, holen die Daten und rendern die Profile
const fetchProfiles = () =&gt; {
 // Token
 const csrf = 'ajax:9082932176494192209';
 
 // Objekt mit den Anfrageeinstellungen, wir übergeben das Token
 const settings = { headers: { 'csrf-token': csrf } }

 // URL der Anfrage, mit dynamischem Start-Index am Ende
 const url = `https://www.linkedin.com/voyager/api/search/blended?count=10&amp;filters=List(geoRegion-jp0,network-S,resultType-PEOPLE)&amp;origin=FACETED_SEARCH&amp;q=all&amp;queryContext=List(spellCorrectionEnabled-true,relatedSearchesEnabled-true)&amp;start=${nextItemIndex}`; 
 /* Wir machen die Anfrage, für jedes Profil in der Antwort rufen wir die Render-Funktion auf und inkrementieren anschließend den Start-Index um 10 */
 fetch(url, settings).then(response =&gt; response.json()).then(data =&gt; {
 data.elements[0].elements.forEach(createProfileBlock);
 nextItemIndex += 10;
});
};


// Wir entfernen alle Profile aus der Liste
$('.search-results__list').find('li').remove();
// Wir fügen die Schaltfläche zum Laden der Profile ein
$('.search-results__list').after('<button id="load-more">Mehr Laden</button>');
// Funktionalität zur Schaltfläche hinzufügen
$('#load-more').addClass('artdeco-button').on('click', fetchProfiles);

// Standardindex für Profilanfragen setzen
window.nextItemIndex = 0;

Wenn man dies direkt in der Konsole auf der Suchseite ausführt, wird eine Schaltfläche hinzugefügt, die bei jedem Klick 10 neue Profile lädt und sie als Liste darstellt. Natürlich müssen vorher das Token und die URL entsprechend angepasst werden. Der Profilblock enthält den Namen, die Position, den Standort, einen Link zum Profil und ein Platzhalterbild.

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

Fazit

So konnten wir mit minimalem Aufwand eine Schwachstelle finden und die Suche ohne Einschränkungen wiederherstellen. Es genügte, die Daten und deren Weg zu analysieren und den tatsächlichen Request zu betrachten.

Ich würde nicht sagen, dass dies ein ernsthaftes Problem für LinkedIn darstellt, da es keine Bedrohung darstellt. Im schlimmsten Fall handelt es sich um entgangene Gewinne aufgrund solcher "Umgehungen", die es ermöglichen, nicht für Premium zu bezahlen. Möglicherweise ist diese Serverantwort für das ordnungsgemäße Funktionieren anderer Teile der Webseite notwendig, oder es ist einfach ein Zeichen von Faulheit der Entwickler, die nicht über ausreichende Ressourcen verfügen, um es besser zu machen. (Einschränkungen traten im Januar 2015 in Kraft, zuvor gab es keine solche Begrenzung).

P.S.

Natürlich ist der jQuery-Code ein recht einfaches Beispiel für die Möglichkeiten. Momentan habe ich eine Browsererweiterung für meine Zwecke erstellt. Sie fügt Kontrollknöpfe hinzu und rendert vollständige Profile mit Bildern, Einladungsbuttons und gemeinsamen Verbindungen. Außerdem sammelt sie dynamisch Filter für Standorte, Unternehmen und andere Aspekte und holt das Token aus den Cookies. So ist kein Hardcoding mehr erforderlich. Zudem fügt sie zusätzliche Einstellungsfelder hinzu, wie "wie viele Profile auf einmal abfragen, bis zu 49".

Umgehung des LinkedIn-Suchlimits durch Nutzung der API

An diesem Add-on arbeite ich noch und plane, es öffentlich zugänglich zu machen. Schreibt, wenn ihr interessiert seid.

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster