473,714 Members | 2,445 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Taint (like in Perl) as a Python module: taint.py

The following is my first attempt at adding a taint feature to Python
to prevent os.system() from being called with untrusted input. What do
you think of it?

# taint.py - Emulate Perl's taint feature in Python
# Copyright (C) 2007 Johann C. Rocholl <jo****@rocholl .net>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software") , to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
"""
Emulate Perl's taint feature in Python

This module replaces all functions in the os module (except stat) with
wrappers that will raise an Exception called TaintError if any of the
parameters is a tainted string.

All strings are tainted by default, and you have to call untaint on a
string to create a safe string from it.

Stripping, zero-filling, and changes to lowercase or uppercase don't
taint a safe string.

If you combine strings with + or join or replace, the result will be a
tainted string unless all its parts are safe.

It is probably a good idea to run some checks on user input before you
call untaint() on it. The safest way is to design a regex that matches
legal input only. A regex that tries to match illegal input is very
hard to prove complete.

You can run the following examples with the command
python taint.py -v
to test if this module works as designed.
>>unsafe = 'test'
tainted(unsaf e)
True
>>os.system(uns afe)
Traceback (most recent call last):
TaintError
>>safe = untaint(unsafe)
tainted(saf e)
False
>>os.system(saf e)
256
>>safe + unsafe
u'testtest'
>>safe.join([safe, unsafe])
u'testtesttest'
>>tainted(saf e + unsafe)
True
>>tainted(saf e + safe)
False
>>tainted(unsaf e.join([safe, safe]))
True
>>tainted(safe. join([safe, unsafe]))
True
>>tainted(safe. join([safe, safe]))
False
>>tainted(safe. replace(safe, unsafe))
True
>>tainted(safe. replace(safe, safe))
False
>>tainted(safe. capitalize()) or tainted(safe.ti tle())
False
>>tainted(safe. lower()) or tainted(safe.up per())
False
>>tainted(safe. strip()) or tainted(safe.rs trip()) or tainted(safe.ls trip())
False
>>tainted(safe. zfill(8))
False
>>tainted(safe. expandtabs())
True
"""

import os
import types
class TaintError(Exce ption):
"""
This exception is raised when you try to call a function in the os
module with a string parameter that isn't a SafeString.
"""
pass
class SafeString(unic ode):
"""
A string class that you must use for parameters to functions in
the os module.
"""

def __add__(self, other):
"""Create a safe string if the other string is also safe."""
if tainted(other):
return unicode.__add__ (self, other)
return untaint(unicode .__add__(self, other))

def join(self, sequence):
"""Create a safe string if all components are safe."""
for element in sequence:
if tainted(element ):
return unicode.join(se lf, sequence)
return untaint(unicode .join(self, sequence))

def replace(self, old, new, *args):
"""Create a safe string if the replacement text is also
safe."""
if tainted(new):
return unicode.replace (self, old, new, *args)
return untaint(unicode .replace(self, old, new, *args))

def strip(self, *args):
return untaint(unicode .strip(self, *args))

def lstrip(self, *args):
return untaint(unicode .lstrip(self, *args))

def rstrip(self, *args):
return untaint(unicode .rstrip(self, *args))

def zfill(self, *args):
return untaint(unicode .zfill(self, *args))

def capitalize(self ):
return untaint(unicode .capitalize(sel f))

def title(self):
return untaint(unicode .title(self))

def lower(self):
return untaint(unicode .lower(self))

def upper(self):
return untaint(unicode .upper(self))
# Alias to the constructor of SafeString,
# so that untaint('abc') gives you a safe string.
untaint = SafeString
def tainted(param):
"""
Check if a string is tainted.
If param is a sequence or dict, all elements will be checked.
"""
if isinstance(para m, (tuple, list)):
for element in param:
if tainted(element ):
return True
elif isinstance(para m, dict):
return tainted(param.v alues())
elif isinstance(para m, (str, unicode)):
return not isinstance(para m, SafeString)
else:
return False
def wrapper(functio n):
"""Create a new function that checks its parameters first."""
def check_first(*ar gs, **kwargs):
"""Check all parameters for unsafe strings, then call."""
if tainted(args) or tainted(kwargs) :
raise TaintError
return function(*args, **kwargs)
return check_first
def install_wrapper s(module, innocent):
"""
Replace each function in the os module with a wrapper that checks
the parameters first, except if the name of the function is in the
innocent list.
"""
for name, function in module.__dict__ .iteritems():
if name in innocent:
continue
if type(function) in [types.FunctionT ype,
types.BuiltinFu nctionType]:
module.__dict__[name] = wrapper(functio n)
install_wrapper s(os, innocent = ['stat'])
if __name__ == '__main__':
import doctest
doctest.testmod ()

Feb 5 '07 #1
5 2158
En Mon, 05 Feb 2007 19:13:04 -0300, Johann C. Rocholl
<jc*******@goog lemail.comescri bió:
The following is my first attempt at adding a taint feature to Python
to prevent os.system() from being called with untrusted input. What do
you think of it?
A simple reload(os) will drop all your wrapped functions, leaving the
original ones.
I suppose you don't intend to publish the SafeString class - but if anyone
can get a SafeString instance in any way or another, he can convert
*anything* into a SafeString trivially.
And tainted() returns False by default?????

Sorry but in general, this won't work :(

--
Gabriel Genellina

Feb 6 '07 #2
"Gabriel Genellina" <ga******@yahoo .com.arwrites:
I suppose you don't intend to publish the SafeString class - but if
anyone can get a SafeString instance in any way or another, he can
convert *anything* into a SafeString trivially.
The point (in Perl) of detecting taint isn't to prevent a programmer
from deliberately removing the taint. It's to help the programmer find
places in the code where taint accidentally remains.
And tainted() returns False by default?????
Sorry but in general, this won't work :(
I'm inclined to agree that the default should be to flag an object as
tainted unless known otherwise.

--
\ "On the other hand, you have different fingers." -- Steven |
`\ Wright |
_o__) |
Ben Finney

Feb 6 '07 #3
En Mon, 05 Feb 2007 23:01:51 -0300, Ben Finney
<bi************ ****@benfinney. id.auescribió:
"Gabriel Genellina" <ga******@yahoo .com.arwrites:
>I suppose you don't intend to publish the SafeString class - but if
anyone can get a SafeString instance in any way or another, he can
convert *anything* into a SafeString trivially.

The point (in Perl) of detecting taint isn't to prevent a programmer
from deliberately removing the taint. It's to help the programmer find
places in the code where taint accidentally remains.
I'm not convinced at all of the usefulness of tainting.
How do you "untaint" a string? By checking some conditions?
Let's say, you validate and untaint a string, regarding it's future usage
on a command line, so you assume it's safe to use on os.system calls - but
perhaps it still contains a sql injection trap (and being untainted you
use it anyway!).
Tainting may be useful for a short lived string, one that is used on the
*same* process as it was created. And in this case, unit testing may be a
good way to validate the string usage along the program.
But if you store input text on a database or configuration file (username,
password, address...) it may get used again by *another* process, maybe a
*different* program, even months later. What to do? Validate all input for
any possible type of unsafe usage before storing them in the database, so
it is untainted? Maybe... but I'd say it's better to ensure things are
*done* *safely* instead of trusting a flag. (Uhmm, perhaps it's like "have
safe sex; use a condom" instead of "require an HIV certificate")

That is:
- for sql injection, use parametrized queries, don't build SQL statements
by hand.
- for html output, use any safe template engine, always quoting inputs.
- for os.system and similar, validate the command line and arguments right
before being executed.
and so on.

--
Gabriel Genellina

Feb 6 '07 #4
"Gabriel Genellina" <ga******@yahoo .com.arwrites:
I'm not convinced at all of the usefulness of tainting.
How do you "untaint" a string? By checking some conditions?
In perl? I don't think you can untaint a string, but you can make a
new untainted string by extracting a regexp match from the tainted
string's contents.
Let's say, you validate and untaint a string, regarding it's future
usage on a command line, so you assume it's safe to use on os.system
calls - but perhaps it still contains a sql injection trap (and being
untainted you use it anyway!).
Well, ok, you didn't check it carefully enough, but at least you made
an attempt. Taint checking is a useful feature in perl.
Tainting may be useful for a short lived string, one that is used on
the *same* process as it was created. And in this case, unit testing
may be a good way to validate the string usage along the program.
Unit testing is completely overrated for security testing. It checks
the paths through the program that you've written tests for. Taint
checking catches errors in paths that you never realized existed.
- for sql injection, use parametrized queries, don't build SQL
statements by hand.
- for html output, use any safe template engine, always quoting inputs.
- for os.system and similar, validate the command line and arguments
right before being executed. and so on.
Right, but it's easy to make errors and overlook things, and taint
checking catches a lot of such mistakes.
Feb 6 '07 #5
On Feb 6, 3:01 am, Ben Finney <bignose+hate s-s...@benfinney. id.au>
wrote:
"Gabriel Genellina" <gagsl...@yahoo .com.arwrites:
And tainted() returns False by default?????
Sorry but in general, this won't work :(

I'm inclined to agree that the default should be to flag an object as
tainted unless known otherwise.
That's true. For example, my first attempt didn't prevent this:
os.open(buffer( '/etc/passwd'), os.O_RDONLY)

Here's a stricter version:

def tainted(param):
"""
Check if a parameter is tainted. If it's a sequence or dict, all
values will be checked (but not the keys).
"""
if isinstance(para m, unicode):
return not isinstance(para m, SafeString)
elif isinstance(para m, (bool, int, long, float, complex, file)):
return False
elif isinstance(para m, (tuple, list)):
for element in param:
if tainted(element ):
return True
elif isinstance(para m, dict):
return tainted(param.v alues())
else:
return True

Feb 6 '07 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
1895
by: leegold2 | last post by:
Hi, I Perl there's that -t option that's supposed to check input for anything nasty. I wondered if there's anything link that in PHP? Some module? Or some tested block of PHP code that will do it? I'd be grateful for any links to info. Thanks, Lee G.
4
2689
by: Ravi | last post by:
Hi, I did some googling, and found that there doesn't seem to be a pure python MySQL communication module. There is one for perl however, Net::MySQL. I was wondering if there was a specific reason why something similar hasn't been implemented in Python, a limitation of the language or libraries perhaps? I briefly scanned through the perl source for Net::MySQL, and there doesn't seem to be anything that couldn't be done in Python, but...
0
1165
by: Xah Lee | last post by:
© # -*- coding: utf-8 -*- © # Python © © # once a module is loaded © # import mymodule © # one can find all the names it © # export with dir() © © import sys © print dir(sys)
4
1433
by: Xah Lee | last post by:
# -*- coding: utf-8 -*- # Python # some venture into standard modules import os # print all names exported by the module print dir(os)
9
3214
by: Xah Lee | last post by:
# -*- coding: utf-8 -*- # Python # Matching string patterns # # Sometimes you want to know if a string is of # particular pattern. Let's say in your website # you have converted all images files from gif # format to png format. Now you need to change the # html code to use the .png files. So, essentially
2
2540
by: Xah Lee | last post by:
# -*- coding: utf-8 -*- # Python # suppose you want to fetch a webpage. from urllib import urlopen print urlopen('http://xahlee.org/Periodic_dosage_dir/_p2/russell-lecture.html').read() # note the line # from <library_name> import <function_name1,function_name2...>
4
1904
by: Xah Lee | last post by:
20050207 text pattern matching # -*- coding: utf-8 -*- # Python # suppose you want to replace all strings of the form # <img src="some.gif" width="30" height="20"> # to # <img src="some.png" width="30" height="20"> # in your html files.
0
4006
by: Kristina Clair | last post by:
Hi, I have a perl script running suid root (thus running in taint mode), and I'm trying to execute a shell command. Usually I do this using backticks so I can get the output, and usually it is not a problem. However, in this instance I am trying to execute a python script, and the python script does not seem to be running as root, but as the apache user.
0
1008
by: Reedick, Andrew | last post by:
<snip> I have a Perl background and have found the O'Reilly books to be useful. The Learning Python book (or whatever it's called) is good because it covers the paradigm shifts and potential gotchas that you won't even consider thinking about otherwise. Only downside is wading through the novice 'how to program' parts. The Cookbook is also good for getting 'standard' apps up and running quickly (meaning you know how to do it in Perl,...
0
8810
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
9078
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9026
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7955
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5959
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4466
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
1
3160
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
2526
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2113
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.