char * to integer
-
Hallo, moin,
in meiner CGI Class hätte ich gerne die CONTENT_LENGTH als Integer. getenv("CONTENT_LENGTH");
liefert mir diese Angabe als char *. Mein Versuch das mit atoi() oder (int) zu casten nimmt der Compiler zwar anstandslos hin, aber das Programm legt dann die Ohren an (segmentation fault).Wie geht es denn richtig, bitte Hinweise. Es geht um meine erste Webseite in C++
http://rolfrost.de/foo.chtmlda steht auch die c++vesion
MFG und weiterhin FF
-
@_ro_ro Wie sieht denn der Code aus? Ich würde mit
std::string
undstd::stoi
arbeiten, aber um feststellen zu können, was bei dir genau schief geht, müssen wir den Code sehen der Kracht. Am Besten als minimales kompilierbares Beispiel.
-
herzlichen Dank. Es war ein typischer Anfängerfehler meinerseits, ich hatte nicht geprüft ob getenv() überhaupt was liefert. Hier die Lösung
size_t contentlength = getenv("CONTENT_LENGTH") == NULL ? 0 : atoi(getenv("CONTENT_LENGTH"));
Kaum macht mans richtig .....
Viele Grüße!!!
PS: Zum Projekt Web-Application-Framework schreibe ich später mal was.
-
@_ro_ro Falls dir das nicht so ganz bewusst ist: Denke dran, dass es sich bei solchen Werten wie
Content-Length
aus einem HTTP-Header um nicht vertrauenswürdige User-Inputs aus dem Netz handelt. Sowas sollte man tunlichst nicht direkt irgendwo verwenden, z.B. um einen Buffer zu allozieren und solche Spässe. Nur so als Hinweis am Rande, weil ich da irgendwie schon ne Allokation in den nächsten Zeilen kommen seheFalls dir das klar war, will ich nix gesagt haben und bitte um Verzeihung für die Belästigung
-
FF wird übrigens überwiegend als Abkürzung für Firefox gebraucht... Ist es denn so schwer, frohe Feiertage o. Ä. auszuschreiben? Das hat ein Geschmäckle, würde man in Bayern (und auf Schwäbisch) sagen. Aber gut, vielleicht liege ich auch einfach nur zur nachtschlafenden Zeit etwas daneben...
-
Moin Rosti!
Bedenke auch, dass bei
atoi
keine Fehlererkennung möglich ist, also dass Fehler und "0" nicht unterschieden werden. Beistoi
etc. kannst du noch einen 2. Parameter mitgeben für Fehler am Stringende.Außerdem würde ich den doppelten getenv-Call vermeiden und stattdessen das Resultat in einer Variablen speichern und diese dann auf
nullptr
testen (bzwif (the_var)
schreiben;NULL
klingt sehr nach C ohne ++,nullptr
ist die C++-Variante) und umwandeln.
-
@Finnegan sagte in char * to integer:
@_ro_ro Falls dir das nicht so ganz bewusst ist: Denke dran, dass es sich bei solchen Werten wie
Content-Length
aus einem HTTP-Header um nicht vertrauenswürdige User-Inputs aus dem Netz handelt. Sowas sollte man tunlichst nicht direkt irgendwo verwenden, z.B. um einen Buffer zu allozieren und solche Spässe. Nur so als Hinweis am Rande, weil ich da irgendwie schon ne Allokation in den nächsten Zeilen kommen seheFalls dir das klar war, will ich nix gesagt haben und bitte um Verzeihung für die Belästigung
Danke Dir und auch Danke an die Kollegen hier
Ja, ich werde all diese Dinge noch mitnehmen und beherzigen. In c++ bin ich noch relativ neu aber mit c bin ich schon einigemale abgesürzt, das ist heftig. Insbesondere auf einem Shared-Host kann sowas richtig Ärger machen und bis gestern wusste ich noch gar nicht daß ich da den gcc benutzen darf. Allein Diese Ehre verpflichtet!
Ansonsten habe ich über fast 30 Jahre Webentwicklung mit Perl aufm Buckel und bin mit 70 jetzt in Rente
Von daher gibt es bei mir auch immer wieder Variablen mit einem $-Zeichen
// Ersatz für htonl unter Verzicht auf die winsock.h // Big Endian to Little Endian // und umgekehrt uint32_t endian( uint32_t be){ int $a = be >> 24; int $b = be >> 16 & 0xFF; int $c = be >> 8 & 0xFF; int $d = be & 0xFF; return ($d << 24) + ($c << 16) + ($b << 8) + $a; }
Viele Grüße!
PS: Weihnachten geht mir auf'n Sack, zum Glück ists morgen vorbei erstma
-
@_ro_ro bedenke, dass int vorzeichenbehaftet ist und vor allem in der Bitbreite nur eine Mindestlänge hat. Ist also denkbar ungeeignet für deine Dollar-Variablen. Vor allem, weil du den int-Wert dann noch 24x left shiftest (overflow möglich). Nimm stattdessen den korrekten unsigned-Typen!
-
@wob sagte in char * to integer:
@_ro_ro bedenke, dass int vorzeichenbehaftet ist und vor allem in der Bitbreite nur eine Mindestlänge hat. Ist also denkbar ungeeignet für deine Dollar-Variablen. Vor allem, weil du den int-Wert dann noch 24x left shiftest (overflow möglich). Nimm stattdessen den korrekten unsigned-Typen!
Ok, werd ich machen, Danke!!!
'MFG
-
um auf Deinen Hinweis zurückzukommen: Ja die Werte aus der Umgebung wie z.B.
CONTENT_LENGTH
sind nicht vertrauenswürdig. Zum Parsen habe ich mich jetzt fürstoi
entschieden und fange mögliche Exceptionsinvalid_argument
sowieout_of_range
ab.
Auch über einen QUERY_STRING der üblicherweise Prozentkodiert ist, ist es möglich dem Programm einen ungültigen HEX-Wert wie z.B%ZZ
unterzujubeln was beistoi
die Exceptioninvalid_argument
schmeißt.
Das mit der Ex ist ok, denn in solchen Fällen macht eine Weiterverarbeitung der Eingaben eh keinen Sinn.Abgesehen davon gibt es für Apache/Nginx
mod_security
, da werden Requests mit ungültigen Prozentkodierungen auch schon geblockt wenn das so konfiguriert ist. Nur darf man sich nicht darauf verlassen.MFG
-
@_ro_ro sagte in char * to integer:
um auf Deinen Hinweis zurückzukommen: Ja die Werte aus der Umgebung wie z.B.
CONTENT_LENGTH
sind nicht vertrauenswürdig. Zum Parsen habe ich mich jetzt fürstoi
entschieden und fange mögliche Exceptionsinvalid_argument
sowieout_of_range
ab.Selbst wenn es sich um gültige Integer-Zahlen handelt, könnten die auch einfach viel zu groß sein. Mit so einem
stoi
-geparstenint
kann man bis zu 2 GiB Größe angeben. Wenn man da etliche Requests an den Webserver schickt und diese parallel in mehreren Prozessen verarbeitet werden, bekommt man damit eventuell schon ein DOS hin mit dem man den Server "aus dem Netz schiesst" - auch wenn sichstoi
nie beschwert hat.Ich würde mich da eher nach der Datenmenge richten, die auch tatsächlich gesendet wird, also die Pakete oder den Stream stückweise einlesen und den Buffer bis zu einem vernünftigen Limit mitwachsen lassen (oder mit fixer Maximalgröße arbeiten).
Es kommt auch drauf an, wie die gesendeten Daten weiterverarbeitet werden. Wenn du die als Datenstrom verarbeiten kannst, also blockweise und dann irgendwohin wegschreiben, dann reicht ein ziemlich kleiner Buffer (simples Beispiel wäre die Verarbeitung von Datei-Uploads). Wenn du die Daten komplett im Speicher brauchst, weil die Verarbeitung es erfordert, kreuz und quer darin umherzuspringen, dann sollte man die Größe schon limitieren und dem User mitteilen, wenn der Request zu groß war.
Content-Length
hingegen würde ich als grundsätzlich nicht vertrauenswürdige Zahl für nichts im Programm verwenden ausser vielleicht einer Konsistenzprüfung: Wenn am Ende die Größe der gesendeten Daten undContent-Length
nicht übereinstimmen, wäre das z.B. ein fehlerhafter Request, der ignoriert wird.
-
Man ist leider auf die CONTENT_LENGTH - Angabe angewiesen. Weil man mit einem CGI Prozess ganz sicher nicht solange aus STDIN lesen will bis da keine Daten mehr kommen, da wäre eine Denial of Servcie Attack ja schon vorprogrammiert.
MFG
Edit: Man kann jedoch folgendes machen:
rawdata.resize(100000); cin.read(&rawdata[0], 100000); // Limit Max-Data!!!
also ein Limit fest kodieren (Je nach Anforderung).
-
@_ro_ro sagte in char * to integer:
Man ist leider auf die CONTENT_LENGTH - Angabe angewiesen. Weil man mit einem CGI Prozess ganz sicher nicht solange aus STDIN lesen will bis da keine Daten mehr kommen, da wäre eine Denial of Servcie Attack ja schon vorprogrammiert.
Es gibt schon einen gewaltigen Unterschied beim Lesen aus STDIN: Damit den Speicher des Servers zu überfüllen ist ungleich teurer für einen Angreifer, da die gesamte Datenmenge über das Netzwerk gesendet werden muss anstatt nur ein paar Kilobyte Datenpakete mit falschen Werten im HTTP-Header.
Trotzdem, auch hier sollte man natürlich die Größe irgendwo begrenzen. Ich habe schliesslich geschrieben, den Buffer "bis zu einem vernünftigen Limit mitwachsen lassen".
Und das auch nur, wenn man tatsächlich die kompletten Daten im Buffer braucht. Eventuell lassen die sich ja auch stückweise verarbeiten, so dass ein viel kleinerer Buffer ausreicht. Einen Datei-Upload für beliebig große Datein könnte man wahrscheinlich mit einem 1 KiB-Buffer handhaben (auch wenn da andere Limits wie Dateigröße auf dem Festspeicher wichtig werden könnten).
Edit: Man kann jedoch folgendes machen:
rawdata.resize(100000); cin.read(&rawdata[0], 100000); // Limit Max-Data!!!
also ein Limit fest kodieren (Je nach Anforderung).
Das ist wahrscheinlich die simpelste Lösung, diese hat aber den Nachteil, dass jedesmal die maximale Buffer-Grösse reserviert wird, auch wenn man weniger benötigt. Wenn das da oben allerdings ein realistisches Limit ist, das deinen Anforderungen genügt, dann kann man diesen Einwand getrost ignorieren. 100 Kilobyte sind echt gar nichts
-
ja sicher doch kann man über CGI/1.1 Dateien upward streamen. Das setzt jedoch einen zweckmäßigen Enctype (Content-Type) voraus und der heißt ganz sicher nicht
multipart/form-data
. In Fakt braucht man hierzu einen proprietären Serializer der das Streamen unterstützt. Und außerdem ein Verfahren, daß den Webserver dazu veranlasst, die Verbindung zum nachgelagerten CGI-Prozess beliebig lange offenzuhalten.Ein solches Verfahren habe ich auf meiner Website beschrieben. Das läuft auf meinem privaten Webserver und damit lade ich meine Fotos vom Smartphone hoch und da können schonmal 200 Dateien und mehr als 1 GB zusammenkommen. Was natürlich auch erst möglich ist seitdem JavaScript mit Binaries umgehen können (HTML5 FileAPI).
MFG