Live data from Hacker News

Be Careful with Python's New-Style String Format

lucumr.pocoo.org

31–40 of 155 posts

Re: Be Careful with Python's New-Style String Format

#31
While I agree this is a possible attack vector, I think it is extremely unlikely, at least in the localization realm, for several reasons:

1. The localization company should never know what programming language you're using.

2. You shouldn't give localization companies direct access to your internal strings. More than hacking your code, they're almost guaranteed to screw the formatting up.

3. Typically, translators are hired for their native language abilities, and not for their technical prowess. I've met precious few who knew how to open a text editor, let alone hack your product via its strings.

I worked with Python and I18N/L10N for about 15 years. The way I always handled localization was to parse all our strings into a PostgreSQL database, and then provide a web interface for translators to do their work. This interface provided translators with the full-context of the strings they were translating, which internal strings often don't, prevented the inclusion of certain characters and keywords, and kept the translators from screwing up the formatting. By doing it this way, we got much better translations, and our internal strings were never out of our control.

Re: Be Careful with Python's New-Style String Format

#32
post #5

I do love writing python, but it's pretty shocking when I find out you can write something like `event.__init__.__globals__[CONFIG][SECRET_KEY]`. That language just does not care about privacy or information hiding at all, I guess.

I'd love to hear your perspectives on Ruby if this bothers you that much.

Re: Be Careful with Python's New-Style String Format

#33
post #5

I do love writing python, but it's pretty shocking when I find out you can write something like `event.__init__.__globals__[CONFIG][SECRET_KEY]`. That language just does not care about privacy or information hiding at all, I guess.

Python's general mentality can be summed as "We are all consenting adults here". If you want to access some part of program or data, you generally can, but the burden of not breaking anything while messing with internals is on you. This is a great power, but also can become an unlimited source of bugs.

[deleted]

Re: Be Careful with Python's New-Style String Format

#34
post #5

I do love writing python, but it's pretty shocking when I find out you can write something like `event.__init__.__globals__[CONFIG][SECRET_KEY]`. That language just does not care about privacy or information hiding at all, I guess.

You can do the same thing in Java with reflection. Don't let users run untrusted code. Full stop. If you need templating use a sandbox like jinja2.

The discovered vulnerability manifested itself in jinja2.

Edit: release notes https://www.palletsprojects.com/blog/jinja-281-released/

Re: Be Careful with Python's New-Style String Format

#35
post #9

No, Rust does not have the ability to access any variable in the program via a format string. Rust has this: format!("{argument}", argument = "test"); // => "test" That's just named arguments to the format. Also, that's a macro; it's expanded at compile time. Python's approach is lame. It should have used something with a limited list of named arguments, or maybe a dict.

Neither does python. The problem being discussed here is that the format string can access and attribute of the object passed in. From PEP3101 [0]: " Unlike some other programming languages, you cannot embed arbitrary expressions in format strings. This is by design - the types of expressions that you can use is deliberately limited. Only two operators are supported: the '.' (getattr) operator, and the '[]' (getitem)…

> Neither does python.

I would argue that being able to access any global value is a sufficient enough concern.

Re: Be Careful with Python's New-Style String Format

#36
Sane Lisp approach: provide easily analyzable target syntax.

  This is the TXR Lisp interactive listener of TXR 163.
  Use the :quit command or type Ctrl-D on empty line to  exit.
  1> (defvar foo 42)
  foo
  2> `@(list foo) ... @foo`
  "42 ... 42"
What is that backticked literal? Let's quote it:

  3> '`@(list foo) ... @foo`
  `@(list foo) ... @foo`
Hmm, prints back in same form. Probably syntactic sugar for a list; what is in the car? cdr?

  4> (car '`@(list foo) ... @foo`)
  sys:quasi
  5> (cdr '`@(list foo) ... @foo`)
  ((list foo) " ... " @foo)
What if we type in this syntax ourselves:

  6> '(sys:quasi (list foo) " ... " (sys:var foo))
  `@(list foo) ... @foo`
Prints as the notation!

To sandbox this, we just have to walk a list and enforce some rule. For instance, the rule might be that all elements after sys:quasi must be string object or else (sys:var sym) forms, where sym is a symbol on some allowed list. Thus (list foo) would be banned.

A custom interpreter which calculates the output string while enforcing the check is trivial to write as a one-liner.

Of course if your program just eval such an untrusted quasiliteral, it has access to the dynamic/global evironment:

   `Mouhaha! @(file-get-string "/etc/passwd")`
Very convenient for some attacker. :)

Re: Be Careful with Python's New-Style String Format

#39
The proposed idea of relying on undocumented internals and blacklisting attribute names to securely sandbox formatting strings is _really_ _dangerous_. Never do that in production code! Language expansions could render your sandbox unsafe at any time.

You can write your own safe formatting engine in much less code.

    def safe_format(fmt, **args):
        return re.sub(r'\{([^{}]*)\}', lambda m: args.get(m.group(1)), fmt)
    
    safe_format('{foo} {bar}', foo='Hello', bar='world')  # Hello world
Add bells and whistles as desired.
Post reply on HN