[FRPythoneers] Python CGI & Security

Evelyn Mitchell efm at tummy.com
Sun Jul 14 16:59:02 MDT 2002


Where is IllegalStateError defined? infomail.py tracebacks:

[efm at gwen pychecker-0.8.10]$ python  /home/efm/infomail.py
Traceback (innermost last):
  File "/home/efm/infomail.py", line 83, in ?
    InfoRequestMailer().run()
  File "/home/efm/mailer.py", line 61, in run
    if self.validate_form():
  File "/home/efm/mailer.py", line 38, in validate_form
    raise IllegalStateError
NameError: IllegalStateError

In mailer.py OK is defined 3 times. Once as a global, at line 99 as
a local, and at line 120 as a local. This may not have the effect you
expect. You probably want to pass 'OK' as a parameter.

RATS complains that re.compile is a dangerous call:
   Argument 1 to this function call should be checked to ensure that it
   does not come from an untrusted source without first verifying that it
   contains nothing dangerous.


* On 2002-07-10 05:02 Matt Gushee <mgushee at havenrock.com> wrote:
> 
> ------- mailer.py ---------------------------------------------------
> 
> #!/usr/bin/python
> 
> import cgi, StringIO, string, smtplib, sys, re, MimeWriter
> from types import InstanceType
> 
> OK = 0
> 
> # Config
> 
> MAILSERVER     = "MAILSERVER"
> ADDRESSES      = {}
> SENDER         = "webform at itsamaritans.org"
> SUBJECTS       = {}
> SKIP_FIELDS    = ['email']
> ERROR_TEMPLATE = "ERROR_TEMPLATE"
> OK_TEMPLATE    = "OK_TEMPLATE"
> FAIL_ON_EXTRA  = 1   # Abort if extraneous fields are found? 
> 
> class Mailer:
>     # Note: this isn't 100% compliant w/ RFC822 but should be close enough
>     email_expr = re.compile(r'^[^][()<>,;:\\"\s\000-\037]+@[^][()<>,;:\\"\s\000-\037]+$')
>     def __init__(self, **kwargs):
>         self.mailserver = kwargs.get('mailserver',MAILSERVER)
>         self.addresses = kwargs.get('addresses',ADDRESSES)
>         self.sender = kwargs.get('sender',SENDER)
>         self.subjects = kwargs.get('subjects',SUBJECTS)
>         self.skip_fields = kwargs.get('skip_fields',SKIP_FIELDS)
>         self.error_template = kwargs.get('error_template',ERROR_TEMPLATE)
>         self.ok_template = kwargs.get('ok_template',OK_TEMPLATE)
>         self.fail_on_extra = kwargs.get('fail_on_extra',FAIL_ON_EXTRA)
>         self.form = None
>         self.valid_funcs = {}
>         self.field_status = {}
>         
>     def validate_form(self):
>         form = self.form
>         if not form:
>             raise IllegalStateError
>         elif (type(form) is not InstanceType or
>               form.__class__ is not cgi.FieldStorage):
>             raise ValueError
>         has_errors = 0
>         for fname in form.keys():
>             vfunc = self.valid_funcs.get(fname,None)
>             if vfunc:
>                 (valid,error) = vfunc(form[fname].value)
>                 self.field_status[fname] = (valid,error)
>                 if not valid:
>                     has_errors = 1
>             elif self.fail_on_extra:
>                 raise ValueError, "Invalid field name: '%s'" % fname
>         return not has_errors
> 
>     def _validate_email(self,address):
>         if self.email_expr.match(string.strip(address)): return 1
>         else: return 0
>         
>     def run(self):
>         self.form = form = cgi.FieldStorage()
>         field_status = self.field_status
>         if self.validate_form():
>             category = form['category'].value
>             recipient = self.addresses[category]
>             
>             # Create output control
> 
>             out = StringIO.StringIO()
>             mail = MimeWriter.MimeWriter(out)
>             mail.addheader("Subject", self.subjects[category])
> 
>             # Set up the email
> 
>             mail.addheader("To", recipient)
>             mail.addheader("From", self.sender)
>     
>             # Quick check
>             assert self.mailserver != "MAILSERVER" and \
>                    recipient != "ADDRESS"
> 
>             # Write email body
>     
>             fp = mail.startbody("text/plain")
>             
>             for fieldname in field_status.keys():
>                 if fieldname not in self.skip_fields:    
>                     fp.write("---" + fieldname + ": \n")
>                     fp.write(form[fieldname].value + "\n\n")
> 
>             # Send email    
>             mail = smtplib.SMTP(self.mailserver)
>             mail.sendmail(self.sender, recipient, out.getvalue())
>         
>             # Print confirmation
>         
>             print "Content-Type: text/html; charset=ISO-8859-1\n\n"
>         
>             print open(self.ok_template).read()
>             
>             OK = 1
>                     
>         else:
>             err_dict = {}
>             for k in self.valid_funcs.keys():
>                 err_dict[k] = ""
>             err_report = '    <ul class="ErrorMessage">\n'
>             for fname in field_status.keys():
>                 if field_status[fname][0]:
>                     err_dict[fname] = form[fname].value
>                 else:
>                     err_dict[fname] = ""
>                     err_report = "%s      <li>%s</li>\n" % (err_report,
>                                                             field_status[fname][1])
>             err_report = "%s    </ul>\n" % err_report
>             err_dict['err_report'] = err_report
> 
>             print "Content-Type: text/html; charset=ISO-8859-1\n\n"
> 
>             print open(self.error_template).read() % err_dict
> 
>             OK = 1
>             sys.exit()
> 
> 
> ------------ infomail.py ----------------------------------------------
> 
> #!/usr/bin/env python
> 
> import mailer, cgi, string
> from types import InstanceType
> 
> # Config
> 
> MAILSERVER     = "mail.itsamaritans.org"
> #MAILSERVER     = "mail.hypermall.net"
> ADDRESSES      = {'volunteer':'volunteer at itsamaritans.org',
>                   'services':'services at itsamaritans.org',
>                   'general':'info at itsamaritans.org'}
> #ADDRESSES      = {'volunteer':'mgushee at havenrock.com',
> #                  'services':'mgushee at havenrock.com',
> #                  'general':'mgushee at havenrock.com'}
> SUBJECTS       = {'volunteer':"Volunteer Inquiry",
>                   'services':"Service Inquiry",
>                   'general':"Information Request"}
> SKIP_FIELDS    = ['category']
> #ERROR_TEMPLATE = "/var/www/templates/badmail_html"
> ERROR_TEMPLATE = "/home/mjmikelson/templates/badmail_html"
> #OK_TEMPLATE    = "/var/www/templates/mailok_html"
> OK_TEMPLATE    = "/home/mjmikelson/templates/mailok_html"
> 
> # maximum characters for text fields
> NAME_LEN = 128       
> EMAIL_LEN = 128       
> PHONE_LEN = 32
> QUESTION_LEN = 4096
> 
> 
> class InfoRequestMailer(mailer.Mailer):
> 
>     def __init__(self):
>         mailer.Mailer.__init__(self,mailserver=MAILSERVER,
>                                addresses=ADDRESSES,subjects=SUBJECTS,
>                                skip_fields=SKIP_FIELDS,
>                                error_template=ERROR_TEMPLATE,
>                                ok_template=OK_TEMPLATE)
>         self.valid_funcs = {'category': self.validate_category,
>                            'name': self.validate_name,
>                            'email': self.validate_email,
>                            'phone': self.validate_phone,
>                            'contactpref': self.validate_contactpref,
>                            'question': self.validate_question}
>     def validate_category(self,input):
>         if input in ('volunteer','services','general'):
>             return (1,None)
>         else:
>             return (0,"Please use the form.")
>     def validate_name(self, input):
>         if not input:
>             return (0,"You must enter your name.")
>         elif len(input) > NAME_LEN:
>             return (0,"Your name must have 128 or fewer characters.")
>         else:
>             return (1, None)
>     def validate_email(self, input):
>         if not input:
>             return (0,"You must enter a valid e-mail address.")
>         elif len(input) > EMAIL_LEN:
>             return (0,"Your e-mail address must have 128 or fewer characters.")
>         elif self._validate_email(input):
>             return (1, None)
>         else:
>             return (0,"You must enter a valid e-mail address.")
>     def validate_phone(self, input):
>         if input and (len(input) < 7 or len(input) > PHONE_LEN): 
>             return (0,"You appear to have entered an invalid phone number.")
>         else:
>             return (1, None)
>     def validate_contactpref(self,input):
>         if input in ('email','phone'):
>             return (1,None)
>         else:
>             return (0,"Please use the form.")
>     def validate_question(self, input):
>         if input and len(input) > QUESTION_LEN:
>             return (0,"Your question may only have 4096 characters (about 600 words).")
>         else:
>             return (1, None)
> 
> InfoRequestMailer().run()

-- 
Regards,                    tummy.com, ltd 
Evelyn Mitchell             Linux Consulting since 1995
efm at tummy.com               Senior System and Network Administrators
                            http://www.tummy.com/



More information about the FRPythoneers mailing list