Heim >Web-Frontend >js-Tutorial >Verwendung von JavaScript zum Knacken von Bestätigungscodes
Kürzlich ist im Internet ein JavaScript-Skript aufgetaucht, das Verifizierungscodes knacken kann – GreaseMonkey! Dieses von „Shaun Friedle“ entwickelte Skript kann das CAPTCHA der Megaupload-Site leicht lösen. Wenn Sie es nicht glauben, können Sie zu http://herecomethelizards.co.uk/mu_captcha/ gehen und es selbst ausprobieren
Jetzt wurde das von der Megaupload-Site bereitgestellte CAPTCHA durch das oben Gesagte besiegt Um ehrlich zu sein, ist der Bestätigungscode hier nicht sehr gut gestaltet. Aber was noch interessanter ist:
1. Die Canvas-Anwendungsschnittstelle getImageData in HTML 5 kann verwendet werden, um Pixeldaten aus dem Verifizierungscode-Bild zu erhalten. Mit Canvas können wir ein Bild nicht nur in eine Leinwand einbetten, sondern es später auch wieder daraus extrahieren.
2. Das obige Skript enthält ein vollständig in JavaScript implementiertes neuronales Netzwerk.
3. Nachdem Sie Canvas verwendet haben, um Pixeldaten aus dem Bild zu extrahieren, senden Sie sie an das neuronale Netzwerk und verwenden Sie eine einfache optische Zeichenerkennungstechnologie, um abzuleiten, welche Zeichen im Bestätigungscode verwendet werden.
Durch das Lesen des Quellcodes können wir nicht nur sein Funktionsprinzip besser verstehen, sondern auch verstehen, wie dieser Verifizierungscode implementiert wird. Wie Sie bereits gesehen haben, sind die hier verwendeten CAPTCHAs nicht sehr komplex – jedes CAPTCHA besteht aus drei Zeichen, jedes Zeichen verwendet eine andere Farbe und verwendet nur Zeichen aus dem 26-Buchstaben-Alphabet, während alle Zeichen alle dieselbe Schriftart verwenden.
Der Zweck des ersten Schritts liegt auf der Hand: Kopieren Sie den Bestätigungscode auf die Leinwand und konvertieren Sie ihn in ein Graustufenbild.
function convert_grey(image_data){
for (var x = 0; x < image_data.width; x++){
for (var y = 0; y < image_data.height; y++ ){
var i = x*4+y*4*image_data.width;
var luma = Math.floor(image_data.data[i] * 299/1000 +
image_data.data[i+ 1 ] * 587/1000 +
Image_data.data[i+2] * 114/1000);
image_data.data[i+1] = luma; 🎜> image_data.data[i+2] = luma;
image_data.data[i+3] = 255; teilt die Leinwand in drei separate Pixelmatrizen auf, die jeweils ein Zeichen enthalten. Dieser Schritt ist sehr einfach durchzuführen, da jedes Zeichen eine eigene Farbe verwendet und somit farblich unterschieden werden kann.
filter(image_data[0], 105);
filter(image_data[1], 120);
filter(image_data[2], 135); Farbe){
for (var x = 0; x < image_data.width; *4+y*4*image_data.width;
if (image_data.data[i] == color) {
image_data.data[i ] = 255;
image_data.data[i+2] = 255;
// Alles andere zu schwarz
} else { image_data.data[i] = 0;
image_data.data[i+2 ] = 0; 🎜> }
Schließlich werden alle irrelevanten Störpixel eliminiert. Dazu können Sie zunächst die weißen (übereinstimmenden) Pixel finden, die vorne oder hinten von schwarzen (nicht übereinstimmenden) Pixeln umgeben sind, und dann die übereinstimmenden Pixel löschen.
var i = x*4+y*4*image_data.width;
var Above = x*4+(y-1)*4*image_data.width; *4+(y+1)*4*image_data.width;
if (image_data.data[i] == 255 &&
image_data.data[above] == 0 &&
image_data.data[ unten] == 0) {
image_data.data[i] = 0;
image_data.data[i+1] = 0;
image_data.data[i+2] = 0; }
Jetzt haben wir eine ungefähre Form des Zeichens, aber bevor es in das neuronale Netzwerk geladen wird, führt das Skript noch die notwendige Kantenerkennung daran durch. Das Skript sucht nach den Pixeln ganz links, rechts, oben und unten in der Grafik, wandelt sie in ein Rechteck um und wandelt das Rechteck dann wieder in eine 20*25-Pixel-Matrix um.
cropped_canvas.getContext("2d").fillRect(0, 0, 20, 25);
cropped_canvas.getContext("2d" ).drawImage(canvas, Edges[0], Edges[1],
Edges[2]-Edges[0], Edges[3]-Edges[1], 0, 0,
image_data[i] = cropped_canvas.getContext("2d").getImageData(0, 0,
cropped_canvas.width, cropped_canvas.height );
Was erhalten wir nach der obigen Verarbeitung? Eine 20*25-Matrix, die ein einzelnes Rechteck enthält, das mit Schwarz und Weiß gefüllt ist. Das ist großartig!
Dann wird dieses Rechteck weiter vereinfacht. Wir extrahieren strategisch einige Punkte aus der Matrix als „Photorezeptoren“, die in das neuronale Netzwerk eingespeist werden. Beispielsweise kann ein bestimmter Fotorezeptor einem Pixel bei 9*6 entsprechen, mit oder ohne Pixel. Das Skript extrahiert eine Reihe solcher Zustände (weitaus weniger als die gesamte 20x25-Matrixberechnung – es werden nur 64 Zustände extrahiert) und speist diese Zustände in das neuronale Netzwerk ein.
Sie fragen sich vielleicht: Warum nicht Pixel direkt vergleichen? Ist es notwendig, ein neuronales Netzwerk zu verwenden? Der Schlüssel zum Problem liegt darin, dass wir diese mehrdeutigen Situationen beseitigen müssen. Wenn Sie die vorherige Demo ausprobiert haben, werden Sie feststellen, dass der direkte Vergleich von Pixeln fehleranfälliger ist als der Vergleich über ein neuronales Netzwerk, obwohl dies nicht häufig vorkommt. Wir müssen jedoch zugeben, dass für die meisten Benutzer ein direkter Pixelvergleich ausreichen dürfte.
Der nächste Schritt besteht darin, zu versuchen, die Buchstaben zu erraten. 64 Boolesche Werte (erhalten aus einem der Charakterbilder) werden in das neuronale Netzwerk importiert, sowie eine Reihe vorberechneter Daten. Eines der Konzepte neuronaler Netze besteht darin, dass die Ergebnisse, die wir erhalten möchten, im Voraus bekannt sind, sodass wir das neuronale Netz basierend auf den Ergebnissen entsprechend trainieren können. Der Skriptautor kann das Skript mehrmals ausführen und eine Reihe der besten Ergebnisse sammeln, die dem neuronalen Netzwerk dabei helfen können, die Antwort zu erraten, indem er von den Werten aus rückwärts arbeitet, die sie erzeugt haben. Diese Bewertungen haben jedoch keine besondere Bedeutung.
Wenn das neuronale Netzwerk die 64 booleschen Werte berechnet, die einem Buchstaben im Bestätigungscode entsprechen, vergleicht es diese mit einem vorberechneten Alphabet und gibt dann eine Bewertung für die Übereinstimmung mit jedem Buchstaben ab. (Das Endergebnis kann ähnlich sein: 98 % können der Buchstabe A sein, 36 % können der Buchstabe B usw. sein.)
Wenn alle drei Buchstaben im Bestätigungscode verarbeitet wurden, wird das Endergebnis angezeigt aus. Es sollte beachtet werden, dass dieses Skript nicht 100 % korrekt ist (ich frage mich, ob die Genauigkeit der Wertung verbessert werden kann, wenn die Buchstaben am Anfang nicht in Rechtecke umgewandelt werden), aber es ist ziemlich gut, zumindest für den aktuellen Zweck. Sag es. Und alle Vorgänge werden im Browser auf Basis der Standard-Client-Technologie ausgeführt.
Ich möchte hinzufügen, dass dieses Skript als Sonderfall betrachtet werden sollte. Diese Technologie funktioniert möglicherweise gut in anderen einfachen Verifizierungscodes, aber bei komplexen B. Verifizierungscodes, ist dies etwas unerreichbar (insbesondere diese Art der clientbasierten Analyse). Ich hoffe, dass sich noch mehr Menschen von diesem Projekt inspirieren lassen und weitere wundervolle Dinge entwickeln können, denn sein Potenzial ist so groß