Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Chris Angelico Newsgroups: comp.lang.python Subject: Re: WP-A: A New URL Shortener Date: Sat, 26 Mar 2016 10:04:06 +1100 Lines: 149 Message-ID: References: <1537bd9e261.12a0e5b4a204345.4468160629979098801@vmesel.com> <500E8DF1-DCAC-4923-BD94-06DA1716484A@vmesel.com> <1964524.jFVgOtWIx9@PointedEars.de> <2334208.C0ktZ5B2k1@PointedEars.de> <4500052.tJGngFWhWt@PointedEars.de> <7663219.M9yg8PEDtW@PointedEars.de> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Trace: news.uni-berlin.de 2WjbqDQfc8Jfc4a5GwfAIAEAMTHGpcSp09YF4VXDTe2g== Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'context': 0.05; 'paths': 0.05; 'testing,': 0.05; 'deny': 0.07; 'escape': 0.07; 'postgresql': 0.07; 'cc:addr:python-list': 0.09; 'back-end': 0.09; 'given,': 0.09; 'incorrect': 0.09; 'orm': 0.09; 'parameter.': 0.09; 'recommends': 0.09; 'statements': 0.09; 'underlying': 0.09; 'stored': 0.10; 'python': 0.10; '(%s)",': 0.16; '*and': 0.16; '*you*': 0.16; '2016': 0.16; 'code?': 0.16; 'conn': 0.16; 'database).': 0.16; 'decent': 0.16; 'enlighten': 0.16; 'from:addr:rosuav': 0.16; 'from:name:chris angelico': 0.16; 'partly': 0.16; 'perfect.': 0.16; 'php)': 0.16; 'plan"': 0.16; 'postgresql)': 0.16; 'query,': 0.16; 'query.': 0.16; 'received:io': 0.16; 'received:psf.io': 0.16; 'run-time.': 0.16; 'semantically': 0.16; 'statement.': 0.16; 'statements,': 0.16; 'subject:URL': 0.16; 'value:': 0.16; 'wrote:': 0.16; 'case.': 0.18; '(in': 0.18; 'variable': 0.18; 'language': 0.19; '>>>': 0.20; 'cc:2**0': 0.20; 'cc:addr:python.org': 0.20; 'prevent': 0.20; "aren't": 0.22; 'correctly.': 0.22; 'latter': 0.22; 'programming': 0.22; 'am,': 0.23; 'code,': 0.23; 'code.': 0.23; 'daniel': 0.23; 'sat,': 0.23; 'thanks,': 0.24; 'second': 0.24; 'written': 0.24; 'header:In-Reply-To:1': 0.24; 'all.': 0.24; 'command': 0.26; '(which': 0.26; 'chris': 0.26; 'external': 0.27; 'bugs': 0.27; 'parameters': 0.27; 'least': 0.27; 'message- id:@mail.gmail.com': 0.27; 'cool': 0.27; 'processed': 0.27; 'reaches': 0.27; 'said,': 0.27; 'then.': 0.27; 'this.': 0.28; "skip:' 10": 0.28; 'values': 0.28; 'db2': 0.29; 'doing?': 0.29; 'embed': 0.29; 'necessary,': 0.29; 'procedures.': 0.29; 'really,': 0.29; 'code': 0.30; 'query': 0.30; 'option': 0.31; 'statement': 0.32; 'options': 0.33; 'source': 0.33; 'retain': 0.33; 'surely': 0.33; 'case,': 0.34; 'languages': 0.34; 'recommended': 0.34; 'that,': 0.34; 'received:google.com': 0.35; 'behind': 0.35; 'could': 0.35; 'done': 0.35; 'possible,': 0.35; 'protocol': 0.35; 'replaced': 0.35; 'tasks': 0.35; 'supports': 0.35; 'according': 0.36; 'but': 0.36; 'should': 0.36; 'there': 0.36; 'url:org': 0.36; 'received:209.85': 0.36; 'possible': 0.36; 'subject:: ': 0.37; 'really': 0.37; 'expect': 0.37; 'safe': 0.63; 'strictly': 0.64; 'between': 0.65; 'mar': 0.65; '>>>>>': 0.66; 'effective.': 0.66; 'issued': 0.66; 'legal': 0.66; 'url:index': 0.67; 'services': 0.67; 'stand': 0.67; 'worth': 0.67; 'choose': 0.68; 'skip:\xe2 10': 0.70; '26,': 0.72; '8bit%:27': 0.72; 'special': 0.73; 'obvious': 0.76; '1990s,': 0.84; 'chrisa': 0.84; 'escaping': 0.84; 'execution.': 0.84; 'moves': 0.84; 'understood.': 0.84; 'url:29': 0.84; 'valid,': 0.84; 'vulnerable': 0.84; 'url:php': 0.86; 'to:none': 0.91; 'why?': 0.91; 'interesting,': 0.93 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:cc :content-transfer-encoding; bh=pjdAvDNbcYzFLC9q3AjsaCHGFSw5Bg8DanLkl8p3iPg=; b=DJMfuvbFtmt3yHOdcpoV973SlBQbFgcAhtjIvZBoT8VONo065Eg7hEHwun772Tj6e2 xJ8qkFXbL2FXc17F09eoZKz8WNc0CglVV1qijIcFc1TIFajR5094gOBqP2ZJIU4AHaVe Fvib2s+eSPQDMC3O8AcLJWN018waqjFuflwLJivYY1NzCrx44d/yPfo/eQ14Jf22K89p wxy6YC9QT8LVn4XQE6y8vs8HBoJifb8PHpvPEwHzX6y59RYtZvIfOPcZQ4Ft20wnRoSM U+XArnzvo7uH5xdbEWX9u19pJawXSS9UfHAyzck6F147IY/yOA8ylmshkYZE9oKfZL9T CX+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:cc:content-transfer-encoding; bh=pjdAvDNbcYzFLC9q3AjsaCHGFSw5Bg8DanLkl8p3iPg=; b=XuEi20kHuim2Rx5w3q6xJDdVYWeCi+DmFmzaPku9PFn6sdMx1Grm3I0sv+a85SRqq4 Vmu2ZRW1L4ZAs62qy902q0uiHFoW6JQrt58n0B1SCzdDGbS7SREAUg737qYNfrCl4t9P Ve4zJsQQnBSlahrFAZZfKQYVgSHKl5Bx8uy+oB1MQfWwIK6PvRh2k11KbbjaGS5ZbWnf 0Fz8btz4wC4Mp4f255FvSRhVfPSG37Ct1/qw1bqkAgrR5x2ZnKSqRouvYcIn87QI46po 7LuHBd81JGDsnkRuKSuGMZv7yGUkmvUuN8G5XUFeXFBXAG5hCjgnL+M7HL7n3kTjlrjd trPw== X-Gm-Message-State: AD7BkJJw2jagLVK44ghce55P4TJTwDzkBKHpEgpIEAn0CBnc5v3ZQMuW/SVc/ON/7gqdO/j20MR2XSGGudLdHQ== X-Received: by 10.50.138.233 with SMTP id qt9mr833262igb.13.1458947046484; Fri, 25 Mar 2016 16:04:06 -0700 (PDT) In-Reply-To: <7663219.M9yg8PEDtW@PointedEars.de> X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Xref: csiph.com comp.lang.python:105713 On Sat, Mar 26, 2016 at 9:25 AM, Thomas 'PointedEars' Lahn wrote: > Chris Angelico wrote: > >> On Sat, Mar 26, 2016 at 8:28 AM, Thomas 'PointedEars' Lahn >> wrote: >>> Chris Angelico wrote: >>>> [=E2=80=A6] Thomas 'PointedEars' Lahn [=E2=80=A6] wrote: >>>>> Chris Angelico wrote: >>>>>> [=E2=80=A6] Thomas 'PointedEars' Lahn [=E2=80=A6] wrote: >>>>>>> Daniel Wilcox wrote: >>>>>>>> Cool thanks, highly recommended to use an ORM to deter easy SQL >>>>>>>> injections. >>>>>>> That is to crack a nut with a sledgehammer. SQL injection can be >>>>>>> easily and more efficiently prevented with prepared statements. [= =E2=80=A6] >>>>>> You don't even need prepared statements. All you need is parameteriz= ed >>>>>> queries. >>>>> A prepared statement in this context uses a parameterized query. >>>>> >>>>> >>> > >>>> >>>> I know what a prepared statement is. And I know that they are >>>> effective. However they are overkill - as I said, you merely need >>>> parameterization. >>> >>> Then enlighten me, please: How is =E2=80=9Cparameterization=E2=80=9D or= a =E2=80=9Cparameterized >>> query=E2=80=9D, as *you* understand it, different from a prepared state= ment? >> >> This is a prepared statement: >> >> http://www.postgresql.org/docs/current/static/sql-prepare.html >> >> You use a special "PREPARE" query to create *and store* a half-run >> query, > > [Having written a database layer (in PHP) myself, I know what a prepared > statement is, thank you very much.] > > Your statement is incorrect both for MySQL (which I know) and PostgreSQL > (AIUI your reference): The query is processed and stored of course, but i= t > is definitely _not_ *run* before the EXECUTE command is issued for it. It legal to partly perform the query. DB2 can retain a "query plan" which consists of the exact paths it will follow. So I stand by my statement. >> Back in the 1990s, I had the option of actually *compiling* my SQL queri= es >> as part of my C code, which would prepare all the queries for future >> execution. It is completely different from the dynamic parameterized >> queries that most people use. > > Interesting, but irrelevant. Not really, no. It was a form of PREPARE/EXECUTE that hid the PREPARE behind a convenient syntax, and then replaced it with EXECUTE for the run-time. >> Parameterization is a more general concept which prepared statements >> invariably use, but which general code need not use. > > If it is to be safe from SQL injection, it better uses a parameterized qu= ery > as it is *commonly* understood. Why? All it needs to do is guarantee that no user data can affect the query. There are myriad ways to do that, and prepared statements are only one of them. Even parameterization is not strictly necessary, as long as the escaping is perfect. (Though that does have its own consequences, and is not recommended.) >> A Python database connector could choose to PREPARE/EXECUTE for every >> query it's given, > > That would not be wise, given that not every query contains variable > parameters. Irrelevant. It would still be legal. Do you understand the difference between what is legal according to a specification and what is actually worth doing? In an explanation of what a parameterized query is, I would expect to be discussing what is semantically and functionally valid, not which optimizations are worth doing. >> or it could choose to escape all the parameters and embed them, > > Recommended against, and not a parameterized query at all. Not once it reaches the underlying database, but it is parameterized in the source code. It's not possible for an external attacker to get past the escaping, if it is done correctly. It is still legal, however, it is indeed not recommended. >> or it could (if it's using a decent database back-end like PostgreSQL) >> simply send the query and its associated parameters as-is. Only one of >> these options is a "prepared statement". > > Maybe. I do not know enough about PostgreSQL and its =E2=80=9C[sending] = the query > and its associated parameters as-is=E2=80=9D yet to confirm or deny this. The wire protocol supports this. >> All three are "parameterized queries", at least from the POV of Python >> code. > > You are mistaken, then: Of the three kinds of =E2=80=9Cparameterized quer= ies=E2=80=9D as > *you* understand them (OWASP and I beg to differ), at least one of them > that is not used in a prepared statement is *insufficient to prevent SQL > injection*. Okay, then. Please explain how this code is vulnerable to SQL injection: conn =3D some_db_module.connect("") cur =3D conn.cursor() data =3D input("Enter a value: ") cur.execute("insert into some_table (some_column) values (%s)", (input,)) conn.commit() Do you need to know the implementation of cur.execute to be able to say whether this is safe, or can you be confident that, short of really blatantly obvious bugs in the database connector, this is genuinely a parameterized query? I posit that the latter is the case. MY CODE has a query with a parameter. After that, it's not my problem; attacks on lower-level services are always possible, but aren't called "SQL injection". > The second kind also moves tasks to the programming language that are bet= ter > done by the DBMS; the program code should database-agnostic (in the best > case, for mockup testing, even oblivious of the database). > > Which is why programming languages have come to support prepared statemen= ts, > and why OWASP recommends to use either them or stored procedures. What would you change in the above code? Does it really need prepared statements or stored procedures? Surely the recommendation of Python is to keep things simple and expressive? ChrisA