You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Yep. CGI.pm made a bad choice. CGI is not Perl, it is written in perl.
Programmers can and do make dumb decisions.
Perl does not stop you from making dumb decisions, because Perl doesn't
want to stop you making good decisions.
CGI is not recommended, and has not been for some time, and is no longer
shipped in the Perl distribution to reflect this.
If you have something to bitch about with CGI: File a bug. Stop Using CGI.
Tell people who are using CGI not to.
Software doesn't magically stop being shit because you complain about it
on a stage.
That's literally all your options. Being written in Perl instead of Ruby
doesnt magically make it more shit. Writing it in some other language
wouldnt make it inherently non-shit.
But, you know, go on, hold up the shittiest modules as a representation of
the language itself and then present the problem as an intractable one.
Obviously, because Internet Explorer is shit, that whatever language it was
written in is shit, and that language will continue to be shit simply
because people continue to use Internet Explorer.
Stop Using C++ guys, it has bugs!.
K
"The Community"
Perl Monks is not "The Perl Community", it is one face of a subset of
"The Perl Community". There's also RT, IRC, MetaCPAN, StackOverflow,
blogs.perl.org, twitter, Facebook, and undoubtedly many more places that
"The Perl Community" congregate in.
The community can't really be considered "Gated" in this manner, you've
just chosen to find one semi-gated community and decide "That's the
Community". That'd be like me referring to a pub as being "The General
Public" and then calling "The General Public" a "Gated Community" because
pubs have bouncers.
WAT
"You can declare variables without specifying a data type"
Yes. This is true to an extent. And as you said, other languages have this.
But the slide given demonstrates 2 exceptions, because it demonstrates the
use of firstclass "Array" data types, and "Hash" data types, which require
specific syntax to manipiulate.
This is not your typical "FooType variable" type constraints, but it does
clearly seperate "Hash" and "Array" "types" from "Scalar" "types"
For contrast, without the "@" and "%" prefixes, you'd only have the options
of
Except that array is sort of like Schrödingers Array where its a quantum
superposition of array and hash, where it behaves like the opposite of the
one you wanted at least some of the time.
Its clear we have a little more granularity in types than that.
And there's JavaScript of course that similarly blurs the lines (in useful
ways)
x={"0": "hello","1": "world"};y=["hello","world"];x[0]==y[0]&&x[1]==y[1]// Wat? y["foo"]="bar";// WAT JSON.stringify(y);// WAT? Where did "foo" go?
Data is an unknown data type and you can't force it to be.
Yes. And this is a standard feature of Dynamic programming languages.
JavaScript, Ruby, Python, etc. They all do this.
Multiple paths for different data types.
Again, Yes, you can have different handling for different types of
"detected" types.
This is also a function of most dynamic programming languages.
Languages without this flexibility may support mutliple dispatch instead.
This is why things like
$("Query String");$(function(jQuery){});
Are supportable in jQuery.
Because its often more convenient to have an API that allows multiple
signatures for a common function, than it is to have to define multiple
function names for the different argument options.
"A Perl Standard" ... well, I don't know about that. Its a common convention
you see in many places. And how applicable it is to a situation depends on
a whole bunch of design trade-offs.
You can do it, and I would even argue, you should!
Because that's exactly the behaviour that is implied by default values
for arguments.
Because:
object.function(argument)
and
object.function(argument,secondargument)
is essentially asking the question "if second argument is of magical type
NOTSPECIFICED, substitute it with an alternative value"
And that's not a whole lot different from "Type Undefined"
And "do something different if the user forgot to pass an argument" is
pretty much a standard in every language.
There's similarly no way to tell JavaScript "hey, this argument must not be
an array", so you have to detect that at runtime.
So obviously JavaScript sucks and everyone should stop using it.
Incidentally, Perl6 supports these if you want them, so ... yay for Perl6!
"The problem is when Hashes and Arrays are considered as Secure Data types"
And that's just the Crux of it. They aren't. Anyone who writes code with an
API knows this.
Anyone making this mistake is the idiot.
Neither the language itself or the culture surrounding it claims that
structured data is inherently secure as a function of being structured.
Because wether or not a data structure is secure is clearly a function
of where that data came from.
For instance, PHP permits forms to send POST/GET requests which result in
arbitrarily structured arrays.
And people who are stupid take that data verbatim as trustworthy.
And that's just it: They're stupid for doing that.
If you don't sanitize your input at the border prior to passing it to
something that requires that input to be "Safe", then your data is not
"Safe".
You didn't sanitize it, there's no way it can be safe.
And some layers must assume the caller did due dilligence.
For instance if you have a function called "rm" and it takes a string of a
file to delete, its not rm's job to work out whether or not the user
calling it was permitted, and its not rms job to work out if the string
passed is a file-that-should-be-deleted or not.
You fix that or pass it to RM, and if rm deletes it, rm did its job,
and did exactly what you told it to do. If you told it to do the wrong
thing, that's all on you.
[ACTUAL POSSIBLE ISSUE] Hash Keys are Not Tainted.
This is the only place I've seen a justifiable complaint about taint mode.
Given the point of taint mode is to make things explode if you didn't
sanitize things correctly, it would be a problem indeed if somebody passed
json like:
{"DROP TABLES *": "Harmless value"}
And somebody, somehow, managed to sanitize the values properly, but managed
to pass those keys unsanitized to a query.
Because:
->query( joinkeys%HASH )
Would silently work, regardles of wether or not the hash key itself was ever
sanitized.
The downside is that this problem is possibly too hard to solve, because
hash keys are heavily used in the VM itself, and underlies things like
Package stashes, and so any taint checks here could slow down perl in
entirely unacceptable ways.
Additionally, people have relied on the taintless behaviour of hash keys on
purpose, and have copied variables into hashes simply to remove taint flags,
which makes changing that behaviour without breaking a lot of code
difficult.
I would still maintain that your coding ethics SHOULD NOT rely on taint
mode to keep you safe, and you should exercise sufficient levels of
dilligence.
But taint mode should still be reliable enough to catch where you've left a
barn door open by accident.
But your criticism focused wrongly on hash values as being the attack
vector, when its hash keys.
Bugzilla treats hash values as secure.
Yes. This is a bug in Bugzilla.
No, this is not something Perl community promotes or encourages.
All data passed to a function must be treated as equally suspicious,
structured or not.
Given the syntax of the _load_from_db function based on the way the slide
presents it, the _load_from_db function is intended as a lower level
function that just "does what its told", which is why it allows a passing
a free-from component of an SQL-Query in verbatim in the first place.
I would posit that the error here is not that it takes a hash as an argument
and treats it as "Secure", its that the second method with "detaint" is
detainting at the wrong level.
_load_from_db should also be treating $param as "Secure", where any
quoting/escaping for passing the value to the database should only be
considered an API convenience, not a security feature.
And _load_from_db should be barfing if any tainted data is passed to
it, not transparently detainting it.
"On all 3 CGI Modules"
You cite one CGI module.
The other two are Web Platforms, which happen to support the CGI
interface under the hood, but are otherwise not related to CGI.pm
And the other two are generally NOT used with the CGI interface,
because CGI is shit, and CGI.pm is shit.
The rest of this part of your analysis seems to be complaining that
different web platforms do different things, and I'm struggling to
understand how that could be construed to be a point, let alone, a point
that demonizes Perl itself as being "Bad".
These are all design decisions of the independent modules in question,
which all just happen to be written in Perl.
Any language can make such a decision, and Any dynamic language
could be equally vulnerable to these sorts of issues.
I imagine if you compared the exact same metrics with different languages
and competing web frameworks, you'd again, get a variety of different
results.
And I would naturally expect something to happen automatically server-side
as a result of extra parameters, because that's a common idiom on the
web
( PHP might be more consistent here, because unlike the other languages
where parsing GET requests requires dedicated modules that implement parts
of the HTTP Specification, PHP implements those parts natively in the
language itself and magically pumps the values into global variables. )
"You can't tell what your datatype is made of!"
Wait. You just argued you could, earlier, and complained that it wasn't
automatic.
The example used ref, which indicates the type of data you have.
This is, again, a common pattern in dynamic programming languages, and
you've used this false claim with other false claims to construct an
argument that paints Perl as being radically different from other
weakly typed programming languages.
You just have to apply dilligence and write code that handles the different
cases.
Its when you don't care what your data is and then you try to do things
with that data that require you to care, that things go amok.
The trick is to not do that.
CGI.pm Exploit.
Yes. CGI.pm is shit, stop using it. Stop running conferences where you tell
people how not to do things with software we're telling people not to use.
Tell people not to use CGI.pm, because it is shit.
CGI.pm is not "Perl".
[ACTUAL POSSIBLE ISSUE] <"ARGV"> Expolit
You can demonstrate this bug much more clearly with
use strict;
use warnings;
@ARGV = ('echo broken|');
while( <"ARGV"> ) {
print$_;
}
This problem is again exacerbated because CGI is shit, as CGI created the
enviroment wherein you have a list of arbitrary user data in @ARGV, and
CGI.pm made things worse by its ->params() bullshit.
But your understanding is wrong.
my$file = $cgi->param('file');
This does NOT return a list of files in your situation.
Because CGI.pm now spews a nice big warning if you're dumb enough to use it in
List Context.
CGI::param called in list context from {...}, this can lead to
vulnerabilities. See the warning in "Fetching the value or values of a
single named parameter" at {...}
Instead, CGI.pm does what you'd expect any other thing to do in a situation
where the user passed two variables: It returns only one of them.
So your demon about list context is nowhere to be seen here.
However, <"ARGV"> being communicated to is clearly a bug that should
be fixed, because @ARGV is a symbol, and strings dereferencing to symbols
transparently like that is typically something strictures prohibits.
2-Arg Open And Friends Suck
Well. Yes, that's why we've been recommending againt using them in code
since 5.8 shipped.
while(<>) implying 2-arg open is also a thing we've recognised as "bad", so we now
have while(<<>>).
But its worth mentioning that if you are writing a Command Line application,
the ability to pass a filename, or a string that can be executed to
produce content can be useful.
Yes, in a Server context, this is very much not what you want, because you
generally don't want users to pass in executables to invoke.
Its kinda useful being able to have
while(<>) {
}
In a CLI app and having that transparently support:
But you of course don't want magic data in ARGV when you're running a
server.
But ... that's just an argument to "STOP USING CGI"
Because CGI stupidly makes the CLI and the HTTP request a unified interface,
so you get the worst of both worlds.
So, again, you've got an exploit that fundementally relies on ancient
technology that we're setting on fire and trying to kill for ages now.
Misleading Documentation
What did you do, step in a time machine? You're giving presentations in
December using a screenshot of an example dated 2009, that was updated back
in April.
I can't confirm if the example has been updated to accommodate this, and I
still maintain CGI is shit and you should expect bad things to happen if you
use it.
Either way, that's what we call "A bug in CGI.pm", and I was under the
impression the right approach is to file a bug when they're found, so that
they can be fixed.
Unless of course you want to be a 1337 hacker geek and keep that to yourself
for 8 months so you can grand-stand on a stage and feel popular while making
it out like its some programming language to blame for bad software existing.
golf clap
"I'm not blaming CGI developers"
But you should. All these problems are design decisions made by
programmers.
They could have easily made decisions that avoided these pitfalls.
The language holding your hand wouldn't magically make this go away.
Yes, there are bugs in the language, and CGI's poor design choices make
those bug bigger.
But lets not fool ourselves that CGI.pm is the shining standard of decent
perl modules on CPAN, like you seem to have a hardon for trying to argue.
And you should blame people who use CGI.pm for using CGI.pm, because...
... CGI.pm is no longer considered good practice for developing web
applications, including quick prototyping and small web scripts. There
are far better, cleaner, quicker, easier, safer, more scalable, more
extensible, more modern alternatives available at this point in time.
And it has said that for over a year now ( May 2014 )
That's right up there in The Manual, and anyone who is part of "The Perl
Community" will gladly tell you that CGI.pm is shit, and you shouldn't use
it.
And if you're not going to listen to either of those very loud signals, you
very much should be considered part of the problem.
I mean, what else do we have to do to convince you not to use CGI.pm?
Maybe we should be adding security holes instead of removing them to
discourage its use?
CLOSING.
In short, your diagnosis revolves mostly on needing CGI.pm, and revolves
around mistakes that CGI.pm encourages you to make that don't make sense
in a Web Context, but do make sense in a CLI context.
And then you conflate intepretations of fundementals that aren't true, and
you think Perl is the problem.
But maybe, you should just stop using CGI.pm, and tell people "Stop using
CGI.pm"
And maybe, you could consider filing bugs about things and getting them
fixed, not bitching that something that is broken and wondering why nobody
has fixed it yet.
But hey, at least you know how Perl5 and Perl6 are fundementally different
;), so you got something right :p
AFTERTHOUGHTS on Questions
Why do Perl people bitch when its attacked?
Well, its become a bit of an annoying trope.
Its an "in thing" to go around complaining about Perl, and at least half the
people who are "attacking it" are using arguments about it that are false.
So attacking perl with stupid arguments has become a Meme in the programming
community, and it is largely perpetuated by people who don't know the
language, who see its syntax, never invest the effort to properly understand
it, and then critise it, not objectively, but out of ignorance.
So there's naturally a level of kickback.
And we also try to be better than have debates where we're constantly
insulting languages for non-objective reasons, becuase we'd rather shut the
fuck up and write some code ;)
Just if people could learn to criticise it objectively ( and file fucking
bugs plz ), then maybe we could consume that objective criticism and use it
to improve the language.
First of all, thank you for the detailed feedback. I really appreciate the time and effort you made writing this up.
I wanted to write a long reply, stating what I think about each section, but I don't think that will help. Instead, I'll try and describe my point of view in general.
Perl has a lot of features. Some are great, some are don't, like in every language. My talks revolved around some of the "less-than-great" features. The question is - are these wise features?
There is always a trade off between usability and security, and developers have to constantly decide which one is more important. I read a lot of code, in a lot of different languages (please see my LinkedIn profile for a list of some of my findings), and it always seemed like Perl has taken the "usability" side of the equation much more significantly than the "security" side, and this caused (and continue to cause) more security problems than should be.
In order to provide a more balanced approach, Perl developers came up with Taint Mode, which increases security but greatly decreases usability. The thing is that Perl developers usually prefer the "usability" side of the spectrum, and choose not to use Taint Mode at all (as you've also mentioned), which brings us to my next point:
Why use Perl with CGI applications? Perl hasn't been written with security in mind, thus making the task of writing secure code more difficult than in other languages. The problem is that there are a lot of unconventional ways to create security problems in Perl than in other languages, because of all the unique features.
When I try to find vulnerabilities in code written in Perl, I tend to skip the rather traditional attacks (SQL Injections, from example), and search for all the Perl specific problems - lists expansions, incorrect references, open() calls, data type assumptions, and other common landmines. You wouldn't believe how many projects are vulnerable to this kind of stuff.
So the only question remaining is - who's fault is that? Is it the fault of the developers, who are not familiar with all of their language security problems, or it's the fault of the language, who've created too many of these problems?
In my eyes, as you've probably guessed, it's the fault of the language. The same way PHP was criticized for being filled with mines, or C for providing too many functions that don't force size restrictions, I'm criticizing Perl right now.
If someone would have approached me and asked - "well, you're complaining a lot, how will you fix it?", I'd happily reply with my opinion about how the language could improve, how it should be oriented more towards security and less towards niche features. Instead, the Perl community chose to bash me personally and ignore the CVEs or problems I raised in the first talk.
When I did my second talk, I really hoped that this I could change someone's mind and maybe improve something. I was happy to discover at least some Perl Monks agreed with (some of) my points, and that there's a general feeling that something should improve.
I really hope the Perl community or developers will take something from my talks and comments, even if it's just fixing the specific problems I raised.
@D3Ve1inE - it's frustrating because not once have you addressed me directly, either on the CGI.pm github repo with issues/pulls/comments/etc or in any of the replies i've made to you on hackernews or reddit. Nor have you sent me any e-mails, or msg'd me on IRC. I'm here, i reply to all requests and queries pretty quickly, and i'm extremely accommodating to suggestions and questions. I'd have fixed that example, had you pointed it out, which is an old example BTW, one that i'd already updated to use strict, use warnings and use Template but missed the existing exploitable code so didn't fix that. I will fix that when i get back from my vacation (this is the one and only response i'm making on the talk). Edit: So it turns out the example you show in the presentation is not the same as the example in the distribution, nor any of the previous version of the distribution, it's not exploitable in the way you present. It seems you edited the example to suit your agenda?
The rock and the hard place i find myself in, since volunteering to be the maintainer of CGI.pm back in April 2014, is that CGI.pm is still deployed in many many places, and a significant number of those places aren't by perl developers and won't be able to cope if i fix the real problems in CGI.pm. Their code will break badly if and when they update. Because CGI.pm has twenty odd years of history there are many problems in it, basic stuff that you've covered in your talks but also other stuff. Code that we have known for years is problematic. I mean, real basic stuff such as making it work under strict would break so much user code that i simply can't do it.
My approach thus far has been to make noise in the documentation and prune where necessary, which seems to be filtering down to some of the users; but it's still going to take a long time to be seen by those who don't take notice, who upgrade and don't expect breaking changes, who will send me hate mail when breaking changes do happen (like removing functions that were deprecated several years ago - yes, this has happened). What we have done is to loudly discourage the use of the module, say it is no longer fit for purpose and keep pushing this message, which is essentially what you have done as well but you then took it too far.
You should invest more time in understanding the language you are criticising, its history, and its modern ecosystem; your slides contained a couple of basic errors that would put you at the level of someone who has very shallow knowledge of a language that is very very deep. Many of the issues in the language you've raised were covered in a book called "Perl Best Practices" released in 2005, and since then a few suggestions in that book have since been seen to not be the best advice.
I actually think you're doing good work but you're presenting that work very poorly and making too many generalisations with code that we (the perl community) have long since discouraged. I've said this already in response to your talk last year, but it bears repeating: If you give another talk at CCC next year then make it a serious one, because i think it would have far more impact than your last two.
The rock and the hard place i find myself in, since volunteering to be the maintainer of CGI.pm back in April 2014, is that CGI.pm is still deployed in many many places, and a significant number of those places aren't by perl developers and won't be able to cope if i fix the real problems in CGI.pm.
Which is what you sign up to when you maintain a module used as widely as that. If you don’t like doing extremely careful change management then you should be working on some greenfield (or blue-sky) project.
Which is what you sign up to when you maintain a module used as widely as that. If you don’t like doing extremely careful change management then you should be working on some greenfield (or blue-sky) project.
Indeed. I was aware of that when i volunteered to maintain the module and am happy to deal with it. My point was directed at Netanel, whose suggestion of "just fixing the specific problems" is indicative of someone who hasn't spent much time maintaining business critical code (or even working on greenfield projects, because greenfield projects will eventually end up as legacy systems).
@D3Ve1inE FWIW, I'm currently trying to refine the content of this document into a form more productive for widespread use, trying to focus more on:
The problems
Explaining the mechanics of the problem objectively closer to the problem space ( for instance, talking about the <"ARGV"> bug in the context of CGI.pm confuses people about what the problem is )
Attempting to consider possible solutions for the problem
Attempting to propose related solutions for how things that are not bugs, but features, can be restricted in a way that doesn't inconvenience people who want the feature, but doesn't expose people who don't want the feature to needless risk.
Hopefully, this will inspire objective comprehension of the problem, and potentially inspire the problems to actually get fixed, and shore up this potential for problems.
Sure, Perl has a bunch of features that unexperienced users could make security holes out of. I wouldn't say Perl is entirely unique in this manner, considering the legacy of C's null-terminated-string based attacks, attacks on sprintf, and our friend the entertaining function gets.
If I had to explain how I perceive Perl different from C in this regard, is that most of C's bugs are not derived so much from language syntax, but from language functions, and then the security defects are in the implementation and design of those functions.
While Perl, we have a lot more of our behaviour implemented as syntax, instead of functions.
A lot of that behaviour is very useful if you know what you're doing, because you can achieve quite a lot with syntactical combinations that would otherwise require large stacks of function calls to achieve in a competing language.
And this is our idiomatic nature. Its is really convenient and useful for a Perl person, because it allows you to achieve more, more quickly, and with less effort. ( And the language can add specific optimisations for specific uses of specific idiomatic combinations of syntax[1] )
But just like how a C person can use the wrong functions and use functions wrongly, a Perl person can use the wrong syntax and use syntax wrongly.
But otherwise, my polished versions of this document will attempt to be less hyperbolic, because hyperbole seems to like breeding more hyperbole, and that gets us farther away from our problem gaining a solution, not closer.
And I suspect this conflict of hyperbole in your first presentation painted a target on your back ( metaphorically speaking ), and so as soon as Perl people heard there was going to be a repeat of that presentation, the natural reflex was "Oh brother, this guy again".
But if you want to help the world get off the CGI train, I'm in. ;)
[1]: For example, if you glanced at this code, you might think "Shit, that will never work, it will exhaust all memory before it does anything". Nope!... at least not on any modern Perl.
for ( 1 .. ( 2 ** 64 ) ) {
}
But this will just halt with an out-of-memory error because we haven't optimised this syntax yet:
Thumbsup from here. @D3Ve1inE: yeah please stop this, it's boring. To reiterate briefly from my experience. CGI.pm is shit. Do not write new code using it. Port old code away from it where possible. Use Plack/PSGI and modules like CGI::Compile/Plack::App::CGI to port away. While I would love it if there was a backcompat CGI.pmButNotDreadful module, it's not going to happen. There are too many poor choices in API design to make that practical to achieve. Why don't you do a talk next year on "proper, reasonably secure web programming in Perl using the modern perl stack rather than the ancient and broken CGI.pm module" rather than continuing to tilt at windmills? I've been doing reasonably big things in perl for a few years now, and generally the security audits have gone fine with only a tiny little extra effort on the team's part. You appear to be arguing that this is not possible?
Good to see an informed write up of the guy's talk
I stopped watching after about fifteen minutes because it became pretty clear it was a waste of time and was mostly about the olympic sport of "Perl Bashing". Which I totally used to do, early in my second year of uni because I was parroting off what one of my lecturers said...
Thankfully I at some point became more informed. I hope the talk giver does at some point too and they don't feel too negatively about themself when they realise how they came across. To a layman they might be hilarious but to someone familiar with the field he's wading into he sounds roughly like a five year old preaching issues with quantum theory to experienced physicists
+100 Excellent point-by-point refutation!