Inhalt eines Formulares in eine Textdatei speichern/Captcha

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Sonic
User
Beiträge: 7
Registriert: Dienstag 22. Januar 2008, 20:21

Mittwoch 23. Januar 2008, 11:42

Hallo,

ich habe mir mit Python eine Datei erstellt, die die Benutzereingabe eines html Formulars anzeigt. Nun würde ich das ganze gerne erweitern, und zwar sollte auf die Seite noch ein Ok Button zur bestätigung der Eingabe. Beim Klick auf den Button sollten die Informationen in eine .txt Datei geschrieben werden, die dann bei jeder neuen Eingabe einfach die Daten der nächsten Person anhängt(also nicht für jede Person eine neue Datei).

Dann würde ich in das Formular gerne noch ein Captcha einbauen.
Es sollte jedem User ein neue Session zuweisen, damit keiner eine Fehlermeldung bekommt)

Ich hoffe, ihr habt das einigermaßen verstanden und könnt mir vielleicht sogar helfen :D

Ach ja, falls ihr den Code braucht.

Code: Alles auswählen

#!/usr/local/bin/python2.3

import cgi
form=cgi.FieldStorage()

out = ""
print "Content-Type: text/html\n\n"
vorname = form["vorname"].value
name = form["nachname"].value
mail = form["mail"].value
zahlungsart = form["zahlungsart"].value
iq = form["iq"].value
alter = form["alter"].value
user_eingabe = form["user_eingabe"].value


out = out + "Vorname: " + vorname + "<br>" + "Nachname: " + name + "<br>" + "E-Mail: " + mail + "<br>" + "Zahlungsart: " + zahlungsart + "<br>" + "IQ: " + iq + "<br>" + "Alter: " + alter + "<br>" + "user_eingabe: " + user_eingabe  
print out
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 23. Januar 2008, 14:02

Zunächst der Standardtip: nutze WSGI, nicht pures CGI. Wsgi kann über CGI eingebunden werden, und es ist nicht so masochistisch zu Programmieren. Ich würde als einstieg "Werkzeug" empfehlen.

Zur Problematik:
ein Ok Button zur bestätigung der Eingabe
Das ist eher ne HTML-Frage, buttons machst du mit "<input type='submit' value='Ok!' />" oder "<button type='submit'>Ok!</button>", die innerhalb eines "<form>"-tags liegen.
Allerdings vermute ich, dass du was anderes Fragen willst, denn ich sehe nicht, wie die Werte überhaupt in die applikation kommen sollen, ohne Formular.
Dann würde ich in das Formular gerne noch ein Captcha einbauen.
Sofern das nicht nur für den Ehrgeiz ist: ein statisches Bild mit einem Text scheint für 99% aller Fälle zu genügen, sie codinghorror.com (hat immer "Orange") für ein prominentes Beispiel.
Sonic
User
Beiträge: 7
Registriert: Dienstag 22. Januar 2008, 20:21

Mittwoch 23. Januar 2008, 14:36

Erstmal danke für die Tipps. :D
Das Formular dient nur als Vorlage, die Felder werden später noch geändert.

Code: Alles auswählen

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
       "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Formular</title>
</head>
<body>

<h1>Kontakt</h1>

<form method="get" action="/cgi-bin/ausgabe.py">
  <table border="0" cellpadding="0" cellspacing="4">
    <tr>
      <td align="right">Vorname:</td>
      <td><input name="vorname" type="text" size="30" maxlength="30"></td>
    </tr>
    <tr>
      <td align="right">Nachname:</td>
      <td><input name="nachname" type="text" size="30" maxlength="40"></td>
    </tr>
    <tr>
      <td align="right">E-Mail:</td>
      <td><input name="mail" type="text" size="30" maxlength="40"></td>
    </tr>
    <tr>
      <td align="right">Zahlmethode:</td>
      <td><input type="radio" name="zahlungsart" value="Mastercard"> Mastercard<br>
    	  <input type="radio" name="zahlungsart" value="Visa"> Visa<br>
    	  <input type="radio" name="zahlungsart" value="AmericanExpress"> American Express</td>
    </tr>
    <tr>
       <td align="right">IQ:</td>
       <td><input type="checkbox" name="iq" value="u50"> Unter 50<br>
    	   <input type="checkbox" name="iq" value="51-199"> 51-199<br>
    	   <input type="checkbox" name="iq" value="ü200"> Über 200</td>
    </tr>
    <tr>
      <td align="right">Alter:</td>
      <td><select name="alter" size="5">
      <option value="u18">Unter 18</option>
      <option value="18-25">18-25</option>
      <option value="26-40">26-40</option>
      <option value="41-60">41-60</option>
      <option value="ü60">Über 60</option>
    </select></td>
    </tr>
    <tr>
      <td align="right">Kommentar:</td>
      <td><textarea name="user_eingabe" cols="50" rows="10"></textarea></td>
    </tr>
    <tr>
      <td align="right"></td>
      <td><input type="submit" value="Absenden"><input type="reset" value="Löschen"></td>
    </tr>
  </table>

    
  
</form>
</body>
</html>


Wenn man auf den absenden Button klickt, ruft er die .py datei auf, die dann die Eingaben anzeigt. Den bestätigungsbutton müsste ich dann in die .py Datei irgendwie einbinden.

Das mit dem captcha ist nicht nur für den Ehrgeiz :)
Das mit dem statischen Bild ist gar keine schlechte Idee, werde ich gleich mal ausprobieren :wink:

Kannst du mir vielleicht einen kleinen Tipp geben, wie ich ihm sage das er die Daten die er anzeigt in eine txt Datei packen soll?
Habe erst vor ein paar Tagen mit Python angefangen, schon mehrere Stunden danach gegooglet, mir fällt einfach nichts ein wie ich das machen könnte.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 23. Januar 2008, 15:22

Das mit dem captcha ist nicht nur für den Ehrgeiz :)
Das mit dem statischen Bild ist gar keine schlechte Idee, werde ich gleich mal ausprobieren :wink:
Bei einer von "meinen" Seiten hats gereicht. Ich war überrascht, in einem selbstgeschriebenen Gästebuch auf einmal Spam vorzufinden (scheinen ja schon etwas heller geworden zu sein, die Bots).
Statisches Bild mit Text, immer gleiche Eingabe, und gut war. Keinen Spam seitdem.
Kannst du mir vielleicht einen kleinen Tipp geben, wie ich ihm sage das er die Daten die er anzeigt in eine txt Datei packen soll?
Da gibts mehrere Möglichkeiten, abhängig davon, was genau die Anforderung ist.

1. Du willst die Daten eigentlich nur speichern, nur dein Programm liest sie wieder

Da würde sich dann "pickle" anbieten, dass erlaubt, Pythonobjekte wie dicts, listen, tupel, etc in eine Datei zu speichern bzw aus ihr zu holen, ohne über das Format nachdenken zu müssen. Sehr bequem, die Textdateien sind aber nicht Menschenlesbar.

Oder, je nachdem wie groß die Applikation wird, speicher den Krams in einer Datenbank. Solange sich kein eigene DB-Server lohnt, gibt es SQLite, was sich so verhält, als wäre es eine DB, aber im Endeffekt nur ne datei ist (vergleichbar mit den MS-Access-Dateien), wenn er lohnt wären da MySQL und Postgres die nächsten Schritte.
Je nach "Eskalationsgrad" kann sich SQL-Alchemy lohnen, was eine Bibliothek ist, mit der man Plattform- und Datenbankunabhängig Datenbanken nutzen kann.

2. Du willst wirklich eine Textdatei speichern, und sie muss in einem bestimmten Format sein, was andere Menschen oder Programme lesen können sollen.

In diesem Fall müsstest du einen Exporter schreiben. Wie man das macht, hängt vom Datenformat ab.
Je nach angepeilter Professionalität ist das allerdings nicht gerade Trivial, schnell können da viele der Probleme auftreten, die Datenbanken lösen sollen (concurrency, z.B.)
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Mittwoch 23. Januar 2008, 16:01

Ein sehr einfaches "Captcha" kannst du dir so bauen:

Wähle zwei Zufallszahlen zwischen 1 und 9.

Füge dann einen HTML- (oder JavaScript)-Schnipsel in dein Formular ein, der dem User die Frage nach der Summe der beiden Zahlen stellt.

Damit du prüfen kannst, ob der Benutzer die korrekte Antwort beim Absenden des Formulars gegeben hat, musst du natürlich selbst die Antwort kennen. Um keine Session auf dem Server zu verwalten, überträgst du am besten die korrekte Antwort ebenfalls.

Code: Alles auswählen

<form ...>
  <input type="hidden" name="a" value="MTM="/>
  6 + 7 = <input type="text" name="b" value=""/>
  ...
</form>
Damit man diese jetzt nicht einfach auslesen kann, verschlüsselst du sie.

Leider kommt Python nicht mit mit adäquaten Kryptografie-Funktionen, somit musst du improvisieren. Möglicherweise reicht encode('base64').

Oder du sagst, die Antwort soll immer 8 lauten und variierst einfach die Eingabe, also eine zufällige Zahl zwischen 1 und 7 und eine zwischen 1 und 8 minus erste Zahl. Ist aber ein bisschen sehr dünn.

Daher vielleicht lieber selbst eine schäbige Verschlüsselungsfunktion gebaut:

Code: Alles auswählen

def encrypt(n, k):
    return xor(str(randint(100, 999) * 19 + n), k).encode("hex")

def decrypt(s, k):
    return int(xor(s.decode("hex"), k)) % 19

def xor(s, k):
    k = k * (len(s) / len(k) + 1)
    return "".join(chr(ord(sc) ^ ord(kc)) for sc, kc in zip(s, k))
Stefan
Sonic
User
Beiträge: 7
Registriert: Dienstag 22. Januar 2008, 20:21

Mittwoch 23. Januar 2008, 16:28

Vielen Dank für eure Vorschläge, werde mir überlegen was besser passt.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 23. Januar 2008, 20:59

Ist jetzt eher eine Akademische Diskussion, wie gesagt reichen statische Bilder imho, aber...
sma hat geschrieben:Damit du prüfen kannst, ob der Benutzer die korrekte Antwort beim Absenden des Formulars gegeben hat, musst du natürlich selbst die Antwort kennen. Um keine Session auf dem Server zu verwalten, überträgst du am besten die korrekte Antwort ebenfalls.
Womit du auf eine recht komplizierte Art ziemlich genau das erreicht hat, was ein statisches Bild leistet, aber nicht mehr.
Beim statischen Bild muss der Angreifer einmal die Seite angucken, das Wort merken, und kann dann immer das gleiche senden.

Bei deiner Lösung muss er sich nur eine passende verschlüsselte Antwort/Antwort-kombination merken, und kann fortan die immer Senden.

Das ganze bietet keinerlei Mehrwert, nur deutlich mehr Arbeit.

Anders sähe das aus, wenn du die Lösung nicht auf der Webseite (egal ob offen oder kryptographisch sicher verschlüsselst), sondern Serverseitig, in einer Session oder sonstwie mitschleppst.

Im Endeffekt dürfte es allerdings auch nicht mehr lange hin sein, bis die Spambots eine höhere Trefferquote haben als die Menschen, da sowohl die User immer blöder als auch die Spammer immer schlauer werden.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Mittwoch 23. Januar 2008, 23:07

keppla hat geschrieben:[...]Womit du auf eine recht komplizierte Art ziemlich genau das erreicht hat, was ein statisches Bild leistet, aber nicht mehr.
Das sehe ich anders. Unter einem statischen Bild verstehe ich, dass bei jedem Formular das selbe Bild präsentiert wird, damit bei jedem Request die selbe Antwort erwartet wird. Damit muss der Spammer, das nur einmal herausbekommen und einfach diese Antwort bei jedem Request mitschicken. Damit ist das ein äußerst schwacher Schutz.

Meinen Vorschlag halte ich für besser. Ich verlange zumindest 18 verschiedene Antworten wobei nicht vorhersagbar ist, welche erwartet wird.

Natürlich kann man hier durch das Parsen des HTML-Quelltexts die Antwort ableiten, wenn man die Frage direkt ins HTML kodiert. Benutzt man JavaScript, muss der Spammer einen Browser fernsteuern und kann nicht mehr mit einem einfachen Kommandozeilen-Script arbeiten. Natürlich alles nichts, was einem ernsthaften Versuch standhält, aber besser, als eine feste Antwort.

Das ist für mich ein Mehrwert.

Statt deines Bildes, was vielleicht nicht jeder erkennen kann, kannst du auch sagen:

Code: Alles auswählen

<form ...>
  Gibt hier 42 ein:<input type="text" name="a"/>
  ...
</form>
was exakt den selben Effekt hat.
keppla hat geschrieben:Anders sähe das aus, wenn du die Lösung nicht auf der Webseite (egal ob offen oder kryptographisch sicher verschlüsselst), sondern Serverseitig, in einer Session oder sonstwie mitschleppst.
Nein, das ist kein wesentlicher Unterschied. Eine vernünftige Verschlüsselung vorausgesetzt, ist diese mit vertretbarem Aufwand nicht zu überwinden. Client-seitige Sessions - nichts anderes habe ich hier - sind hier praktisch gleichwertig zu Server-seitigen Sessions, die deutlich aufwendiger zu implementieren wären.

Problem meines Verfahrens ist, dass es nur 18 mögliche Antworten gibt. Der Spammer kann damit einfach 18 Antworten schicken - 17 werden verworfen, doch eine kommt durch. Dafür spare ich mir den Aufwand, eines dieser komischen Bilder zu erzeugen, die man häufig nicht lesen kann und habe eine Lösung, die auch Blinde überwinden können.

Stefan
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Donnerstag 24. Januar 2008, 08:53

sma hat geschrieben:
keppla hat geschrieben:[...]Womit du auf eine recht komplizierte Art ziemlich genau das erreicht hat, was ein statisches Bild leistet, aber nicht mehr.
Das sehe ich anders. Unter einem statischen Bild verstehe ich, dass bei jedem Formular das selbe Bild präsentiert wird, damit bei jedem Request die selbe Antwort erwartet wird.
Ja, so meinte ich das auch.
Damit muss der Spammer, das nur einmal herausbekommen und einfach diese Antwort bei jedem Request mitschicken. Damit ist das ein äußerst schwacher Schutz.
Ja, aber eben nicht schwächer als dein Vorschlag, denn...
Meinen Vorschlag halte ich für besser. Ich verlange zumindest 18 verschiedene Antworten wobei nicht vorhersagbar ist, welche erwartet wird.
Du musst doch gar nicht vorhersagen, welche erwartet ist. Du kannst immer die selbe verschlüsselte Antwort/Antwort-kombo senden. Also die, die du beim ersten mal siehst, genau so wie beim Bild.
Problem meines Verfahrens ist, dass es nur 18 mögliche Antworten gibt.
Nein, das "Problem" dieses Verfahrens ist, das die Kenntnis von nur einer Antwort völlig ausreicht (also wie beim Bild) , egal wieviele Mögliche es gibt.
Sonic
User
Beiträge: 7
Registriert: Dienstag 22. Januar 2008, 20:21

Donnerstag 24. Januar 2008, 09:35

edit/ hat sich erledigt, ich soll das Formular jetzt als .py Datei machen :roll: .
Sonic
User
Beiträge: 7
Registriert: Dienstag 22. Januar 2008, 20:21

Donnerstag 24. Januar 2008, 11:37

Nächste Frage :roll: .
Ich habe das ganze jetzt mal angefangen und wollte wissen ob man die Checkboxen und Radiobuttons auch in Python umsetzen kann.
Die Eingabe funktioniert perfekt, nur wird nichts von beidem Ausgegeben.
Denke aber eher das ich irgendeinen dummen Fehler gemacht habe.

Code: Alles auswählen

#!/usr/local/bin/python2.3

import cgitb; cgitb.enable()
import cgi
form=cgi.FieldStorage()
print "Content-Type: text/html\n"
print "<HTML><HEAD><TITLE>Formular</TITLE></HEAD><BODY>"
if form.has_key("Send"):
  if form.has_key("Vorname"):
    print 'Vorname: ' + form["Vorname"].value + '<br>'
  if form.has_key("Nachname"):
    print 'Nachname: ' + form["Nachname"].value + '<br>'
  if form.has_key("mail"):
    print 'E-Mail: ' + form["mail"].value + '<br>'
  if form.has_key("Zahlungsart"):
      print 'Zahlungsart: ' + form["Zahlungsart"].value + '<br>'
  if form.has_key("IQ"):
      print 'IQ: ' + form["iq"].value + '<br>'
else:
  print '<FORM method="post" action="hallo.py">'
  print 'Vorname: <INPUT type="text" name="Vorname"><br>'
  print 'Nachname: <INPUT type="text" name="Nachname"><br>'
  print 'E-Mail: <INPUT type="text" name="mail"><br>'
  print 'Zahlungsart: <br>'
  print 'Mastercard:<INPUT type="radio" name"Zahlungsart" value="Mastercard"><br>Visa:<INPUT type="radio" name"Zahlungsart" value="Visa"><br>American Express:<INPUT type="radio" name"Zahlungsart" value="American Express"><br>'
  print 'IQ: <br>'
  print 'Unter 50 <INPUT type="checkbox" name="iq" value="u50"><br>51-199<INPUT type="checkbox" name="iq" value="51-199"><br>Über50<INPUT type="checkbox" name="iq" value="ü50"><br>'
  print '<INPUT type="submit" value="Absenden" name="Send">'
  print '</FORM>'
print "</BODY></HTML>"
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Donnerstag 24. Januar 2008, 11:53

Sonic hat geschrieben:Nächste Frage :roll: .
Ich habe das ganze jetzt mal angefangen und wollte wissen ob man die Checkboxen und Radiobuttons auch in Python umsetzen kann.
Warum sollte das etwas mit python zu tun haben?
Denke aber eher das ich irgendeinen dummen Fehler gemacht habe.
Ich denke auch, guck dir mal das "name"-tag genau an:

Code: Alles auswählen

<INPUT type="radio" name"Zahlungsart" value="Visa"><br>American Express:<INPUT type="radio" name"Zahlungsart" value="American Express"><br>
Und nochmal der ernstgemeinte Tipp: nutze WSGI! nutze Templates! egal was, kriech doch nicht so auf dem Zahnfleisch herum und produziere unwartbaren code (das Tag wäre dir mit jedem synatxhiliter aufgefallen, hättest du templates genutzt)

@edit
ich soll das Formular jetzt als .py machen
Sofern das Hausaufgaben oder was ähnliches sind, verstehe ich natürlich, dass der Tipp ins leere läuft, da du dir das nicht aussuchen kannst. Ansonsten aber bleibe ich dabei ;)
Sonic
User
Beiträge: 7
Registriert: Dienstag 22. Januar 2008, 20:21

Donnerstag 24. Januar 2008, 12:28

Code: Alles auswählen

<INPUT type="radio" name"Zahlungsart" value="Visa"><br>American Express:<INPUT type="radio" name"Zahlungsart" value="American Express"><br>
Habe ich vollkommen übersehen.

Sofern das Hausaufgaben oder was ähnliches sind, verstehe ich natürlich, dass der Tipp ins leere läuft, da du dir das nicht aussuchen kannst. Ansonsten aber bleibe ich dabei Wink
Nicht direkt, bin in einem Praktikum und soll das ganze für den Betrieb machen, sozusagen als Übung. Da kann ich mir leider nicht aussuchen wie ich das machen will^^.
Sonst hätte ich das sofort ausprobiert, genauso wie pickle, was zu umständlich sein soll.
Zuletzt geändert von Sonic am Donnerstag 24. Januar 2008, 13:21, insgesamt 1-mal geändert.
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Donnerstag 24. Januar 2008, 13:06

Sonic hat geschrieben:Nicht direkt, bin in einem Praktikum und soll das ganze für den Betrieb machen.
O weia!
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Donnerstag 24. Januar 2008, 13:30

Nicht direkt, bin in einem Praktikum und soll das ganze für den Betrieb machen, sozusagen als Übung. Da kann ich mir leider nicht aussuchen wie ich das machen will^^.

Sonst hätte ich das sofort ausprobiert, genauso wie pickle, was zu umständlich sein soll.
Picklen ist eine Zeile. Textdatei schreiben und lesen ist ein größerer Aufwand.
WSGI ist nicht komplizierter als cgi, es ist aber ein Standard mit vielen anderen Vorteilen.

Sollte das ein Praktikum bei einem Softwarehaus sein, nimm die besser nicht als Arbeitgeber.
Wenn die das Produktiv einsetzen wollen, und es nicht nur Übung ist, wäre das schon eine Form ausgleichender Gerechtigkeit, da du es nur einmal schreibst, die es aber Jahrelang warten müssen :)
Antworten