4 ms·
Yes, but it's not obvious how to sanitize input in this case, or that it even needs sanitizing. Formatting a string sounds pretty innocuous.
by raquo 10y ago
Yes, but it's not obvious how to sanitize input in this case, or that it even needs sanitizing. Formatting a string sounds pretty innocuous.
- userbinator 10y agoI think "it's not obvious how to sanitize input" is the main point here --- one advantage of the %-style format strings, they're easier to parse and escape.
- tedunangst 10y agoBut we don't want the string escaped. We want it interpreted.
- jgalt212 10y agoyes, basically eval is evil
- xapata 10y agoAnd yet, eval is necessary for so many important things...
- masklinn 10y agoThat's not even eval, the entire thing is a series of dynamic attribute lookups[0], you can trivially implement that in pure Python without needing to `eval` anything. [0] it also supports mapping and sequence lookups IIRC but that's about the same thing
- tzs 10y agoWe want it interpreted, but we don't have to let the language handle it directly. A much safer way is to define our own syntax for this and interpret it in our code, with that code only having access to a limited set of safe substitutions. For instance, suppose we want to allow user formatting of contact information. A contact entry has a name, address, phone number, and email address. The user supplies a template string using %_NAME_, %_ADDR_, %_PHONE_, and %_EMAIL where they would like the name, address, phone number, and email address substituted, respectively. I'd probably be doing this in Perl, and I'd do it something like this: sub format_contact { my($template, $name, $addr, $phone, $email) = @_; my %val = (name => $name, addr => $addr, phone => $phone, email => $email); $template =~ s/%_([a-z]+)_/$val{lc($1)}/gi; return $template; }
- onchance 10y agoWould sanitizing for double underscores be enough to capture the most dangerous cases? import re def sanitize(user_input): """Sanitize user input for str.format Usage: sanitize("{post.title} - {post.blog.title}") sanitize("{post.title}: Another fine post by "{post.author}") sanitize("~~~ xXx {post.blog.__init__.dbconnection.__keys__.password} xXx ~~~") """ return re.sub(r'{[^}]*__[^}]*}', '', user_input) Even better, we could specify which variables to allow in user input: import re def sanitize(user_input, *allowed_variables): """Sanitize user input for str.format Usage: allowed_variables = ["post.blog.title", "post.title", "post.author"] sanitize("{post.title} - {post.blog.title}", *allowed_variables) sanitize("{post.title}: Another fine post by "{post.author}", *allowed_variables) sanitize("~~~ xXx {post.blog.__init__.dbconnection.__keys__.password} xXx ~~~", *allowed_variables) """ for match in re.finditer(r'{([^}]*)}', user_input): if match[1] not in allowed_variables: user_input = user_input.replace(match[0], '') return user_input