Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:106631 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 22818 invoked from network); 16 Aug 2019 00:52:36 -0000 Received: from unknown (HELO mail-wr1-f51.google.com) (209.85.221.51) by pb1.pair.com with SMTP; 16 Aug 2019 00:52:36 -0000 Received: by mail-wr1-f51.google.com with SMTP id c3so3563469wrd.7 for ; Thu, 15 Aug 2019 15:21:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=craigfrancis.co.uk; s=default; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=GqxnMFz8S82KPkuMYhwvKUrMrEFwFncHlvnwahgOAjY=; b=DpuU+Er9PQJ70TenTGpTSgF/LYtO/lYK680rMWC8Hh1W3qRsFd1CzFCqtJc0+Dc9Ls neFEXUrVverXoSrgbrI7hHcZSiHyomVWXm2/SgR2qKjLAC3lkpibuRsaOXeJ+ai4Yg18 IxYcBBeAKx6FNA8TnC1ivQ+ZEjjzNv9DMmxC8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=GqxnMFz8S82KPkuMYhwvKUrMrEFwFncHlvnwahgOAjY=; b=ko05j97vyzt9vrGphtFChZ18Jb3eO/oih2AklhMTaDQ0MO3awJOAr0BSdWjpDvjEsa RFq+Oqm1MS5kko9zCYFx+1u1B9RFilp7MKAH+2jGcYCd66nXKbCG7otCNjse0YJ3MFCI boYGyVn5CkGFTSbwXQBQI75RyxOnLmeD0aZnV5UXTJdqzGInENezv3hXH/ZuA11NcDqd ewGppB4Cd37ahgIxoNdXaXSPpR87T3aGMS9RbmG67sX9T4IIn8RgQRnBCJvzOR03M47F HE2ogPSxD4oYqq20BoGhzhPwflyedqzm8s+W0paMmDPv1jF5jzZDc4CwVDTHxbEEGmPS 1cOQ== X-Gm-Message-State: APjAAAXNXSC6n9AQcTOcU+U0JCwv3RFXMcqONhqAJlXxwvtCOxj+WyP6 Nf4vqtUI1Z88PoqaD45fkNMmjRufn1w+netI9p4lEg== X-Google-Smtp-Source: APXvYqz7sIrY1ACjMnmyy2H0K6FyeisOsO3SJLdKlqpjl4gE93VjVPaCNtKat7oJj7K/HrXTvcdJKb6wOrmYODFKfP4= X-Received: by 2002:adf:8541:: with SMTP id 59mr7320107wrh.298.1565907695688; Thu, 15 Aug 2019 15:21:35 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 15 Aug 2019 23:21:24 +0100 Message-ID: To: Matthew Brown Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000f3f54605902f4b05" Subject: Re: [PHP-DEV] Literal / Taint checking From: craig@craigfrancis.co.uk (Craig Francis) --000000000000f3f54605902f4b05 Content-Type: text/plain; charset="UTF-8" On Thu, 15 Aug 2019 at 21:37, Matthew Brown wrote: > > If anything, this proposal would help user-land solutions (it gives them >> more information while the code is in running). >> > > Well, it might help runtime-based user-land solutions, but not static > analysis-based solutions. > I mostly see us needing to use both solutions - static analysis does a deep dive (ideally helped with any information the PHP engine can provide, even if it's just parsing), and this runtime check running constantly - only because static analysis by itself can skip bits, e.g. https://gerrit.wikimedia.org/g/mediawiki/tools/phan/SecurityCheckPlugin/#general-limitations > In our bug disclosure program at Vimeo we've had no SQL injection issues > reported, but a number of XSS issues (echoing attacker-controlled data), > and those issues cannot so easily be prevented by this technique as there's > generally little reason to echo literal values. > This proposal can ensure SQL injection is impossible, rather than our current processes, which has some gaps (I'm glad to see you haven't had any reported issues, but I believe you're in the minority). This can also be expanded for command line injection issues (kind of moving away from escapeshellarg). I've not spent enough time on the templating side of things yet (I've been working more on the browser side for this, e.g. CSP and application/xhtml+xml). But I'm hopeful this proposal can still be useful, in a similar way to how the JavaScript changes will help templating (ref Trusted Types). Even if we only use this for guarding some inputs - e.g. a templating system being sure which bits are safe HTML literals, loaded into a DomDocument, and unsafe user data being applied with setAttribute() after some sanity checks. But there are some annoying edge cases, which means that I don't think this can be perfect: $user_homepage = 'javascript:alert(document.cookie)'; Example > I can also think of a number of user-constructed SQL queries (e.g. WHERE > ... IN) that require non-literal values to work (if this were to come to > pass there might be a set of special `unsafe` methods). > This is what I've been using for `WHERE ... IN` to create a literal for the SQL string: $parameters = []; $in_sql = $db->*parameter_in*($parameters, 'i', $ids); // I'm using `maxdb_stmt::bind_param` which needs a type. $sql = 'SELECT * FROM table WHERE id IN (' . $in_sql . ')'; $db->fetch_all($sql, $parameters) ... public function *parameter_in*(&$parameters, $type, $values) { $count = count($values); if ($count == 0) { throw new Exception('At least 1 value is required for an IN list'); } if ($type == 'i') { $values = array_map('intval', $values); } else if ($type == 's') { $values = array_map('strval', $values); } else { throw new Exception('Unknown parameter type for parameter_in(), should be "i" or "s"'); } foreach ($values as $value) { $parameters[] = [$type, $value]; } return substr(str_repeat('?,', $count), 0, -1); // Returns a literal string. } --000000000000f3f54605902f4b05--