webserver programmieren mit ssl verschlüsselung ???

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
hmikux

Hallo Leute,
ich versuche mich gerade in Python einzuarbeiten und benutze hierzu das Buch "Python ge-packt" von M.Weigend. Einen einfachen webserver mit cgi-unterstützung zu programmieren ist ja nicht schwer! Jedoch frage ich mich nun inwieweit man einen "sicheren" webserver programmieren kann, der mit ssl arbeitet - jeglicher traffic zwischen client und server sollte verschlüsselt sein.

Als einfachen Webserver benutze ich das code-Beispiel aus dem Buch:

Code: Alles auswählen

#!/usr/local/bin/python
from BaseHTTPServer import HTTPServer
from CGIHTTPServer import CGIHTTPRequestHandler
serveradresse=("", 8080)
server=HTTPServer(serveradresse,CGIHTTPRequestHand ler)
server.serve_forever()
Mit Hilfe des md5-Moduls baue ich mir eine Startseite mit Authentifizierung! Jedoch bringt mir die Authentifizierung nichts, wenn jeglicher traffic unverschlüsselt ueber das netz geht.

Ist python hierzu auch geeignet, oder sollte ich da gleich auch apache zurückgreifen? Möchte einen webserver auf meinem "MiniLinux" aufbauen um meinen VDR-server zu steuern - dabei lediglich python, bash, html inkl. cgi-scripte benutzen.

hmikux
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

SSL Unterstützung wäre schon cool, wünschte ich mir auch. Aber ich hab keinen Plan wie man es realisiert...
Im Prinzip könnte man auf einem Linux Rechner, den Server mit OpenSLL kapseln, oder?

Ansonsten kann ich dir mal raten diesen http://python.sandtner.org/viewtopic.php?t=2741 Thread durch zu lesen... Damit kannst du den Server auf den lokalen IP-Bereich einschränken, wenn du ihn nicht gerade durch's Internet Administrieren willst, ist das schon mal was ;)
Beyond
User
Beiträge: 227
Registriert: Freitag 6. September 2002, 19:06
Kontaktdaten:

Ja. Würde ich auch so machen. Nimm z.B. den Apache (gibt's sogar für Windows), der kann SSL. Dann machst Du einen Forward auf den Python-Server (der nur lokale Zugriffe erlaubt).

cu beyond
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Einfacher wäre es allerdings, wenn SSL direkt mit dem Python-Server gehen würde... Apache ist ja nicht gerade ein kleines Mini-Tool ;)
hmikux

Hi, wenn ich den apache nehme, kann ich auf meinen Python webserver verzichten. Das war ja nicht Sinn der Sache.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Du kannst:
1) pyopenssl nutzen (ich habe auch aktuelle Windows Binaries gemacht)
2) Stunnel oder SSLWrap nutzen, um deinen Server in SSL verschlüsselung zu kapseln.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hast du es selber mal versucht? Hast du Beispielcode, wie man ein CGIHTTPServer einfach erweitern kann?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Also mit PyOpenSSL müsste das so ähnlich gehen wie mit dem SecureXMLRPCServer Beispiel.

Und stunnel ist eine ganze andere Sache, ist externes kapseln, so dass Python gar nicht weiß, dass die Verbindung über SSL läuft.

Edit: TLS Lite scheint auch gar nicht schlecht zu sein. In dem Fall wäre wohl die Integration über SocketServer angebracht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

TLS Lite sieht wirklich interessant aus! Es scheint auch völlig ohne andere Pakete zu funktionieren. Allerdings kann es auch verschiedene andere Pakete wie z.B. M2Crypto nutzen, was alles ein wenig schneller machen sollte...

In der Readme: http://trevp.net/tlslite/readme.txt steht unter Punkt 10 ein einfaches Beispiel:

Code: Alles auswählen

  from SocketServer import *
  from BaseHTTPServer import *
  from SimpleHTTPServer import *
  from tlslite.api import *

  s = open("./serverX509Cert.pem").read()
  x509 = X509()
  x509.parse(s)
  certChain = X509CertChain([x509])

  s = open("./serverX509Key.pem").read()
  privateKey = parsePEMKey(s, private=True)

  sessionCache = SessionCache()

  class MyHTTPServer(ThreadingMixIn, TLSSocketServerMixIn, HTTPServer):
      def handshake(self, tlsConnection):
          try:
              tlsConnection.handshakeServer(certChain=certChain,
                                            privateKey=privateKey,
                                            sessionCache=sessionCache)
              tlsConnection.ignoreAbruptClose = True
              return True
          except TLSError, error:
              print "Handshake failure:", str(error)
              return False

  httpd = MyHTTPServer(('localhost', 443), SimpleHTTPRequestHandler)
  httpd.serve_forever()
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Genau. Nur die Performance von pure Python SSL braucht dich dann nicht zu wundern. Ich würde das ja testen, hab nur dummerweise null Ahnung von SSL, müsste mir jemand schnell sagen, wie ich die Certs und Keys erstelle. Am besten du kombinierst es mit pycrypto, dann geht das auch unter Windows (zwei pycrypto py2.4 Binaries Vorhanden) und vermutlich auch entsprechend schneller. M2Crypto soll laut GvR promlematisch sein.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Okay... aber tlslite hat doch scheinbar einige C Module... ich habe den Quellcode mal mit

Code: Alles auswählen

#include <wincrypt.h>
erweitert um auch an HCRYPTPROV ranzukommen, und das Modul entropy auch gleich miterstellt.

Wie immer, Binary ohne Garantie.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

In der readme steht aber was anderes:
TLS Lite is pure python, however it can access OpenSSL [4],
cryptlib [5], pycrypto [9], and GMPY [10] for faster crypto operations.
Naja, vielleicht ist die ja mittlerweile etwas veraltet???
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Vielleicht sind die nicht wirklich nötig, und es lässt sich wie dort geschrieben ohne weitere sachen betreiben.
Aber schau selbst: im Tarball sind unter tlslite/utils zwei C Dateien. Win32prng ist ein Pseudozufallszahlengenerator (wie random und crnd).
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab mal versucht einen Server zu bauen. Allerdings so, das man tlslite nicht installieren muß. Es muß nur im Verz "tlslite" liegen:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-

import CGIHTTPServer, SocketServer, socket
import BaseHTTPServer
import os, sys

sys.path.append("tlslite")
sys.path.append("tlslite/integration")
sys.path.append("tlslite/utils")

import TLSSocketServerMixIn
import X509
import X509CertChain
import keyfactory
import SessionCache

def getFile( fileName ):
    f = file( fileName, "r")
    c = f.read()
    f.close()
    return c

x509 = X509.X509()
x509.parse( getFile("./cert.pem") )
certChain = X509CertChain.X509CertChain([x509])

privateKey = keyfactory.parsePEMKey( getFile( "./key.pem" ), private=True )

sessionCache = SessionCache.SessionCache()


class MyHTTPServer( SocketServer.ThreadingMixIn,
                TLSSocketServerMixIn.TLSSocketServerMixIn,
                BaseHTTPServer.HTTPServer ):
    def handshake(self, tlsConnection):
        #~ try:
            tlsConnection.handshakeServer( certChain=certChain,
                                   privateKey=privateKey,
                                   sessionCache=sessionCache )
            tlsConnection.ignoreAbruptClose = True
            return True
        #~ except TLSError, error:
            #~ print "Handshake failure:", str(error)
            #~ return False


httpd = MyHTTPServer(("", 443), CGIHTTPServer.CGIHTTPRequestHandler)
print "Server gestartet: https://localhost"
httpd.serve_forever()
Ich bekomme allerdings Fehler, wenn ich im Browser die Seite aufrufen will. Ich hab extra bei handshake() die Fehler-Abfrage auskommentiert, damit man die vollständige Fehlermeldung erhält:

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\Python\Python24\lib\SocketServer.py", line 463, in process_request_thread
    self.finish_request(request, client_address)
  File "D:\Python\HTTPsServer\tlslite\integration\TLSSocketServerMixIn.py", line 52, in finish_request
    if self.handshake(tlsConnection) == True:
  File "SocketServer1.py", line 40, in handshake
    sessionCache=sessionCache )
  File "D:\Python\HTTPsServer\tlslite\TLSConnection.py", line 1009, in handshakeServer
    checker):
  File "D:\Python\HTTPsServer\tlslite\TLSConnection.py", line 1032, in handshakeServerAsync
    for result in self._handshakeWrapperAsync(handshaker, checker):
  File "D:\Python\HTTPsServer\tlslite\TLSConnection.py", line 1537, in _handshakeWrapperAsync
    for result in handshaker:
  File "D:\Python\HTTPsServer\tlslite\TLSConnection.py", line 1075, in _handshakeServerAsyncHelper
    raise ValueError("Unrecognized certificate type")
ValueError: Unrecognized certificate type
Liegt vielleicht auch an den Zertifikaten... Ich habe die beiden Dateien unter Linux mit openssl erstellt:

Code: Alles auswählen

openssl genrsa -out key.pem 2048
openssl req -new -x509 -days 1460  -key key.pem -out cert.pem
EDIT: Achso, ich möchte gern tlslite benutzen ohne installation, damit man es evtl. auch auf dem Web-Server benutzen kann, wo man keine Module nachinstallalieren kann... Da tlslite ja in pures Python geschrieben ist, sollte es möglich sein... Aber dazu muß es erstmal generell funktionieren...
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Leonidas hat geschrieben:Wie immer, Binary ohne Garantie.
Hab gerade gesehen... in der ZIP-Version, die ich mir herrunter geladen hab, sind Windows Installer für Python v2.3 und v2.4 schon dabei! Sie liegen im Verz. "Installers"
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ja sowas. Darauf muss man erst kommen... ich lad mir meist grundsätzlich die gzips runter wenn ich Quellcode will, auch wenn Zips da sind. Tja, dumm gelaufen. Dann nutz lieber die Installer aus dem ZIP, ist wohl besser.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Also ich komme nicht so recht weiter... Ich erhalte immer den Fehler "Unrecognized certificate type"...

Einen Fingerprint erhalte ich aber mit "certChain.getFingerprint()"...

Hab mit ein wenig die API-Doku http://trevp.net/tlslite/docs/index.html angeschaut, hilft aber auch nicht so ganz...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ich bekam immer den Fehler "Incorrect padding", aaaber ich habe mich mal etwas reingehängt:

Code: Alles auswählen

#!/usr/bin/env python
# -*- encoding: latin-1 -*-
import SocketServer, BaseHTTPServer, CGIHTTPServer
import tlslite.api

class MyHTTPServer(SocketServer.ThreadingMixIn, 
        tlslite.api.TLSSocketServerMixIn, 
        BaseHTTPServer.HTTPServer):
            
    def handshake(self, tlsConnection):
        try:
            tlsConnection.handshakeServer(certChain=certChain,
                                          privateKey=privateKey,
                                          sessionCache=sessionCache)
            tlsConnection.ignoreAbruptClose = True
            return True
        except tlslite.api.TLSError, error:
            print "Handshake failure:", str(error)
            return False

def getfile(filename):
    f = file(filename)
    content = f.read()
    f.close()
    return content
    

def main():
    s = getfile("cacert.pem")
    x509 = tlslite.api.X509()
    x509.parse(s)
    global certChain
    certChain = tlslite.api.X509CertChain([x509])

    s = getfile("cakey.pem")
    global privateKey
    privateKey = tlslite.api.parsePEMKey(s, private=True)

    global sessionCache
    sessionCache = tlslite.api.SessionCache()

    httpd = MyHTTPServer(('localhost', 443), CGIHTTPServer.CGIHTTPRequestHandler)
    httpd.serve_forever()

if __name__ == '__main__':
    main()
Das heißt natürlcih nicht, das der Code gut ist, die globals nerven, ist aber nur ein schneller Hack. Die Zertifikate habe ich mir unter Windows mit OpenSSL 0.9.7e erstellt:

Code: Alles auswählen

openssl genrsa 2048 > cakey.pem
openssl req -new -x509 -days 30  -key private/cakey.pem -out cacert.pem 
wobei ich beim zweiten halt die Werte eingestellt habe. Der Schlüssel hat kein Passwort, aber das sollte irgendwie mit dem passwortCallback von parsePEMKey zu lösen sein.

Und siehe da, Firefox zeigt ein Directory Listning ohne zu murren über HTTPS dar.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wow! Super, jetzt klappt es bei mir auch! Sogar in meiner nicht installierten tlslite-Version!
Die Verz. Struktur:

Code: Alles auswählen

/MeinServer.py
/tlslite
/tlslite/integration
/tlslite/utils
Ich hab MeinServer.py noch mal umstrukturiert, sodas man kein global verwenden muß... Läuft aber im Prinzip auf's selbe hinaus:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: ISO-8859-1 -*-

import sys,os,SocketServer, BaseHTTPServer, CGIHTTPServer
import webbrowser

sys.path.append(os.getcwd()+"\\tlslite")
sys.path.append(os.getcwd()+"\\tlslite\\integration")
sys.path.append(os.getcwd()+"\\tlslite\\utils")

import tlslite.api


def getfile(filename):
    f = file(filename)
    content = f.read()
    f.close()
    return content


x509 = tlslite.api.X509()
x509.parse( getfile("cacert.pem") )
certChain = tlslite.api.X509CertChain([x509])

privateKey = tlslite.api.parsePEMKey( getfile("cakey.pem"), private=True)

sessionCache = tlslite.api.SessionCache()



class MyHTTPServer(SocketServer.ThreadingMixIn,
        tlslite.api.TLSSocketServerMixIn,
        BaseHTTPServer.HTTPServer):

    def handshake(self, tlsConnection):
        try:
            tlsConnection.handshakeServer(certChain=certChain,
                                          privateKey=privateKey,
                                          sessionCache=sessionCache)
            tlsConnection.ignoreAbruptClose = True
            return True
        except tlslite.api.TLSError, error:
            print "Handshake failure:", str(error)
            return False

if __name__ == '__main__':
    httpd = MyHTTPServer(('localhost', 443), CGIHTTPServer.CGIHTTPRequestHandler)
    print "Server gestartet: https://127.0.0.1:443"
    webbrowser.open_new("https://127.0.0.1:443") # Öffne Browser
    httpd.serve_forever()
Jetzt wird die Sache Interessant! Das ganze ein wenig Aufzubohren:
-Einschränken auf IP-Bereich
-Auf ThreadingTCPServer umstellen
8)

Dadurch das man tlslite nicht wirklich installieren muß, könnte man das ganze evtl. auf einen Web-Server einrichten und dort quasi einen Virtuellen HTTPs Server öffnen... Die Sourcen und die *.pem-Dateien per FTP auf den Server packen und fertig...
Naja, ich denke allerdings, das es wahrscheinlich nicht möglich ist, da man bestimmt nicht einfach einen Port "öffnen" darf... Aber Versuchen kann man es ja mal...

EDIT: Gesagt, getan: Schade, ich hab's mir schon gedacht, es geht nicht:
File "/usr/lib/python2.2/SocketServer.py", line 329, in __init__
self.server_bind()
File "/usr/lib/python2.2/BaseHTTPServer.py", line 94, in server_bind
SocketServer.TCPServer.server_bind(self)
File "/usr/lib/python2.2/SocketServer.py", line 340, in server_bind
self.socket.bind(self.server_address)
socket.error: (13, 'Permission denied')
Zuletzt geändert von jens am Dienstag 1. März 2005, 14:11, insgesamt 1-mal geändert.
Antworten